A Discrete-Event Network Simulator
API
log.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006,2007 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 #include "log.h"
20 
21 #include "assert.h"
22 #include "environment-variable.h"
23 #include "fatal-error.h"
24 #include "string.h"
25 
26 #include "ns3/core-config.h"
27 
28 #include <algorithm> // transform
29 #include <cstring> // strlen
30 #include <iostream>
31 #include <list>
32 #include <locale> // toupper
33 #include <map>
34 #include <numeric> // accumulate
35 #include <stdexcept>
36 #include <utility>
37 
48 namespace
49 {
51 const std::map<std::string, ns3::LogLevel> LOG_LABEL_LEVELS = {
52  // clang-format off
53  {"none", ns3::LOG_NONE},
54  {"error", ns3::LOG_ERROR},
55  {"level_error", ns3::LOG_LEVEL_ERROR},
56  {"warn", ns3::LOG_WARN},
57  {"level_warn", ns3::LOG_LEVEL_WARN},
58  {"debug", ns3::LOG_DEBUG},
59  {"level_debug", ns3::LOG_LEVEL_DEBUG},
60  {"info", ns3::LOG_INFO},
61  {"level_info", ns3::LOG_LEVEL_INFO},
62  {"function", ns3::LOG_FUNCTION},
63  {"level_function", ns3::LOG_LEVEL_FUNCTION},
64  {"logic", ns3::LOG_LOGIC},
65  {"level_logic", ns3::LOG_LEVEL_LOGIC},
66  {"all", ns3::LOG_ALL},
67  {"level_all", ns3::LOG_LEVEL_ALL},
68  {"func", ns3::LOG_PREFIX_FUNC},
69  {"prefix_func", ns3::LOG_PREFIX_FUNC},
70  {"time", ns3::LOG_PREFIX_TIME},
71  {"prefix_time", ns3::LOG_PREFIX_TIME},
72  {"node", ns3::LOG_PREFIX_NODE},
73  {"prefix_node", ns3::LOG_PREFIX_NODE},
74  {"level", ns3::LOG_PREFIX_LEVEL},
75  {"prefix_level", ns3::LOG_PREFIX_LEVEL},
76  {"prefix_all", ns3::LOG_PREFIX_ALL}
77  // clang-format on
78 };
79 
81 const std::map<ns3::LogLevel, std::string> LOG_LEVEL_LABELS = {[]() {
82  std::map<ns3::LogLevel, std::string> labels;
83  for (const auto& [label, lev] : LOG_LABEL_LEVELS)
84  {
85  // Only keep the first label for a level
86  if (labels.find(lev) == labels.end())
87  {
88  std::string pad{label};
89  // Add whitespace for alignment with "ERROR", "DEBUG" etc.
90  if (pad.size() < 5)
91  {
92  pad.insert(pad.size(), 5 - pad.size(), ' ');
93  }
94  std::transform(pad.begin(), pad.end(), pad.begin(), ::toupper);
95  labels[lev] = pad;
96  }
97  }
98  return labels;
99 }()};
100 
101 } // Unnamed namespace
102 
103 namespace ns3
104 {
105 
111 static TimePrinter g_logTimePrinter = nullptr;
116 static NodePrinter g_logNodePrinter = nullptr;
117 
130 {
131  public:
132  PrintList(); //<! Constructor, prints the list and exits.
133 };
134 
140 
141 /* static */
144 {
145  static LogComponent::ComponentList components;
146  return &components;
147 }
148 
150 {
151  auto [found, value] = EnvironmentVariable::Get("NS_LOG", "print-list", ":");
152  if (found)
153  {
155  exit(0);
156  }
157 }
158 
159 LogComponent::LogComponent(const std::string& name,
160  const std::string& file,
161  const LogLevel mask /* = 0 */)
162  : m_levels(0),
163  m_mask(mask),
164  m_name(name),
165  m_file(file)
166 {
167  // Check if we're mentioned in NS_LOG, and set our flags appropriately
168  EnvVarCheck();
169 
171  for (LogComponent::ComponentList::const_iterator i = components->begin();
172  i != components->end();
173  i++)
174  {
175  if (i->first == name)
176  {
177  NS_FATAL_ERROR("Log component \"" << name << "\" has already been registered once.");
178  }
179  }
180  components->insert(std::make_pair(name, this));
181 }
182 
184 GetLogComponent(const std::string name)
185 {
187  LogComponent* ret;
188 
189  try
190  {
191  ret = components->at(name);
192  }
193  catch (std::out_of_range&)
194  {
195  NS_FATAL_ERROR("Log component \"" << name << "\" does not exist.");
196  }
197  return *ret;
198 }
199 
200 void
202 {
203  auto [found, value] = EnvironmentVariable::Get("NS_LOG", m_name, ":");
204  if (!found)
205  {
206  std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "*", ":");
207  }
208  if (!found)
209  {
210  std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "***", ":");
211  }
212 
213  if (!found)
214  {
215  return;
216  }
217 
218  if (value.empty())
219  {
220  // Default is enable all levels, all prefixes
221  value = "**";
222  }
223 
224  // Got a value, might have flags
225  int level = 0;
226  StringVector flags = SplitString(value, "|");
227  NS_ASSERT_MSG(!flags.empty(), "Unexpected empty flags from non-empty value");
228  bool pre_pipe{true};
229 
230  for (const auto& lev : flags)
231  {
232  if (lev == "**")
233  {
234  level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
235  }
236  else if (lev == "all" || lev == "*")
237  {
238  level |= (pre_pipe ? LOG_LEVEL_ALL : LOG_PREFIX_ALL);
239  }
240  else if (LOG_LABEL_LEVELS.find(lev) != LOG_LABEL_LEVELS.end())
241  {
242  level |= LOG_LABEL_LEVELS.at(lev);
243  }
244  pre_pipe = false;
245  }
246  Enable((LogLevel)level);
247 }
248 
249 bool
251 {
252  // LogComponentEnableEnvVar ();
253  return (level & m_levels) ? 1 : 0;
254 }
255 
256 bool
258 {
259  return m_levels == 0;
260 }
261 
262 void
264 {
265  m_mask |= level;
266 }
267 
268 void
270 {
271  m_levels |= (level & ~m_mask);
272 }
273 
274 void
276 {
277  m_levels &= ~level;
278 }
279 
280 std::string
282 {
283  return m_name;
284 }
285 
286 std::string
288 {
289  return m_file;
290 }
291 
292 /* static */
293 std::string
295 {
296  auto it = LOG_LEVEL_LABELS.find(level);
297  if (it != LOG_LEVEL_LABELS.end())
298  {
299  return it->second;
300  }
301  return "unknown";
302 }
303 
304 void
305 LogComponentEnable(const std::string& name, LogLevel level)
306 {
308  LogComponent::ComponentList::const_iterator i;
309  for (i = components->begin(); i != components->end(); i++)
310  {
311  if (i->first == name)
312  {
313  i->second->Enable(level);
314  return;
315  }
316  }
317  if (i == components->end())
318  {
319  // nothing matched
320  NS_LOG_UNCOND("Logging component \"" << name << "\" not found.");
322  NS_FATAL_ERROR("Logging component \""
323  << name << "\" not found."
324  << " See above for a list of available log components");
325  }
326 }
327 
328 void
330 {
332  for (LogComponent::ComponentList::const_iterator i = components->begin();
333  i != components->end();
334  i++)
335  {
336  i->second->Enable(level);
337  }
338 }
339 
340 void
341 LogComponentDisable(const std::string& name, LogLevel level)
342 {
344  for (LogComponent::ComponentList::const_iterator i = components->begin();
345  i != components->end();
346  i++)
347  {
348  if (i->first == name)
349  {
350  i->second->Disable(level);
351  break;
352  }
353  }
354 }
355 
356 void
358 {
360  for (LogComponent::ComponentList::const_iterator i = components->begin();
361  i != components->end();
362  i++)
363  {
364  i->second->Disable(level);
365  }
366 }
367 
368 void
370 {
372  for (LogComponent::ComponentList::const_iterator i = components->begin();
373  i != components->end();
374  i++)
375  {
376  std::cout << i->first << "=";
377  if (i->second->IsNoneEnabled())
378  {
379  std::cout << "0" << std::endl;
380  continue;
381  }
382  if (i->second->IsEnabled(LOG_LEVEL_ALL))
383  {
384  std::cout << "all";
385  }
386  else
387  {
388  if (i->second->IsEnabled(LOG_ERROR))
389  {
390  std::cout << "error";
391  }
392  if (i->second->IsEnabled(LOG_WARN))
393  {
394  std::cout << "|warn";
395  }
396  if (i->second->IsEnabled(LOG_DEBUG))
397  {
398  std::cout << "|debug";
399  }
400  if (i->second->IsEnabled(LOG_INFO))
401  {
402  std::cout << "|info";
403  }
404  if (i->second->IsEnabled(LOG_FUNCTION))
405  {
406  std::cout << "|function";
407  }
408  if (i->second->IsEnabled(LOG_LOGIC))
409  {
410  std::cout << "|logic";
411  }
412  }
413  if (i->second->IsEnabled(LOG_PREFIX_ALL))
414  {
415  std::cout << "|prefix_all";
416  }
417  else
418  {
419  if (i->second->IsEnabled(LOG_PREFIX_FUNC))
420  {
421  std::cout << "|func";
422  }
423  if (i->second->IsEnabled(LOG_PREFIX_TIME))
424  {
425  std::cout << "|time";
426  }
427  if (i->second->IsEnabled(LOG_PREFIX_NODE))
428  {
429  std::cout << "|node";
430  }
431  if (i->second->IsEnabled(LOG_PREFIX_LEVEL))
432  {
433  std::cout << "|level";
434  }
435  }
436  std::cout << std::endl;
437  }
438 }
439 
448 static bool
449 ComponentExists(std::string componentName)
450 {
452  LogComponent::ComponentList::const_iterator i;
453  for (i = components->begin(); i != components->end(); i++)
454  {
455  if (i->first == componentName)
456  {
457  return true;
458  }
459  }
460  NS_ASSERT(i == components->end());
461  // nothing matched
462  return false;
463 }
464 
470 static void
472 {
473  auto dict = EnvironmentVariable::GetDictionary("NS_LOG", ":")->GetStore();
474 
475  for (auto& [component, value] : dict)
476  {
477  if (component != "*" && component != "***" && !ComponentExists(component))
478  {
479  NS_LOG_UNCOND("Invalid or unregistered component name \"" << component << "\"");
482  "Invalid or unregistered component name \""
483  << component
484  << "\" in env variable NS_LOG, see above for a list of valid components");
485  }
486 
487  // We have a valid component or wildcard, check the flags
488  if (!value.empty())
489  {
490  // Check the flags present in value
491  StringVector flags = SplitString(value, "|");
492  for (const auto& flag : flags)
493  {
494  // Handle wild cards
495  if (flag == "*" || flag == "**")
496  {
497  continue;
498  }
499  bool ok = LOG_LABEL_LEVELS.find(flag) != LOG_LABEL_LEVELS.end();
500  if (!ok)
501  {
502  NS_FATAL_ERROR("Invalid log level \""
503  << flag << "\" in env variable NS_LOG for component name "
504  << component);
505  }
506  } // for flag
507  } // !value.empty
508  } // for component
509 }
510 
511 void
513 {
514  g_logTimePrinter = printer;
520 }
521 
524 {
525  return g_logTimePrinter;
526 }
527 
528 void
530 {
531  g_logNodePrinter = printer;
532 }
533 
536 {
537  return g_logNodePrinter;
538 }
539 
541  : m_os(os)
542 {
543 }
544 
545 void
547 {
548  if (m_first)
549  {
550  m_first = false;
551  }
552  else
553  {
554  m_os << ", ";
555  }
556 }
557 
558 template <>
560 ParameterLogger::operator<< <std::string>(const std::string& param)
561 {
562  CommaRest();
563  m_os << "\"" << param << "\"";
564  return *this;
565 }
566 
568 ParameterLogger::operator<<(const char* param)
569 {
570  (*this) << std::string(param);
571  return *this;
572 }
573 
574 template <>
576 ParameterLogger::operator<< <int8_t>(const int8_t param)
577 {
578  (*this) << static_cast<int16_t>(param);
579  return *this;
580 }
581 
582 template <>
583 ParameterLogger&
584 ParameterLogger::operator<< <uint8_t>(const uint8_t param)
585 {
586  (*this) << static_cast<uint16_t>(param);
587  return *this;
588 }
589 
590 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
static KeyFoundType Get(const std::string &envvar, const std::string &key="", const std::string &delim=";")
Get the value corresponding to a key from an environment variable.
static std::shared_ptr< Dictionary > GetDictionary(const std::string &envvar, const std::string &delim=";")
Get the dictionary for a particular environment variable.
A single log component configuration.
Definition: log.h:328
static ComponentList * GetComponentList()
Get the list of LogComponents.
Definition: log.cc:143
void Enable(const LogLevel level)
Enable this LogComponent at level.
Definition: log.cc:269
bool IsEnabled(const LogLevel level) const
Check if this LogComponent is enabled for level.
Definition: log.cc:250
std::string File() const
Get the compilation unit defining this LogComponent.
Definition: log.cc:287
int32_t m_levels
Enabled LogLevels.
Definition: log.h:419
void Disable(const LogLevel level)
Disable logging at level for this LogComponent.
Definition: log.cc:275
static std::string GetLevelLabel(const LogLevel level)
Get the string label for the given LogLevel.
Definition: log.cc:294
void EnvVarCheck()
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition: log.cc:201
std::string m_file
File defining this LogComponent.
Definition: log.h:422
bool IsNoneEnabled() const
Check if all levels are disabled.
Definition: log.cc:257
std::string Name() const
Get the name of this LogComponent.
Definition: log.cc:281
int32_t m_mask
Blocked LogLevels.
Definition: log.h:420
std::map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition: log.h:398
LogComponent(const std::string &name, const std::string &file, const LogLevel mask=LOG_NONE)
Constructor.
Definition: log.cc:159
void SetMask(const LogLevel level)
Prevent the enabling of a specific LogLevel.
Definition: log.cc:263
std::string m_name
LogComponent name.
Definition: log.h:421
Insert , when streaming function arguments.
Definition: log.h:438
ParameterLogger & operator<<(T param)
Write a function parameter on the output stream, separating parameters after the first by ,...
Definition: log.h:498
void CommaRest()
Add , before every parameter after the first.
Definition: log.cc:546
bool m_first
First argument flag, doesn't get ,.
Definition: log.h:492
ParameterLogger(std::ostream &os)
Constructor.
Definition: log.cc:540
std::ostream & m_os
Underlying output stream.
Definition: log.h:493
Handler for the undocumented print-list token in NS_LOG which triggers printing of the list of log co...
Definition: log.cc:130
Class Environment declaration.
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:66
#define NS_ASSERT_MSG(condition, message)
At runtime, in debugging builds, if this condition is not true, the program prints the message to out...
Definition: assert.h:86
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionally.
static NodePrinter g_logNodePrinter
The Log NodePrinter.
Definition: log.cc:116
static void CheckEnvironmentVariables()
Parse the NS_LOG environment variable.
Definition: log.cc:471
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition: log.cc:449
static TimePrinter g_logTimePrinter
The Log TimePrinter.
Definition: log.cc:111
Debug message logging.
const std::map< std::string, ns3::LogLevel > LOG_LABEL_LEVELS
Mapping of log level text names to values.
Definition: log.cc:51
const std::map< ns3::LogLevel, std::string > LOG_LEVEL_LABELS
Inverse mapping of level values to log level text names.
Definition: log.cc:81
Every class exported by the ns3 library is enclosed in the ns3 namespace.
void LogComponentEnable(const std::string &name, LogLevel level)
Enable the logging output associated with that log component.
Definition: log.cc:305
static PrintList g_printList
Invoke handler for print-list in NS_LOG environment variable.
Definition: log.cc:139
void LogSetTimePrinter(TimePrinter printer)
Set the TimePrinter function to be used to prepend log messages with the simulation time.
Definition: log.cc:512
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
Definition: time-printer.h:43
void(* NodePrinter)(std::ostream &os)
Function signature for prepending the node id to a log message.
Definition: node-printer.h:40
std::vector< std::string > StringVector
Return type of SplitString.
Definition: string.h:37
NodePrinter LogGetNodePrinter()
Get the LogNodePrinter function currently in use.
Definition: log.cc:535
StringVector SplitString(const std::string &str, const std::string &delim)
Split a string on a delimiter.
Definition: string.cc:34
void LogComponentDisable(const std::string &name, LogLevel level)
Disable the logging output associated with that log component.
Definition: log.cc:341
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_NONE
No logging.
Definition: log.h:95
@ 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_ALL
Print everything.
Definition: log.h:115
@ 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()
Get the LogTimePrinter function currently in use.
Definition: log.cc:523
void LogComponentDisableAll(LogLevel level)
Disable all logging for all components.
Definition: log.cc:357
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition: log.cc:184
void LogComponentEnableAll(LogLevel level)
Enable the logging output for all registered log components.
Definition: log.cc:329
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition: log.cc:529
void LogComponentPrintList()
Print the list of logging messages available.
Definition: log.cc:369
value
Definition: second.py:41
ns3::StringValue attribute value declarations.