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 
172  if (components->find(name) != components->end())
173  {
174  NS_FATAL_ERROR("Log component \"" << name << "\" has already been registered once.");
175  }
176 
177  components->insert(std::make_pair(name, this));
178 }
179 
181 GetLogComponent(const std::string name)
182 {
184  LogComponent* ret;
185 
186  try
187  {
188  ret = components->at(name);
189  }
190  catch (std::out_of_range&)
191  {
192  NS_FATAL_ERROR("Log component \"" << name << "\" does not exist.");
193  }
194  return *ret;
195 }
196 
197 void
199 {
200  auto [found, value] = EnvironmentVariable::Get("NS_LOG", m_name, ":");
201  if (!found)
202  {
203  std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "*", ":");
204  }
205  if (!found)
206  {
207  std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "***", ":");
208  }
209 
210  if (!found)
211  {
212  return;
213  }
214 
215  if (value.empty())
216  {
217  // Default is enable all levels, all prefixes
218  value = "**";
219  }
220 
221  // Got a value, might have flags
222  int level = 0;
223  StringVector flags = SplitString(value, "|");
224  NS_ASSERT_MSG(!flags.empty(), "Unexpected empty flags from non-empty value");
225  bool pre_pipe{true};
226 
227  for (const auto& lev : flags)
228  {
229  if (lev == "**")
230  {
231  level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
232  }
233  else if (lev == "all" || lev == "*")
234  {
235  level |= (pre_pipe ? LOG_LEVEL_ALL : LOG_PREFIX_ALL);
236  }
237  else if (LOG_LABEL_LEVELS.find(lev) != LOG_LABEL_LEVELS.end())
238  {
239  level |= LOG_LABEL_LEVELS.at(lev);
240  }
241  pre_pipe = false;
242  }
243  Enable((LogLevel)level);
244 }
245 
246 bool
248 {
249  // LogComponentEnableEnvVar ();
250  return level & m_levels;
251 }
252 
253 bool
255 {
256  return m_levels == 0;
257 }
258 
259 void
261 {
262  m_mask |= level;
263 }
264 
265 void
267 {
268  m_levels |= (level & ~m_mask);
269 }
270 
271 void
273 {
274  m_levels &= ~level;
275 }
276 
277 std::string
279 {
280  return m_name;
281 }
282 
283 std::string
285 {
286  return m_file;
287 }
288 
289 /* static */
290 std::string
292 {
293  auto it = LOG_LEVEL_LABELS.find(level);
294  if (it != LOG_LEVEL_LABELS.end())
295  {
296  return it->second;
297  }
298  return "unknown";
299 }
300 
301 void
302 LogComponentEnable(const std::string& name, LogLevel level)
303 {
305  auto logComponent = components->find(name);
306 
307  if (logComponent == components->end())
308  {
309  NS_LOG_UNCOND("Logging component \"" << name << "\" not found.");
311  NS_FATAL_ERROR("Logging component \""
312  << name << "\" not found."
313  << " See above for a list of available log components");
314  }
315 
316  logComponent->second->Enable(level);
317 }
318 
319 void
321 {
323  for (auto i = components->begin(); i != components->end(); i++)
324  {
325  i->second->Enable(level);
326  }
327 }
328 
329 void
330 LogComponentDisable(const std::string& name, LogLevel level)
331 {
333  auto logComponent = components->find(name);
334 
335  if (logComponent != components->end())
336  {
337  logComponent->second->Disable(level);
338  }
339 }
340 
341 void
343 {
345  for (auto i = components->begin(); i != components->end(); i++)
346  {
347  i->second->Disable(level);
348  }
349 }
350 
351 void
353 {
354  // Create sorted map of components by inserting them into a map
355  std::map<std::string, LogComponent*> componentsSorted;
356 
357  for (const auto& component : *LogComponent::GetComponentList())
358  {
359  componentsSorted.insert(component);
360  }
361 
362  // Iterate through sorted components
363  for (const auto& [name, component] : componentsSorted)
364  {
365  std::cout << name << "=";
366  if (component->IsNoneEnabled())
367  {
368  std::cout << "0" << std::endl;
369  continue;
370  }
371  if (component->IsEnabled(LOG_LEVEL_ALL))
372  {
373  std::cout << "all";
374  }
375  else
376  {
377  if (component->IsEnabled(LOG_ERROR))
378  {
379  std::cout << "error";
380  }
381  if (component->IsEnabled(LOG_WARN))
382  {
383  std::cout << "|warn";
384  }
385  if (component->IsEnabled(LOG_DEBUG))
386  {
387  std::cout << "|debug";
388  }
389  if (component->IsEnabled(LOG_INFO))
390  {
391  std::cout << "|info";
392  }
393  if (component->IsEnabled(LOG_FUNCTION))
394  {
395  std::cout << "|function";
396  }
397  if (component->IsEnabled(LOG_LOGIC))
398  {
399  std::cout << "|logic";
400  }
401  }
402  if (component->IsEnabled(LOG_PREFIX_ALL))
403  {
404  std::cout << "|prefix_all";
405  }
406  else
407  {
408  if (component->IsEnabled(LOG_PREFIX_FUNC))
409  {
410  std::cout << "|func";
411  }
412  if (component->IsEnabled(LOG_PREFIX_TIME))
413  {
414  std::cout << "|time";
415  }
416  if (component->IsEnabled(LOG_PREFIX_NODE))
417  {
418  std::cout << "|node";
419  }
420  if (component->IsEnabled(LOG_PREFIX_LEVEL))
421  {
422  std::cout << "|level";
423  }
424  }
425  std::cout << std::endl;
426  }
427 }
428 
437 static bool
438 ComponentExists(std::string componentName)
439 {
441 
442  return components->find(componentName) != components->end();
443 }
444 
450 static void
452 {
453  auto dict = EnvironmentVariable::GetDictionary("NS_LOG", ":")->GetStore();
454 
455  for (auto& [component, value] : dict)
456  {
457  if (component != "*" && component != "***" && !ComponentExists(component))
458  {
459  NS_LOG_UNCOND("Invalid or unregistered component name \"" << component << "\"");
462  "Invalid or unregistered component name \""
463  << component
464  << "\" in env variable NS_LOG, see above for a list of valid components");
465  }
466 
467  // We have a valid component or wildcard, check the flags
468  if (!value.empty())
469  {
470  // Check the flags present in value
471  StringVector flags = SplitString(value, "|");
472  for (const auto& flag : flags)
473  {
474  // Handle wild cards
475  if (flag == "*" || flag == "**")
476  {
477  continue;
478  }
479  bool ok = LOG_LABEL_LEVELS.find(flag) != LOG_LABEL_LEVELS.end();
480  if (!ok)
481  {
482  NS_FATAL_ERROR("Invalid log level \""
483  << flag << "\" in env variable NS_LOG for component name "
484  << component);
485  }
486  } // for flag
487  } // !value.empty
488  } // for component
489 }
490 
491 void
493 {
494  g_logTimePrinter = printer;
500 }
501 
504 {
505  return g_logTimePrinter;
506 }
507 
508 void
510 {
511  g_logNodePrinter = printer;
512 }
513 
516 {
517  return g_logNodePrinter;
518 }
519 
521  : m_os(os)
522 {
523 }
524 
525 void
527 {
528  if (m_first)
529  {
530  m_first = false;
531  }
532  else
533  {
534  m_os << ", ";
535  }
536 }
537 
538 } // 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:266
bool IsEnabled(const LogLevel level) const
Check if this LogComponent is enabled for level.
Definition: log.cc:247
std::string File() const
Get the compilation unit defining this LogComponent.
Definition: log.cc:284
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:272
static std::string GetLevelLabel(const LogLevel level)
Get the string label for the given LogLevel.
Definition: log.cc:291
void EnvVarCheck()
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition: log.cc:198
std::string m_file
File defining this LogComponent.
Definition: log.h:422
bool IsNoneEnabled() const
Check if all levels are disabled.
Definition: log.cc:254
std::string Name() const
Get the name of this LogComponent.
Definition: log.cc:278
std::unordered_map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition: log.h:398
int32_t m_mask
Blocked LogLevels.
Definition: log.h:420
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:260
std::string m_name
LogComponent name.
Definition: log.h:421
void CommaRest()
Add , before every parameter after the first.
Definition: log.cc:526
bool m_first
First argument flag, doesn't get ,.
Definition: log.h:470
ParameterLogger(std::ostream &os)
Constructor.
Definition: log.cc:520
std::ostream & m_os
Underlying output stream.
Definition: log.h:471
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_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:451
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition: log.cc:438
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:302
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:492
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:515
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:330
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:110
@ 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 for non-trivial function calls.
Definition: log.h:106
@ LOG_ERROR
Serious error messages only.
Definition: log.h:97
@ LOG_WARN
Warning messages.
Definition: log.h:100
@ LOG_INFO
Something happened to change state.
Definition: log.h:103
@ LOG_PREFIX_ALL
All prefixes.
Definition: log.h:122
@ LOG_LEVEL_FUNCTION
LOG_FUNCTION and above.
Definition: log.h:107
@ 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:113
@ LOG_PREFIX_LEVEL
Prefix all trace prints with log level (severity).
Definition: log.h:121
@ LOG_LOGIC
Debugging logs for key branches and decisions in a function.
Definition: log.h:109
@ LOG_PREFIX_NODE
Prefix all trace prints with simulation node.
Definition: log.h:120
@ LOG_LEVEL_INFO
LOG_INFO and above.
Definition: log.h:104
@ LOG_DEBUG
Full voluminous logging to support debugging.
Definition: log.h:112
TimePrinter LogGetTimePrinter()
Get the LogTimePrinter function currently in use.
Definition: log.cc:503
void LogComponentDisableAll(LogLevel level)
Disable all logging for all components.
Definition: log.cc:342
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition: log.cc:181
void LogComponentEnableAll(LogLevel level)
Enable the logging output for all registered log components.
Definition: log.cc:320
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition: log.cc:509
void LogComponentPrintList()
Print the list of logging messages available.
Definition: log.cc:352
ns3::StringValue attribute value declarations.