A Discrete-Event Network Simulator
API
log.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2006,2007 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "log.h"
21 
22 #include <list>
23 #include <utility>
24 #include <iostream>
25 #include "assert.h"
26 #include <stdexcept>
27 #include "ns3/core-config.h"
28 #include "fatal-error.h"
29 
30 #ifdef HAVE_GETENV
31 #include <cstring>
32 #endif
33 
34 #ifdef HAVE_STDLIB_H
35 #include <cstdlib>
36 #endif
37 
45 namespace ns3 {
46 
58 
65 class PrintList
66 {
67 public:
68  PrintList (); //<! Constructor, prints the list and exits.
69 };
70 
76 
77 
78 /* static */
81 {
82  static LogComponent::ComponentList components;
83  return &components;
84 }
85 
86 
88 {
89 #ifdef HAVE_GETENV
90  char *envVar = getenv ("NS_LOG");
91  if (envVar == 0)
92  {
93  return;
94  }
95  std::string env = envVar;
96  std::string::size_type cur = 0;
97  std::string::size_type next = 0;
98  while (next != std::string::npos)
99  {
100  next = env.find_first_of (":", cur);
101  std::string tmp = std::string (env, cur, next-cur);
102  if (tmp == "print-list")
103  {
105  exit (0);
106  break;
107  }
108  cur = next + 1;
109  }
110 #endif
111 }
112 
113 
114 LogComponent::LogComponent (const std::string & name,
115  const std::string & file,
116  const enum LogLevel mask /* = 0 */)
117  : m_levels (0), m_mask (mask), m_name (name), m_file (file)
118 {
119  EnvVarCheck ();
120 
122  for (LogComponent::ComponentList::const_iterator i = components->begin ();
123  i != components->end ();
124  i++)
125  {
126  if (i->first == name)
127  {
128  NS_FATAL_ERROR ("Log component \""<<name<<"\" has already been registered once.");
129  }
130  }
131  components->insert (std::make_pair (name, this));
132 }
133 
134 LogComponent &
135 GetLogComponent (const std::string name)
136 {
138  LogComponent* ret;
139 
140  try
141  {
142  ret = components->at (name);
143  }
144  catch (std::out_of_range&)
145  {
146  NS_FATAL_ERROR ("Log component \"" << name << "\" does not exist.");
147  }
148  return *ret;
149 }
150 
151 void
153 {
154 #ifdef HAVE_GETENV
155  char *envVar = getenv ("NS_LOG");
156  if (envVar == 0)
157  {
158  return;
159  }
160  std::string env = envVar;
161 
162  std::string::size_type cur = 0;
163  std::string::size_type next = 0;
164  while (next != std::string::npos)
165  {
166  next = env.find_first_of (":", cur);
167  std::string tmp = std::string (env, cur, next-cur);
168  std::string::size_type equal = tmp.find ("=");
169  std::string component;
170  if (equal == std::string::npos)
171  {
172  component = tmp;
173  if (component == m_name || component == "*" || component == "***")
174  {
175  int level = LOG_LEVEL_ALL | LOG_PREFIX_ALL;
176  Enable ((enum LogLevel)level);
177  return;
178  }
179  }
180  else
181  {
182  component = tmp.substr (0, equal);
183  if (component == m_name || component == "*")
184  {
185  int level = 0;
186  std::string::size_type cur_lev;
187  std::string::size_type next_lev = equal;
188  bool pre_pipe = true; // before the first '|', enables positional 'all', '*'
189  do
190  {
191  cur_lev = next_lev + 1;
192  next_lev = tmp.find ("|", cur_lev);
193  std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
194  if (lev == "error")
195  {
196  level |= LOG_ERROR;
197  }
198  else if (lev == "warn")
199  {
200  level |= LOG_WARN;
201  }
202  else if (lev == "debug")
203  {
204  level |= LOG_DEBUG;
205  }
206  else if (lev == "info")
207  {
208  level |= LOG_INFO;
209  }
210  else if (lev == "function")
211  {
212  level |= LOG_FUNCTION;
213  }
214  else if (lev == "logic")
215  {
216  level |= LOG_LOGIC;
217  }
218  else if ( pre_pipe && ( (lev == "all") || (lev == "*") ) )
219  {
220  level |= LOG_LEVEL_ALL;
221  }
222  else if ( (lev == "prefix_func") || (lev == "func") )
223  {
224  level |= LOG_PREFIX_FUNC;
225  }
226  else if ( (lev == "prefix_time") || (lev == "time") )
227  {
228  level |= LOG_PREFIX_TIME;
229  }
230  else if ( (lev == "prefix_node") || (lev == "node") )
231  {
232  level |= LOG_PREFIX_NODE;
233  }
234  else if ( (lev == "prefix_level") || (lev == "level") )
235  {
236  level |= LOG_PREFIX_LEVEL;
237  }
238  else if ( (lev == "prefix_all") ||
239  (!pre_pipe && ( (lev == "all") || (lev == "*") ) )
240  )
241  {
242  level |= LOG_PREFIX_ALL;
243  }
244  else if (lev == "level_error")
245  {
246  level |= LOG_LEVEL_ERROR;
247  }
248  else if (lev == "level_warn")
249  {
250  level |= LOG_LEVEL_WARN;
251  }
252  else if (lev == "level_debug")
253  {
254  level |= LOG_LEVEL_DEBUG;
255  }
256  else if (lev == "level_info")
257  {
258  level |= LOG_LEVEL_INFO;
259  }
260  else if (lev == "level_function")
261  {
262  level |= LOG_LEVEL_FUNCTION;
263  }
264  else if (lev == "level_logic")
265  {
266  level |= LOG_LEVEL_LOGIC;
267  }
268  else if (lev == "level_all")
269  {
270  level |= LOG_LEVEL_ALL;
271  }
272  else if (lev == "**")
273  {
274  level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
275  }
276 
277  pre_pipe = false;
278  } while (next_lev != std::string::npos);
279 
280  Enable ((enum LogLevel)level);
281  }
282  }
283  cur = next + 1;
284  }
285 #endif
286 }
287 
288 
289 bool
290 LogComponent::IsEnabled (const enum LogLevel level) const
291 {
292  // LogComponentEnableEnvVar ();
293  return (level & m_levels) ? 1 : 0;
294 }
295 
296 bool
298 {
299  return m_levels == 0;
300 }
301 
302 void
303 LogComponent::SetMask (const enum LogLevel level)
304 {
305  m_mask |= level;
306 }
307 
308 void
309 LogComponent::Enable (const enum LogLevel level)
310 {
311  m_levels |= (level & ~m_mask);
312 }
313 
314 void
315 LogComponent::Disable (const enum LogLevel level)
316 {
317  m_levels &= ~level;
318 }
319 
320 char const *
321 LogComponent::Name (void) const
322 {
323  return m_name.c_str ();
324 }
325 
326 std::string
327 LogComponent::File (void) const
328 {
329  return m_file;
330 }
331 
332 /* static */
333 std::string
335 {
336  if (level == LOG_ERROR)
337  {
338  return "ERROR";
339  }
340  else if (level == LOG_WARN)
341  {
342  // whitespace left at the end for alignment
343  return "WARN ";
344  }
345  else if (level == LOG_DEBUG)
346  {
347  return "DEBUG";
348  }
349  else if (level == LOG_INFO)
350  {
351  // whitespace left at the end for alignment
352  return "INFO ";
353  }
354  else if (level == LOG_FUNCTION)
355  {
356  return "FUNCT";
357  }
358  else if (level == LOG_LOGIC)
359  {
360  return "LOGIC";
361  }
362  else
363  {
364  return "unknown";
365  }
366 }
367 
368 void
369 LogComponentEnable (char const *name, enum LogLevel level)
370 {
372  LogComponent::ComponentList::const_iterator i;
373  for (i = components->begin ();
374  i != components->end ();
375  i++)
376  {
377  if (i->first.compare (name) == 0)
378  {
379  i->second->Enable (level);
380  return;
381  }
382  }
383  if (i == components->end())
384  {
385  // nothing matched
387  NS_FATAL_ERROR ("Logging component \"" << name <<
388  "\" not found. See above for a list of available log components");
389  }
390 }
391 
392 void
394 {
396  for (LogComponent::ComponentList::const_iterator i = components->begin ();
397  i != components->end ();
398  i++)
399  {
400  i->second->Enable (level);
401  }
402 }
403 
404 void
405 LogComponentDisable (char const *name, enum LogLevel level)
406 {
408  for (LogComponent::ComponentList::const_iterator i = components->begin ();
409  i != components->end ();
410  i++)
411  {
412  if (i->first.compare (name) == 0)
413  {
414  i->second->Disable (level);
415  break;
416  }
417  }
418 }
419 
420 void
422 {
424  for (LogComponent::ComponentList::const_iterator i = components->begin ();
425  i != components->end ();
426  i++)
427  {
428  i->second->Disable (level);
429  }
430 }
431 
432 void
434 {
436  for (LogComponent::ComponentList::const_iterator i = components->begin ();
437  i != components->end ();
438  i++)
439  {
440  std::cout << i->first << "=";
441  if (i->second->IsNoneEnabled ())
442  {
443  std::cout << "0" << std::endl;
444  continue;
445  }
446  if (i->second->IsEnabled (LOG_LEVEL_ALL))
447  {
448  std::cout << "all";
449  }
450  else
451  {
452  if (i->second->IsEnabled (LOG_ERROR))
453  {
454  std::cout << "error";
455  }
456  if (i->second->IsEnabled (LOG_WARN))
457  {
458  std::cout << "|warn";
459  }
460  if (i->second->IsEnabled (LOG_DEBUG))
461  {
462  std::cout << "|debug";
463  }
464  if (i->second->IsEnabled (LOG_INFO))
465  {
466  std::cout << "|info";
467  }
468  if (i->second->IsEnabled (LOG_FUNCTION))
469  {
470  std::cout << "|function";
471  }
472  if (i->second->IsEnabled (LOG_LOGIC))
473  {
474  std::cout << "|logic";
475  }
476  }
477  if (i->second->IsEnabled (LOG_PREFIX_ALL))
478  {
479  std::cout << "|prefix_all";
480  }
481  else
482  {
483  if (i->second->IsEnabled (LOG_PREFIX_FUNC))
484  {
485  std::cout << "|func";
486  }
487  if (i->second->IsEnabled (LOG_PREFIX_TIME))
488  {
489  std::cout << "|time";
490  }
491  if (i->second->IsEnabled (LOG_PREFIX_NODE))
492  {
493  std::cout << "|node";
494  }
495  if (i->second->IsEnabled (LOG_PREFIX_LEVEL))
496  {
497  std::cout << "|level";
498  }
499  }
500  std::cout << std::endl;
501  }
502 }
503 
512 static bool ComponentExists(std::string componentName)
513 {
514  char const*name=componentName.c_str();
516  LogComponent::ComponentList::const_iterator i;
517  for (i = components->begin ();
518  i != components->end ();
519  i++)
520  {
521  if (i->first.compare (name) == 0)
522  {
523  return true;
524  }
525  }
526  NS_ASSERT (i == components->end());
527  // nothing matched
528  return false;
529 }
530 
536 static void CheckEnvironmentVariables (void)
537 {
538 #ifdef HAVE_GETENV
539  char *envVar = getenv ("NS_LOG");
540  if (envVar == 0 || std::strlen(envVar) == 0)
541  {
542  return;
543  }
544  std::string env = envVar;
545 
546  std::string::size_type cur = 0;
547  std::string::size_type next = 0;
548 
549  while (next != std::string::npos)
550  {
551  next = env.find_first_of (":", cur);
552  std::string tmp = std::string (env, cur, next-cur);
553  std::string::size_type equal = tmp.find ("=");
554  std::string component;
555  if (equal == std::string::npos)
556  {
557  // ie no '=' characters found
558  component = tmp;
559  if (ComponentExists(component) || component == "*" || component == "***")
560  {
561  return;
562  }
563  else
564  {
566  NS_FATAL_ERROR("Invalid or unregistered component name \"" << component <<
567  "\" in env variable NS_LOG, see above for a list of valid components");
568  }
569  }
570  else
571  {
572  component = tmp.substr (0, equal);
573  if (ComponentExists(component) || component == "*")
574  {
575  std::string::size_type cur_lev;
576  std::string::size_type next_lev = equal;
577  do
578  {
579  cur_lev = next_lev + 1;
580  next_lev = tmp.find ("|", cur_lev);
581  std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
582  if (lev == "error"
583  || lev == "warn"
584  || lev == "debug"
585  || lev == "info"
586  || lev == "function"
587  || lev == "logic"
588  || lev == "all"
589  || lev == "prefix_func"
590  || lev == "func"
591  || lev == "prefix_time"
592  || lev == "time"
593  || lev == "prefix_node"
594  || lev == "node"
595  || lev == "prefix_level"
596  || lev == "level"
597  || lev == "prefix_all"
598  || lev == "level_error"
599  || lev == "level_warn"
600  || lev == "level_debug"
601  || lev == "level_info"
602  || lev == "level_function"
603  || lev == "level_logic"
604  || lev == "level_all"
605  || lev == "*"
606  || lev == "**"
607  )
608  {
609  continue;
610  }
611  else
612  {
613  NS_FATAL_ERROR("Invalid log level \"" << lev <<
614  "\" in env variable NS_LOG for component name " << component);
615  }
616  } while (next_lev != std::string::npos);
617  }
618  else
619  {
621  NS_FATAL_ERROR("Invalid or unregistered component name \"" << component <<
622  "\" in env variable NS_LOG, see above for a list of valid components");
623  }
624  }
625  cur = next + 1; // parse next component
626  }
627 #endif
628 }
630 {
631  g_logTimePrinter = printer;
637 }
639 {
640  return g_logTimePrinter;
641 }
642 
644 {
645  g_logNodePrinter = printer;
646 }
648 {
649  return g_logNodePrinter;
650 }
651 
652 
654  : m_first (true),
655  m_os (os)
656 {
657 }
658 
659 template<>
661 ParameterLogger::operator<< <std::string>(const std::string param)
662 {
663  if (m_first)
664  {
665  m_os << "\"" << param << "\"";
666  m_first = false;
667  }
668  else
669  {
670  m_os << ", \"" << param << "\"";
671  }
672  return *this;
673 }
674 
675 template<>
676 ParameterLogger&
677 ParameterLogger::operator<< <const char *>(const char * param)
678 {
679  (*this) << std::string (param);
680  return *this;
681 }
682 
683 template<>
684 ParameterLogger&
685 ParameterLogger::operator<< <int8_t>(const int8_t param)
686 {
687  if (m_first)
688  {
689  m_os << static_cast<int16_t> (param);
690  m_first = false;
691  }
692  else
693  {
694  m_os << ", " << static_cast<int16_t> (param);
695  }
696  return *this;
697 }
698 
699 template<>
700 ParameterLogger&
701 ParameterLogger::operator<< <uint8_t>(const uint8_t param)
702 {
703  if (m_first)
704  {
705  m_os << static_cast<uint16_t> (param);
706  m_first = false;
707  }
708  else
709  {
710  m_os << ", " << static_cast<uint16_t> (param);
711  }
712  return *this;
713 }
714 
715 } // namespace ns3
NS_FATAL_x macro definitions.
std::string File(void) const
Get the compilation unit defining this LogComponent.
Definition: log.cc:327
LogComponent(const std::string &name, const std::string &file, const enum LogLevel mask=LOG_NONE)
Constructor.
Definition: log.cc:114
Serious error messages only.
Definition: log.h:96
Prefix all trace prints with simulation node.
Definition: log.h:119
void LogComponentDisable(char const *name, enum LogLevel level)
Disable the logging output associated with that log component.
Definition: log.cc:405
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition: log.cc:512
bool IsNoneEnabled(void) const
Check if all levels are disabled.
Definition: log.cc:297
Function tracing.
Definition: log.h:108
Informational messages (e.g., banners).
Definition: log.h:105
void LogSetTimePrinter(TimePrinter printer)
Set the TimePrinter function to be used to prepend log messages with the simulation time...
Definition: log.cc:629
static void CheckEnvironmentVariables(void)
Parse the NS_LOG environment variable.
Definition: log.cc:536
A single log component configuration.
Definition: log.h:335
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
ParameterLogger(std::ostream &os)
Constructor.
Definition: log.cc:653
char const * Name(void) const
Get the name of this LogComponent.
Definition: log.cc:321
void Disable(const enum LogLevel level)
Disable logging at level for this LogComponent.
Definition: log.cc:315
void EnvVarCheck(void)
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition: log.cc:152
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:162
std::string m_file
File defining this LogComponent.
Definition: log.h:433
TimePrinter LogGetTimePrinter(void)
Get the LogTimePrinter function currently in use.
Definition: log.cc:638
Insert , when streaming function arguments.
Definition: log.h:448
void LogComponentEnable(char const *name, enum LogLevel level)
Enable the logging output associated with that log component.
Definition: log.cc:369
LOG_ERROR and above.
Definition: log.h:97
void Enable(const enum LogLevel level)
Enable this LogComponent at level.
Definition: log.cc:309
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition: log.cc:643
All prefixes.
Definition: log.h:121
void SetMask(const enum LogLevel level)
Prevent the enabling of a specific LogLevel.
Definition: log.cc:303
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
LOG_INFO and above.
Definition: log.h:106
Prefix all trace prints with log level (severity).
Definition: log.h:120
void LogComponentPrintList(void)
Print the list of logging messages available.
Definition: log.cc:433
LOG_WARN and above.
Definition: log.h:100
Control flow tracing within functions.
Definition: log.h:111
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
Definition: time-printer.h:43
std::map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition: log.h:408
void LogComponentEnableAll(enum LogLevel level)
Enable the logging output for all registered log components.
Definition: log.cc:393
Prefix all trace prints with simulation time.
Definition: log.h:118
NodePrinter LogGetNodePrinter(void)
Get the LogNodePrinter function currently in use.
Definition: log.cc:647
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void LogComponentDisableAll(enum LogLevel level)
Disable all logging for all components.
Definition: log.cc:421
static ComponentList * GetComponentList(void)
Get the list of LogComponnents.
Definition: log.cc:80
void(* NodePrinter)(std::ostream &os)
Function signature for prepending the node id to a log message.
Definition: node-printer.h:40
static NodePrinter g_logNodePrinter
The Log NodePrinter.
Definition: log.cc:57
int32_t m_mask
Blocked LogLevels.
Definition: log.h:431
int32_t m_levels
Enabled LogLevels.
Definition: log.h:430
static PrintList g_printList
Invoke handler for print-list in NS_LOG environment variable.
Definition: log.cc:75
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition: log.cc:135
LogLevel
Logging severity classes and levels.
Definition: log.h:93
Handler for print-list token in NS_LOG to print the list of log components.
Definition: log.cc:65
LOG_FUNCTION and above.
Definition: log.h:109
static TimePrinter g_logTimePrinter
The Log TimePrinter.
Definition: log.cc:52
LOG_DEBUG and above.
Definition: log.h:103
Prefix all trace prints with function.
Definition: log.h:117
PrintList()
Definition: log.cc:87
LOG_LOGIC and above.
Definition: log.h:112
Rare ad-hoc debug messages.
Definition: log.h:102
Print everything.
Definition: log.h:115
bool IsEnabled(const enum LogLevel level) const
Check if this LogComponent is enabled for level.
Definition: log.cc:290
Warning messages.
Definition: log.h:99
Debug message logging.
static std::string GetLevelLabel(const enum LogLevel level)
Get the string label for the given LogLevel.
Definition: log.cc:334
std::string m_name
LogComponent name.
Definition: log.h:432