log rides along for free
authorCraig Dowell <craigdo@ee.washington.edu>
Wed, 12 Sep 2007 16:24:31 -0700
changeset 1498 520bc8457799
parent 1497 dff0a53e60f2
child 1499 93d51d757afa
log rides along for free
src/core/log.cc
src/core/log.h
src/core/wscript
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.cc	Wed Sep 12 16:24:31 2007 -0700
@@ -0,0 +1,269 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#include <list>
+#include <utility>
+#include <iostream>
+#include "log.h"
+#include "assert.h"
+#include "ns3/core-config.h"
+#include "fatal-error.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+namespace ns3 {
+
+typedef std::list<std::pair <std::string, LogComponent *> > ComponentList;
+typedef std::list<std::pair <std::string, LogComponent *> >::iterator ComponentListI;
+
+static 
+ComponentList *GetComponentList (void)
+{
+  static ComponentList components;
+  return &components;
+}
+
+void
+LogComponentEnableEnvVar (void)
+{
+  static bool isFirstLog = true;
+  if (!isFirstLog)
+    {
+      return;
+    }
+#ifdef HAVE_GETENV
+  char *envVar = getenv("NS_LOG");
+  if (envVar == 0)
+    {
+      isFirstLog = false;
+      return;
+    }
+  std::string env = envVar;
+  if (env == "print-list")
+    {
+      LogComponentPrintList ();
+      isFirstLog = false;
+      return;
+    }
+  bool allFound = true;
+  std::string::size_type cur = 0;
+  std::string::size_type next = 0;
+  while (true)
+    {
+      next = env.find_first_of (";", cur);
+      std::string tmp = std::string (env, cur, next);
+      {
+        /* The following code is a workaround for a bug in the g++
+         * c++ string library. Its goal is to remove any trailing ';'
+         * from the string even though there should not be any in
+         * it. This code should be safe even if the bug is not there.
+         */
+        std::string::size_type trailing = tmp.find_first_of (";");
+        tmp = tmp.substr (0, trailing);
+      }
+      if (tmp.size () == 0)
+        {
+          break;
+        }
+      std::string::size_type equal = tmp.find ("=");
+      std::string component;
+      int level;
+      if (equal == std::string::npos)
+        {
+          component = tmp;
+          level = LOG_LEVEL_DEBUG;
+        }
+      else
+        {
+          component = tmp.substr (0, equal);
+          std::string::size_type cur_lev;
+          std::string::size_type next_lev = equal;
+          do
+            {
+              cur_lev = next_lev + 1;
+              next_lev = tmp.find ("|", cur_lev);
+              std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
+              if (lev == "debug")
+                {
+                  level |= LOG_LEVEL_DEBUG;
+                }
+              else if (lev == "func")
+                {
+                  level |= LOG_LEVEL_FUNCTION;
+                }
+              else if (lev == "param")
+                {
+                  level |= LOG_LEVEL_PARAM;
+                }
+              else if (lev == "warn")
+                {
+                  level |= LOG_LEVEL_WARN;
+                }
+              else if (lev == "error")
+                {
+                  level |= LOG_LEVEL_ERROR;
+                }
+            } while (next_lev != std::string::npos);
+        }
+      bool found = false;
+      ComponentList *components = GetComponentList ();
+      for (ComponentListI i = components->begin ();
+           i != components->end ();
+           i++)
+        {
+          if (i->first.compare (component) == 0)
+            {
+              found = true;
+              
+              i->second->Enable ((enum LogLevel)level);
+              break;
+            }
+        }
+      if (!found)
+        {
+          allFound = false;
+        }
+      if (next == std::string::npos)
+        {
+          break;
+        }
+      cur = next + 1;
+      if (cur >= env.size ()) 
+        {
+          break;
+        }
+    }
+  if (allFound)
+    {
+      isFirstLog = false;
+    }
+  
+#endif
+}
+
+
+LogComponent::LogComponent (char const * name)
+  : m_levels (0)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      NS_ASSERT (i->first != name);
+    }
+  components->push_back (std::make_pair (name, this));
+}
+bool 
+LogComponent::IsEnabled (enum LogLevel level) const
+{
+  LogComponentEnableEnvVar ();
+  return (level & m_levels) == 1;
+}
+bool
+LogComponent::IsNoneEnabled (void) const
+{
+  return m_levels == 0;
+}
+void 
+LogComponent::Enable (enum LogLevel level)
+{
+  m_levels |= level;
+}
+void 
+LogComponent::Disable (enum LogLevel level)
+{
+  m_levels &= ~level;
+}
+
+void 
+LogComponentEnable (char const *name, enum LogLevel level)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      if (i->first.compare (name) == 0) 
+	{
+	  i->second->Enable (level);
+	  break;
+	}
+    }  
+}
+void 
+LogComponentDisable (char const *name, enum LogLevel level)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      if (i->first.compare (name) == 0) 
+	{
+	  i->second->Disable (level);
+	  break;
+	}
+    }  
+}
+
+
+void 
+LogComponentPrintList (void)
+{
+  ComponentList *components = GetComponentList ();
+  for (ComponentListI i = components->begin ();
+       i != components->end ();
+       i++)
+    {
+      std::cout << i->first << "=";
+      if (i->second->IsNoneEnabled ())
+        {
+          std::cout << "0" << std::endl;
+          continue;
+        }
+      if (i->second->IsEnabled (LOG_LEVEL_DEBUG))
+        {
+          std::cout << "debug";
+        }
+      if (i->second->IsEnabled (LOG_LEVEL_FUNCTION))
+        {
+          std::cout << "|func";
+        }
+      if (i->second->IsEnabled (LOG_LEVEL_PARAM))
+        {
+          std::cout << "|param";
+        }
+      if (i->second->IsEnabled (LOG_LEVEL_WARN))
+        {
+          std::cout << "|warn";
+        }
+      if (i->second->IsEnabled (LOG_LEVEL_ERROR))
+        {
+          std::cout << "|error";
+        }
+      std::cout << std::endl;
+    }
+}
+
+} // namespace ns3
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/log.h	Wed Sep 12 16:24:31 2007 -0700
@@ -0,0 +1,167 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2006,2007 INRIA
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
+ */
+#ifndef LOG_H
+#define LOG_H
+
+#include <string>
+#include <iostream>
+
+/**
+ * \defgroup logging Logging
+ * \brief Logging functions and macros
+ *
+ *   LOG functionality: macros which allow developers to
+ *     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.
+ */
+
+/**
+ * \ingroup logging
+ * \param name a string
+ *
+ * Define a Log component with a specific name. This macro
+ * should be used at the top of every file in which you want 
+ * to use the NS_LOG macro. This macro defines a new
+ * "log component" which can be later selectively enabled
+ * or disabled with the ns3::LogComponentEnable and 
+ * ns3::LogComponentDisable functions or with the NS_LOG
+ * environment variable.
+ */
+#define NS_LOG_COMPONENT_DEFINE(name)                                \
+  static ns3::LogComponent g_log = ns3::LogComponent (name)
+
+/**
+ * \ingroup logging
+ * \param msg message to output
+ *
+ * Generate logging output in the "log component" of the 
+ * current file. i.e., every call to NS_LOG from within
+ * a file implicitely generates out within the component
+ * defined with the NS_LOG_COMPONENT_DEFINE macro in the
+ * same file.
+ */
+#define NS_LOG(level,msg)                       \
+  do                                            \
+    {                                           \
+      if (g_log.IsEnabled (level))              \
+        {                                       \
+          std::clog << msg << std::endl;        \
+        }                                       \
+    }                                           \
+  while (false)
+
+#define NS_LOG_DEBUG(msg) \
+  NS_LOG (ns3::LOG_LEVEL_DEBUG,msg)
+
+#define NS_LOG_FUNCTION \
+  NS_LOG (ns3::LOG_LEVEL_FUNCTION, __PRETTY_PRINT__)
+
+#define NS_LOG_PARAM(msg) \
+  NS_LOG (ns3::LOG_LEVEL_PARAM,msg)
+
+#define NS_LOG_WARN(msg) \
+  NS_LOG (ns3::LOG_LEVEL_WARN,msg)
+
+#define NS_LOG_ERROR(msg) \
+  NS_LOG (ns3::LOG_LEVEL_ERROR,msg)
+
+#define NS_LOG_UNCOND(msg) \
+  do                                            \
+    {                                           \
+      std::clog << msg << std::endl;            \
+    }                                           \
+  while (false)
+
+
+
+namespace ns3 {
+
+enum LogLevel {
+  LOG_LEVEL_DEBUG    = 1<<0,
+  LOG_LEVEL_FUNCTION = 1<<1,
+  LOG_LEVEL_PARAM    = 1<<2,
+  LOG_LEVEL_WARN     = 1<<3,
+  LOG_LEVEL_ERROR    = 1<<4,
+  LOG_LEVEL_LAST     = 1<<31
+};
+
+/**
+ * \param name a log component name
+ * \ingroup logging
+ *
+ * Enable the logging output associated with that log component.
+ * The logging output can be later disabled with a call
+ * to ns3::LogComponentDisable.
+ */
+void LogComponentEnable (char const *name, enum LogLevel level);
+
+/**
+ * \param name a log component name
+ * \ingroup logging
+ *
+ * Disable the logging output associated with that log component.
+ * The logging output can be later re-enabled with a call
+ * to ns3::LogComponentEnable.
+ */
+void LogComponentDisable (char const *name, enum LogLevel level);
+
+/**
+ * \ingroup logging
+ *
+ * Print the list of logging messages available.
+ * The output of this function can be obtained by setting
+ * the NS_LOG environment variable to the special value 
+ * 'print-list'.
+ * 
+ * For example: NS_LOG=print-list
+ */
+void LogComponentPrintList (void);
+
+class LogComponent {
+public:
+  LogComponent (char const *name);
+  bool IsEnabled (enum LogLevel level) const;
+  bool IsNoneEnabled (void) const;
+  void Enable (enum LogLevel level);
+  void Disable (enum LogLevel level);
+private:
+  uint32_t m_levels;
+};
+
+} // namespace ns3
+
+#endif /* LOG_H */
--- a/src/core/wscript	Wed Sep 12 16:20:07 2007 -0700
+++ b/src/core/wscript	Wed Sep 12 16:24:31 2007 -0700
@@ -30,6 +30,7 @@
     core.source = [
         'callback-test.cc',
         'debug.cc',
+        'log.cc',
         'breakpoint.cc',
         'ptr.cc',
         'object.cc',
@@ -69,6 +70,7 @@
         'ptr.h',
         'object.h',
         'debug.h',
+        'log.h',
         'assert.h',
         'breakpoint.h',
         'fatal-error.h',