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 #include <cstdlib> // getenv
31 #include <cstring> // strlen
32 
40 namespace ns3 {
41 
53 
60 class PrintList
61 {
62 public:
63  PrintList (); //<! Constructor, prints the list and exits.
64 };
65 
71 
72 
73 /* static */
76 {
77  static LogComponent::ComponentList components;
78  return &components;
79 }
80 
81 
83 {
84  const char *envVar = std::getenv ("NS_LOG");
85  if (envVar == 0 || std::strlen (envVar) == 0)
86  {
87  return;
88  }
89  std::string env = envVar;
90  std::string::size_type cur = 0;
91  std::string::size_type next = 0;
92  while (next != std::string::npos)
93  {
94  next = env.find_first_of (":", cur);
95  std::string tmp = std::string (env, cur, next - cur);
96  if (tmp == "print-list")
97  {
99  exit (0);
100  break;
101  }
102  cur = next + 1;
103  }
104 }
105 
106 
107 LogComponent::LogComponent (const std::string & name,
108  const std::string & file,
109  const enum LogLevel mask /* = 0 */)
110  : m_levels (0), m_mask (mask), m_name (name), m_file (file)
111 {
112  EnvVarCheck ();
113 
115  for (LogComponent::ComponentList::const_iterator i = components->begin ();
116  i != components->end ();
117  i++)
118  {
119  if (i->first == name)
120  {
121  NS_FATAL_ERROR ("Log component \"" << name << "\" has already been registered once.");
122  }
123  }
124  components->insert (std::make_pair (name, this));
125 }
126 
127 LogComponent &
128 GetLogComponent (const std::string name)
129 {
131  LogComponent* ret;
132 
133  try
134  {
135  ret = components->at (name);
136  }
137  catch (std::out_of_range&)
138  {
139  NS_FATAL_ERROR ("Log component \"" << name << "\" does not exist.");
140  }
141  return *ret;
142 }
143 
144 void
146 {
147  const char *envVar = std::getenv ("NS_LOG");
148  if (envVar == 0 || std::strlen (envVar) == 0)
149  {
150  return;
151  }
152  std::string env = envVar;
153 
154  std::string::size_type cur = 0;
155  std::string::size_type next = 0;
156  while (next != std::string::npos)
157  {
158  next = env.find_first_of (":", cur);
159  std::string tmp = std::string (env, cur, next - cur);
160  std::string::size_type equal = tmp.find ("=");
161  std::string component;
162  if (equal == std::string::npos)
163  {
164  component = tmp;
165  if (component == m_name || component == "*" || component == "***")
166  {
167  int level = LOG_LEVEL_ALL | LOG_PREFIX_ALL;
168  Enable ((enum LogLevel)level);
169  return;
170  }
171  }
172  else
173  {
174  component = tmp.substr (0, equal);
175  if (component == m_name || component == "*")
176  {
177  int level = 0;
178  std::string::size_type cur_lev;
179  std::string::size_type next_lev = equal;
180  bool pre_pipe = true; // before the first '|', enables positional 'all', '*'
181  do
182  {
183  cur_lev = next_lev + 1;
184  next_lev = tmp.find ("|", cur_lev);
185  std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
186  if (lev == "error")
187  {
188  level |= LOG_ERROR;
189  }
190  else if (lev == "warn")
191  {
192  level |= LOG_WARN;
193  }
194  else if (lev == "debug")
195  {
196  level |= LOG_DEBUG;
197  }
198  else if (lev == "info")
199  {
200  level |= LOG_INFO;
201  }
202  else if (lev == "function")
203  {
204  level |= LOG_FUNCTION;
205  }
206  else if (lev == "logic")
207  {
208  level |= LOG_LOGIC;
209  }
210  else if ( pre_pipe && ( (lev == "all") || (lev == "*") ) )
211  {
212  level |= LOG_LEVEL_ALL;
213  }
214  else if ( (lev == "prefix_func") || (lev == "func") )
215  {
216  level |= LOG_PREFIX_FUNC;
217  }
218  else if ( (lev == "prefix_time") || (lev == "time") )
219  {
220  level |= LOG_PREFIX_TIME;
221  }
222  else if ( (lev == "prefix_node") || (lev == "node") )
223  {
224  level |= LOG_PREFIX_NODE;
225  }
226  else if ( (lev == "prefix_level") || (lev == "level") )
227  {
228  level |= LOG_PREFIX_LEVEL;
229  }
230  else if ( (lev == "prefix_all")
231  || (!pre_pipe && ( (lev == "all") || (lev == "*") ) )
232  )
233  {
234  level |= LOG_PREFIX_ALL;
235  }
236  else if (lev == "level_error")
237  {
238  level |= LOG_LEVEL_ERROR;
239  }
240  else if (lev == "level_warn")
241  {
242  level |= LOG_LEVEL_WARN;
243  }
244  else if (lev == "level_debug")
245  {
246  level |= LOG_LEVEL_DEBUG;
247  }
248  else if (lev == "level_info")
249  {
250  level |= LOG_LEVEL_INFO;
251  }
252  else if (lev == "level_function")
253  {
254  level |= LOG_LEVEL_FUNCTION;
255  }
256  else if (lev == "level_logic")
257  {
258  level |= LOG_LEVEL_LOGIC;
259  }
260  else if (lev == "level_all")
261  {
262  level |= LOG_LEVEL_ALL;
263  }
264  else if (lev == "**")
265  {
266  level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
267  }
268 
269  pre_pipe = false;
270  }
271  while (next_lev != std::string::npos);
272 
273  Enable ((enum LogLevel)level);
274  }
275  }
276  cur = next + 1;
277  }
278 }
279 
280 
281 bool
282 LogComponent::IsEnabled (const enum LogLevel level) const
283 {
284  // LogComponentEnableEnvVar ();
285  return (level & m_levels) ? 1 : 0;
286 }
287 
288 bool
290 {
291  return m_levels == 0;
292 }
293 
294 void
295 LogComponent::SetMask (const enum LogLevel level)
296 {
297  m_mask |= level;
298 }
299 
300 void
301 LogComponent::Enable (const enum LogLevel level)
302 {
303  m_levels |= (level & ~m_mask);
304 }
305 
306 void
307 LogComponent::Disable (const enum LogLevel level)
308 {
309  m_levels &= ~level;
310 }
311 
312 char const *
313 LogComponent::Name (void) const
314 {
315  return m_name.c_str ();
316 }
317 
318 std::string
319 LogComponent::File (void) const
320 {
321  return m_file;
322 }
323 
324 /* static */
325 std::string
327 {
328  if (level == LOG_ERROR)
329  {
330  return "ERROR";
331  }
332  else if (level == LOG_WARN)
333  {
334  // whitespace left at the end for alignment
335  return "WARN ";
336  }
337  else if (level == LOG_DEBUG)
338  {
339  return "DEBUG";
340  }
341  else if (level == LOG_INFO)
342  {
343  // whitespace left at the end for alignment
344  return "INFO ";
345  }
346  else if (level == LOG_FUNCTION)
347  {
348  return "FUNCT";
349  }
350  else if (level == LOG_LOGIC)
351  {
352  return "LOGIC";
353  }
354  else
355  {
356  return "unknown";
357  }
358 }
359 
360 void
361 LogComponentEnable (char const *name, enum LogLevel level)
362 {
364  LogComponent::ComponentList::const_iterator i;
365  for (i = components->begin ();
366  i != components->end ();
367  i++)
368  {
369  if (i->first.compare (name) == 0)
370  {
371  i->second->Enable (level);
372  return;
373  }
374  }
375  if (i == components->end ())
376  {
377  // nothing matched
379  NS_FATAL_ERROR ("Logging component \"" << name <<
380  "\" not found. See above for a list of available log components");
381  }
382 }
383 
384 void
386 {
388  for (LogComponent::ComponentList::const_iterator i = components->begin ();
389  i != components->end ();
390  i++)
391  {
392  i->second->Enable (level);
393  }
394 }
395 
396 void
397 LogComponentDisable (char const *name, enum LogLevel level)
398 {
400  for (LogComponent::ComponentList::const_iterator i = components->begin ();
401  i != components->end ();
402  i++)
403  {
404  if (i->first.compare (name) == 0)
405  {
406  i->second->Disable (level);
407  break;
408  }
409  }
410 }
411 
412 void
414 {
416  for (LogComponent::ComponentList::const_iterator i = components->begin ();
417  i != components->end ();
418  i++)
419  {
420  i->second->Disable (level);
421  }
422 }
423 
424 void
426 {
428  for (LogComponent::ComponentList::const_iterator i = components->begin ();
429  i != components->end ();
430  i++)
431  {
432  std::cout << i->first << "=";
433  if (i->second->IsNoneEnabled ())
434  {
435  std::cout << "0" << std::endl;
436  continue;
437  }
438  if (i->second->IsEnabled (LOG_LEVEL_ALL))
439  {
440  std::cout << "all";
441  }
442  else
443  {
444  if (i->second->IsEnabled (LOG_ERROR))
445  {
446  std::cout << "error";
447  }
448  if (i->second->IsEnabled (LOG_WARN))
449  {
450  std::cout << "|warn";
451  }
452  if (i->second->IsEnabled (LOG_DEBUG))
453  {
454  std::cout << "|debug";
455  }
456  if (i->second->IsEnabled (LOG_INFO))
457  {
458  std::cout << "|info";
459  }
460  if (i->second->IsEnabled (LOG_FUNCTION))
461  {
462  std::cout << "|function";
463  }
464  if (i->second->IsEnabled (LOG_LOGIC))
465  {
466  std::cout << "|logic";
467  }
468  }
469  if (i->second->IsEnabled (LOG_PREFIX_ALL))
470  {
471  std::cout << "|prefix_all";
472  }
473  else
474  {
475  if (i->second->IsEnabled (LOG_PREFIX_FUNC))
476  {
477  std::cout << "|func";
478  }
479  if (i->second->IsEnabled (LOG_PREFIX_TIME))
480  {
481  std::cout << "|time";
482  }
483  if (i->second->IsEnabled (LOG_PREFIX_NODE))
484  {
485  std::cout << "|node";
486  }
487  if (i->second->IsEnabled (LOG_PREFIX_LEVEL))
488  {
489  std::cout << "|level";
490  }
491  }
492  std::cout << std::endl;
493  }
494 }
495 
504 static bool ComponentExists (std::string componentName)
505 {
506  char const*name = componentName.c_str ();
508  LogComponent::ComponentList::const_iterator i;
509  for (i = components->begin ();
510  i != components->end ();
511  i++)
512  {
513  if (i->first.compare (name) == 0)
514  {
515  return true;
516  }
517  }
518  NS_ASSERT (i == components->end ());
519  // nothing matched
520  return false;
521 }
522 
528 static void CheckEnvironmentVariables (void)
529 {
530  const char *envVar = std::getenv ("NS_LOG");
531  if (envVar == 0 || std::strlen (envVar) == 0)
532  {
533  return;
534  }
535 
536  std::string env = envVar;
537  std::string::size_type cur = 0;
538  std::string::size_type next = 0;
539 
540  while (next != std::string::npos)
541  {
542  next = env.find_first_of (":", cur);
543  std::string tmp = std::string (env, cur, next - cur);
544  std::string::size_type equal = tmp.find ("=");
545  std::string component;
546  if (equal == std::string::npos)
547  {
548  // ie no '=' characters found
549  component = tmp;
550  if (ComponentExists (component) || component == "*" || component == "***")
551  {
552  return;
553  }
554  else
555  {
557  NS_FATAL_ERROR ("Invalid or unregistered component name \"" << component <<
558  "\" in env variable NS_LOG, see above for a list of valid components");
559  }
560  }
561  else
562  {
563  component = tmp.substr (0, equal);
564  if (ComponentExists (component) || component == "*")
565  {
566  std::string::size_type cur_lev;
567  std::string::size_type next_lev = equal;
568  do
569  {
570  cur_lev = next_lev + 1;
571  next_lev = tmp.find ("|", cur_lev);
572  std::string lev = tmp.substr (cur_lev, next_lev - cur_lev);
573  if (lev == "error"
574  || lev == "warn"
575  || lev == "debug"
576  || lev == "info"
577  || lev == "function"
578  || lev == "logic"
579  || lev == "all"
580  || lev == "prefix_func"
581  || lev == "func"
582  || lev == "prefix_time"
583  || lev == "time"
584  || lev == "prefix_node"
585  || lev == "node"
586  || lev == "prefix_level"
587  || lev == "level"
588  || lev == "prefix_all"
589  || lev == "level_error"
590  || lev == "level_warn"
591  || lev == "level_debug"
592  || lev == "level_info"
593  || lev == "level_function"
594  || lev == "level_logic"
595  || lev == "level_all"
596  || lev == "*"
597  || lev == "**"
598  )
599  {
600  continue;
601  }
602  else
603  {
604  NS_FATAL_ERROR ("Invalid log level \"" << lev <<
605  "\" in env variable NS_LOG for component name " << component);
606  }
607  }
608  while (next_lev != std::string::npos);
609  }
610  else
611  {
613  NS_FATAL_ERROR ("Invalid or unregistered component name \"" << component <<
614  "\" in env variable NS_LOG, see above for a list of valid components");
615  }
616  }
617  cur = next + 1; // parse next component
618  }
619 }
621 {
622  g_logTimePrinter = printer;
628 }
630 {
631  return g_logTimePrinter;
632 }
633 
635 {
636  g_logNodePrinter = printer;
637 }
639 {
640  return g_logNodePrinter;
641 }
642 
643 
645  : m_first (true),
646  m_os (os)
647 {}
648 
649 template<>
651 ParameterLogger::operator<< <std::string> (const std::string param)
652 {
653  if (m_first)
654  {
655  m_os << "\"" << param << "\"";
656  m_first = false;
657  }
658  else
659  {
660  m_os << ", \"" << param << "\"";
661  }
662  return *this;
663 }
664 
665 template<>
666 ParameterLogger &
667 ParameterLogger::operator<< <const char *> (const char * param)
668 {
669  (*this) << std::string (param);
670  return *this;
671 }
672 
673 template<>
674 ParameterLogger &
675 ParameterLogger::operator<< <int8_t> (const int8_t param)
676 {
677  if (m_first)
678  {
679  m_os << static_cast<int16_t> (param);
680  m_first = false;
681  }
682  else
683  {
684  m_os << ", " << static_cast<int16_t> (param);
685  }
686  return *this;
687 }
688 
689 template<>
690 ParameterLogger &
691 ParameterLogger::operator<< <uint8_t> (const uint8_t param)
692 {
693  if (m_first)
694  {
695  m_os << static_cast<uint16_t> (param);
696  m_first = false;
697  }
698  else
699  {
700  m_os << ", " << static_cast<uint16_t> (param);
701  }
702  return *this;
703 }
704 
705 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
A single log component configuration.
Definition: log.h:337
void Enable(const enum LogLevel level)
Enable this LogComponent at level.
Definition: log.cc:301
int32_t m_levels
Enabled LogLevels.
Definition: log.h:430
static std::string GetLevelLabel(const enum LogLevel level)
Get the string label for the given LogLevel.
Definition: log.cc:326
static ComponentList * GetComponentList(void)
Get the list of LogComponnents.
Definition: log.cc:75
void Disable(const enum LogLevel level)
Disable logging at level for this LogComponent.
Definition: log.cc:307
bool IsNoneEnabled(void) const
Check if all levels are disabled.
Definition: log.cc:289
std::string m_file
File defining this LogComponent.
Definition: log.h:433
std::string File(void) const
Get the compilation unit defining this LogComponent.
Definition: log.cc:319
void SetMask(const enum LogLevel level)
Prevent the enabling of a specific LogLevel.
Definition: log.cc:295
LogComponent(const std::string &name, const std::string &file, const enum LogLevel mask=LOG_NONE)
Constructor.
Definition: log.cc:107
std::map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition: log.h:409
char const * Name(void) const
Get the name of this LogComponent.
Definition: log.cc:313
int32_t m_mask
Blocked LogLevels.
Definition: log.h:431
void EnvVarCheck(void)
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition: log.cc:145
std::string m_name
LogComponent name.
Definition: log.h:432
bool IsEnabled(const enum LogLevel level) const
Check if this LogComponent is enabled for level.
Definition: log.cc:282
Insert , when streaming function arguments.
Definition: log.h:449
bool m_first
First argument flag, doesn't get ,.
Definition: log.h:450
ParameterLogger(std::ostream &os)
Constructor.
Definition: log.cc:644
std::ostream & m_os
Underlying output stream.
Definition: log.h:451
Handler for print-list token in NS_LOG to print the list of log components.
Definition: log.cc:61
PrintList()
Definition: log.cc:82
NS_FATAL_x macro definitions.
#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
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
static NodePrinter g_logNodePrinter
The Log NodePrinter.
Definition: log.cc:52
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition: log.cc:504
static void CheckEnvironmentVariables(void)
Parse the NS_LOG environment variable.
Definition: log.cc:528
static TimePrinter g_logTimePrinter
The Log TimePrinter.
Definition: log.cc:47
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static PrintList g_printList
Invoke handler for print-list in NS_LOG environment variable.
Definition: log.cc:70
void LogComponentDisableAll(enum LogLevel level)
Disable all logging for all components.
Definition: log.cc:413
void LogSetTimePrinter(TimePrinter printer)
Set the TimePrinter function to be used to prepend log messages with the simulation time.
Definition: log.cc:620
void LogComponentPrintList(void)
Print the list of logging messages available.
Definition: log.cc:425
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
Definition: time-printer.h:43
NodePrinter LogGetNodePrinter(void)
Get the LogNodePrinter function currently in use.
Definition: log.cc:638
void(* NodePrinter)(std::ostream &os)
Function signature for prepending the node id to a log message.
Definition: node-printer.h:40
LogLevel
Logging severity classes and levels.
Definition: log.h:94
@ LOG_LEVEL_ALL
Print everything.
Definition: log.h:116
@ LOG_PREFIX_FUNC
Prefix all trace prints with function.
Definition: log.h:118
@ LOG_LEVEL_LOGIC
LOG_LOGIC and above.
Definition: log.h:113
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition: log.h:119
@ LOG_FUNCTION
Function tracing.
Definition: log.h:109
@ LOG_ERROR
Serious error messages only.
Definition: log.h:97
@ LOG_WARN
Warning messages.
Definition: log.h:100
@ LOG_INFO
Informational messages (e.g., banners).
Definition: log.h:106
@ LOG_PREFIX_ALL
All prefixes.
Definition: log.h:122
@ LOG_LEVEL_FUNCTION
LOG_FUNCTION and above.
Definition: log.h:110
@ LOG_LEVEL_ERROR
LOG_ERROR and above.
Definition: log.h:98
@ LOG_LEVEL_WARN
LOG_WARN and above.
Definition: log.h:101
@ LOG_LEVEL_DEBUG
LOG_DEBUG and above.
Definition: log.h:104
@ LOG_PREFIX_LEVEL
Prefix all trace prints with log level (severity).
Definition: log.h:121
@ LOG_LOGIC
Control flow tracing within functions.
Definition: log.h:112
@ LOG_PREFIX_NODE
Prefix all trace prints with simulation node.
Definition: log.h:120
@ LOG_LEVEL_INFO
LOG_INFO and above.
Definition: log.h:107
@ LOG_DEBUG
Rare ad-hoc debug messages.
Definition: log.h:103
TimePrinter LogGetTimePrinter(void)
Get the LogTimePrinter function currently in use.
Definition: log.cc:629
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition: log.cc:128
void LogComponentDisable(char const *name, enum LogLevel level)
Disable the logging output associated with that log component.
Definition: log.cc:397
void LogComponentEnable(char const *name, enum LogLevel level)
Enable the logging output associated with that log component.
Definition: log.cc:361
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition: log.cc:634
void LogComponentEnableAll(enum LogLevel level)
Enable the logging output for all registered log components.
Definition: log.cc:385