From 9a7694f32a5aa64e430afd01c99e4601ca98b758 Mon Sep 17 00:00:00 2001 From: Craig Dowell Date: Fri, 12 Oct 2007 13:41:24 -0700 Subject: [PATCH] deal with static constructor problem --- src/core/log.cc | 40 +++++++++++++++++++++++++++++++++++++++- src/core/log.h | 44 +++++++++++++++++++++++++++----------------- 2 files changed, 66 insertions(+), 18 deletions(-) diff --git a/src/core/log.cc b/src/core/log.cc index d3e6fe30f..0bfb978c4 100644 --- a/src/core/log.cc +++ b/src/core/log.cc @@ -48,10 +48,44 @@ void LogComponentEnableEnvVar (void) { static bool isFirstLog = true; +#if 0 +// +// Interesting static constructor bug: +// +// The RandomDirection2dMobilityModel declares a RandomVariableDefaultValue +// g_speedVariable. This variable is initialized in the +// static_initialization_and_destruction_0 function as expected. This causes +// RandomVariableDefaultValue::Parse () to be called which calls NS_LOG_X +// functions. The macro calls LogComponent::IsEnabled () which calls +// LogComponentEnableEnvVar (). The following variable called isFirstLog +// is set after the first call to prevent the environment variable from +// actually being parsed on every log call. +// +// When the RandomDirection2dMobilityModel static constructor is run, other +// log components may not have had their static constructors run yet. It is +// in those other static constructors that their log components are added to +// the list of log components. +// +// The end result is that if any code calls an NS_LOG_X function during its +// static constructor, the environment variable check is "locked out" for +// any log component declarations (in different compilation units) that have +// not yet been executed. +// +// So, the choice seems to be to either 1) parse the environment variables +// at every log call; or 2) make LogComponentEnableEnvVar explicitly called +// after all other static constructors are called. This means in main (). +// The former choice seems the only reasonable way out if we care remotely +// about performance in logging. +// +// I made LogComponentEnableEnvVar a public API that you need to call in +// main () if you want to use environment variables to drive the log output. +// if (!isFirstLog) { return; } +#endif // 0 + #ifdef HAVE_GETENV char *envVar = getenv("NS_LOG"); if (envVar == 0) @@ -142,6 +176,10 @@ LogComponentEnableEnvVar (void) { level |= LOG_ALL; } + else if (lev == "prefix") + { + level |= LOG_PREFIX_ALL; + } else if (lev == "level_error") { level |= LOG_LEVEL_ERROR; @@ -236,7 +274,7 @@ LogComponent::LogComponent (char const * name) bool LogComponent::IsEnabled (enum LogLevel level) const { - LogComponentEnableEnvVar (); + // LogComponentEnableEnvVar (); return (level & m_levels) ? 1 : 0; } diff --git a/src/core/log.h b/src/core/log.h index d54b8fcdf..61ab9026d 100644 --- a/src/core/log.h +++ b/src/core/log.h @@ -32,22 +32,8 @@ * send information out on screen. All logging messages * are disabled by default. To enable selected logging * messages, use the ns3::LogComponentEnable - * function. - * - * Alternatively, you can use the NS_LOG - * environment variable to define a ';'-separated list of - * logging components to enable. For example, NS_LOG=a;b;c;DAFD;GH - * would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'. - * - * For each component, the "debug" log level is enabled by default - * but more components can be enabled selectively with the following - * syntax: NS_LOG='Component1=func|param|warn;Component2=error|debug' - * This example would enable the 'func', 'param', and 'warn' log - * levels for 'Component1' and the 'error' and 'debug' log levels - * for 'Component2'. - * - * The list of available log components can be printed on stdout - * with the NS_LOG=print-list syntax. + * function or use the NS_LOG environment variable and + * ns3::LogComponentEnableEnvVar */ /** @@ -187,12 +173,34 @@ enum LogLevel { LOG_ALL = 0x7fffffff, // print everything LOG_LEVEL_ALL = LOG_ALL, - LOG_PREFIX_ALL = 0x80000000 + LOG_PREFIX_ALL = 0x80000000 // prefix all trace prints with function }; #endif #ifdef NS3_LOG_ENABLE +/** + * \brief Enable the logging output based on an environment variable. + * + * Use the environment variable NS_LOG to define a ';'-separated list of + * logging components to enable. For example, NS_LOG=a;b;c;DAFD;GH + * would enable the components 'a', 'b', 'c', 'DAFD', and, 'GH'. + * NS_LOG=* will enable all available log components. + * + * For each component, the "debug" log level is enabled by default + * but more components can be enabled selectively with the following + * syntax: NS_LOG='Component1=func|param|warn;Component2=error|debug' + * This example would enable the 'func', 'param', and 'warn' log + * levels for 'Component1' and the 'error' and 'debug' log levels + * for 'Component2'. The wildcard can be used here as well. For example + * NS_LOG='*=level_all|prefix' would enable all log levels and prefix all + * prints with the component and function names. + * + * The list of available log components can be printed on stdout + * with the NS_LOG=print-list syntax. + */ + void LogComponentEnableEnvVar (void); + /** * \param name a log component name * \param level a logging level @@ -204,6 +212,7 @@ enum LogLevel { * to ns3::LogComponentDisable. */ void LogComponentEnable (char const *name, enum LogLevel level); + /** * \param level a logging level * \param decorate whether or not to add function names to all logs @@ -213,6 +222,7 @@ enum LogLevel { */ void LogComponentEnableAll (enum LogLevel level); #else +#define LogComponentEnableEnvVar() #define LogComponentEnable(a,b) #define LogComponentEnableAll(a) #endif