A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
log.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2006,2007 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8#include "log.h"
9
10#include "assert.h"
12#include "fatal-error.h"
13#include "string.h"
14
15#include "ns3/core-config.h"
16
17#include <algorithm> // transform
18#include <cstring> // strlen
19#include <iostream>
20#include <list>
21#include <locale> // toupper
22#include <map>
23#include <numeric> // accumulate
24#include <stdexcept>
25#include <utility>
26
27/**
28 * \file
29 * \ingroup logging
30 * ns3::LogComponent and related implementations.
31 */
32
33/**
34 * \ingroup logging
35 * Unnamed namespace for log.cc
36 */
37namespace
38{
39/** Mapping of log level text names to values. */
40const std::map<std::string, ns3::LogLevel> LOG_LABEL_LEVELS = {
41 // clang-format off
42 {"none", ns3::LOG_NONE},
43 {"error", ns3::LOG_ERROR},
44 {"level_error", ns3::LOG_LEVEL_ERROR},
45 {"warn", ns3::LOG_WARN},
46 {"level_warn", ns3::LOG_LEVEL_WARN},
47 {"debug", ns3::LOG_DEBUG},
48 {"level_debug", ns3::LOG_LEVEL_DEBUG},
49 {"info", ns3::LOG_INFO},
50 {"level_info", ns3::LOG_LEVEL_INFO},
51 {"function", ns3::LOG_FUNCTION},
52 {"level_function", ns3::LOG_LEVEL_FUNCTION},
53 {"logic", ns3::LOG_LOGIC},
54 {"level_logic", ns3::LOG_LEVEL_LOGIC},
55 {"all", ns3::LOG_ALL},
56 {"level_all", ns3::LOG_LEVEL_ALL},
57 {"func", ns3::LOG_PREFIX_FUNC},
58 {"prefix_func", ns3::LOG_PREFIX_FUNC},
59 {"time", ns3::LOG_PREFIX_TIME},
60 {"prefix_time", ns3::LOG_PREFIX_TIME},
61 {"node", ns3::LOG_PREFIX_NODE},
62 {"prefix_node", ns3::LOG_PREFIX_NODE},
63 {"level", ns3::LOG_PREFIX_LEVEL},
64 {"prefix_level", ns3::LOG_PREFIX_LEVEL},
65 {"prefix_all", ns3::LOG_PREFIX_ALL}
66 // clang-format on
67};
68
69/** Inverse mapping of level values to log level text names. */
70const std::map<ns3::LogLevel, std::string> LOG_LEVEL_LABELS = {[]() {
71 std::map<ns3::LogLevel, std::string> labels;
72 for (const auto& [label, lev] : LOG_LABEL_LEVELS)
73 {
74 // Only keep the first label for a level
75 if (labels.find(lev) == labels.end())
76 {
77 std::string pad{label};
78 // Add whitespace for alignment with "ERROR", "DEBUG" etc.
79 if (pad.size() < 5)
80 {
81 pad.insert(pad.size(), 5 - pad.size(), ' ');
82 }
83 std::transform(pad.begin(), pad.end(), pad.begin(), ::toupper);
84 labels[lev] = pad;
85 }
86 }
87 return labels;
88}()};
89
90} // Unnamed namespace
91
92namespace ns3
93{
94
95/**
96 * \ingroup logging
97 * The Log TimePrinter.
98 * This is private to the logging implementation.
99 */
101/**
102 * \ingroup logging
103 * The Log NodePrinter.
104 */
106
107/**
108 * \ingroup logging
109 * Handler for the undocumented \c print-list token in NS_LOG
110 * which triggers printing of the list of log components, then exits.
111 *
112 * A static instance of this class is instantiated below, so the
113 * \c print-list token is handled before any other logging action
114 * can take place.
115 *
116 * This is private to the logging implementation.
117 */
119{
120 public:
121 PrintList(); //<! Constructor, prints the list and exits.
122};
123
124/**
125 * Invoke handler for \c print-list in NS_LOG environment variable.
126 * This is private to the logging implementation.
127 */
129
130/* static */
133{
134 static LogComponent::ComponentList components;
135 return &components;
136}
137
139{
140 auto [found, value] = EnvironmentVariable::Get("NS_LOG", "print-list", ":");
141 if (found)
142 {
144 exit(0);
145 }
146}
147
148LogComponent::LogComponent(const std::string& name,
149 const std::string& file,
150 const LogLevel mask /* = 0 */)
151 : m_levels(0),
152 m_mask(mask),
153 m_name(name),
154 m_file(file)
155{
156 // Check if we're mentioned in NS_LOG, and set our flags appropriately
157 EnvVarCheck();
158
160
161 if (components->find(name) != components->end())
162 {
163 NS_FATAL_ERROR("Log component \"" << name << "\" has already been registered once.");
164 }
165
166 components->insert(std::make_pair(name, this));
167}
168
170GetLogComponent(const std::string name)
171{
173 LogComponent* ret;
174
175 try
176 {
177 ret = components->at(name);
178 }
179 catch (std::out_of_range&)
180 {
181 NS_FATAL_ERROR("Log component \"" << name << "\" does not exist.");
182 }
183 return *ret;
184}
185
186void
188{
189 auto [found, value] = EnvironmentVariable::Get("NS_LOG", m_name, ":");
190 if (!found)
191 {
192 std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "*", ":");
193 }
194 if (!found)
195 {
196 std::tie(found, value) = EnvironmentVariable::Get("NS_LOG", "***", ":");
197 }
198
199 if (!found)
200 {
201 return;
202 }
203
204 if (value.empty())
205 {
206 // Default is enable all levels, all prefixes
207 value = "**";
208 }
209
210 // Got a value, might have flags
211 int level = 0;
212 StringVector flags = SplitString(value, "|");
213 NS_ASSERT_MSG(!flags.empty(), "Unexpected empty flags from non-empty value");
214 bool pre_pipe{true};
215
216 for (const auto& lev : flags)
217 {
218 if (lev == "**")
219 {
220 level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
221 }
222 else if (lev == "all" || lev == "*")
223 {
224 level |= (pre_pipe ? LOG_LEVEL_ALL : LOG_PREFIX_ALL);
225 }
226 else if (LOG_LABEL_LEVELS.find(lev) != LOG_LABEL_LEVELS.end())
227 {
228 level |= LOG_LABEL_LEVELS.at(lev);
229 }
230 pre_pipe = false;
231 }
232 Enable((LogLevel)level);
233}
234
235bool
237{
238 // LogComponentEnableEnvVar ();
239 return level & m_levels;
240}
241
242bool
244{
245 return m_levels == 0;
246}
247
248void
250{
251 m_mask |= level;
252}
253
254void
256{
257 m_levels |= (level & ~m_mask);
258}
259
260void
262{
263 m_levels &= ~level;
264}
265
266std::string
268{
269 return m_name;
270}
271
272std::string
274{
275 return m_file;
276}
277
278/* static */
279std::string
281{
282 auto it = LOG_LEVEL_LABELS.find(level);
283 if (it != LOG_LEVEL_LABELS.end())
284 {
285 return it->second;
286 }
287 return "unknown";
288}
289
290void
291LogComponentEnable(const std::string& name, LogLevel level)
292{
294 auto logComponent = components->find(name);
295
296 if (logComponent == components->end())
297 {
298 NS_LOG_UNCOND("Logging component \"" << name << "\" not found.");
300 NS_FATAL_ERROR("Logging component \""
301 << name << "\" not found."
302 << " See above for a list of available log components");
303 }
304
305 logComponent->second->Enable(level);
306}
307
308void
310{
312 for (auto i = components->begin(); i != components->end(); i++)
313 {
314 i->second->Enable(level);
315 }
316}
317
318void
319LogComponentDisable(const std::string& name, LogLevel level)
320{
322 auto logComponent = components->find(name);
323
324 if (logComponent != components->end())
325 {
326 logComponent->second->Disable(level);
327 }
328}
329
330void
332{
334 for (auto i = components->begin(); i != components->end(); i++)
335 {
336 i->second->Disable(level);
337 }
338}
339
340void
342{
343 // Create sorted map of components by inserting them into a map
344 std::map<std::string, LogComponent*> componentsSorted;
345
346 for (const auto& component : *LogComponent::GetComponentList())
347 {
348 componentsSorted.insert(component);
349 }
350
351 // Iterate through sorted components
352 for (const auto& [name, component] : componentsSorted)
353 {
354 std::cout << name << "=";
355 if (component->IsNoneEnabled())
356 {
357 std::cout << "0" << std::endl;
358 continue;
359 }
360 if (component->IsEnabled(LOG_LEVEL_ALL))
361 {
362 std::cout << "all";
363 }
364 else
365 {
366 if (component->IsEnabled(LOG_ERROR))
367 {
368 std::cout << "error";
369 }
370 if (component->IsEnabled(LOG_WARN))
371 {
372 std::cout << "|warn";
373 }
374 if (component->IsEnabled(LOG_DEBUG))
375 {
376 std::cout << "|debug";
377 }
378 if (component->IsEnabled(LOG_INFO))
379 {
380 std::cout << "|info";
381 }
382 if (component->IsEnabled(LOG_FUNCTION))
383 {
384 std::cout << "|function";
385 }
386 if (component->IsEnabled(LOG_LOGIC))
387 {
388 std::cout << "|logic";
389 }
390 }
391 if (component->IsEnabled(LOG_PREFIX_ALL))
392 {
393 std::cout << "|prefix_all";
394 }
395 else
396 {
397 if (component->IsEnabled(LOG_PREFIX_FUNC))
398 {
399 std::cout << "|func";
400 }
401 if (component->IsEnabled(LOG_PREFIX_TIME))
402 {
403 std::cout << "|time";
404 }
405 if (component->IsEnabled(LOG_PREFIX_NODE))
406 {
407 std::cout << "|node";
408 }
409 if (component->IsEnabled(LOG_PREFIX_LEVEL))
410 {
411 std::cout << "|level";
412 }
413 }
414 std::cout << std::endl;
415 }
416}
417
418/**
419 * \ingroup logging
420 * Check if a log component exists.
421 * This is private to the logging implementation.
422 *
423 * \param [in] componentName The putative log component name.
424 * \returns \c true if \c componentName exists.
425 */
426static bool
427ComponentExists(std::string componentName)
428{
430
431 return components->find(componentName) != components->end();
432}
433
434/**
435 * \ingroup logging
436 * Parse the \c NS_LOG environment variable.
437 * This is private to the logging implementation.
438 */
439static void
441{
442 auto dict = EnvironmentVariable::GetDictionary("NS_LOG", ":")->GetStore();
443
444 for (auto& [component, value] : dict)
445 {
446 if (component != "*" && component != "***" && !ComponentExists(component))
447 {
448 NS_LOG_UNCOND("Invalid or unregistered component name \"" << component << "\"");
451 "Invalid or unregistered component name \""
452 << component
453 << "\" in env variable NS_LOG, see above for a list of valid components");
454 }
455
456 // We have a valid component or wildcard, check the flags
457 if (!value.empty())
458 {
459 // Check the flags present in value
460 StringVector flags = SplitString(value, "|");
461 for (const auto& flag : flags)
462 {
463 // Handle wild cards
464 if (flag == "*" || flag == "**")
465 {
466 continue;
467 }
468 bool ok = LOG_LABEL_LEVELS.find(flag) != LOG_LABEL_LEVELS.end();
469 if (!ok)
470 {
471 NS_FATAL_ERROR("Invalid log level \""
472 << flag << "\" in env variable NS_LOG for component name "
473 << component);
474 }
475 } // for flag
476 } // !value.empty
477 } // for component
478}
479
480void
482{
483 g_logTimePrinter = printer;
484 /**
485 * \internal
486 * This is the only place where we are more or less sure that all log variables
487 * are registered. See \bugid{1082} for details.
488 */
490}
491
494{
495 return g_logTimePrinter;
496}
497
498void
500{
501 g_logNodePrinter = printer;
502}
503
506{
507 return g_logNodePrinter;
508}
509
511 : m_os(os)
512{
513}
514
515void
517{
518 if (m_first)
519 {
520 m_first = false;
521 }
522 else
523 {
524 m_os << ", ";
525 }
526}
527
528} // 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:317
static ComponentList * GetComponentList()
Get the list of LogComponents.
Definition log.cc:132
void Enable(const LogLevel level)
Enable this LogComponent at level.
Definition log.cc:255
bool IsEnabled(const LogLevel level) const
Check if this LogComponent is enabled for level.
Definition log.cc:236
std::string File() const
Get the compilation unit defining this LogComponent.
Definition log.cc:273
int32_t m_levels
Enabled LogLevels.
Definition log.h:408
void Disable(const LogLevel level)
Disable logging at level for this LogComponent.
Definition log.cc:261
static std::string GetLevelLabel(const LogLevel level)
Get the string label for the given LogLevel.
Definition log.cc:280
void EnvVarCheck()
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition log.cc:187
std::string m_file
File defining this LogComponent.
Definition log.h:411
bool IsNoneEnabled() const
Check if all levels are disabled.
Definition log.cc:243
std::string Name() const
Get the name of this LogComponent.
Definition log.cc:267
std::unordered_map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition log.h:387
int32_t m_mask
Blocked LogLevels.
Definition log.h:409
LogComponent(const std::string &name, const std::string &file, const LogLevel mask=LOG_NONE)
Constructor.
Definition log.cc:148
void SetMask(const LogLevel level)
Prevent the enabling of a specific LogLevel.
Definition log.cc:249
std::string m_name
LogComponent name.
Definition log.h:410
void CommaRest()
Add , before every parameter after the first.
Definition log.cc:516
bool m_first
First argument flag, doesn't get ,.
Definition log.h:459
ParameterLogger(std::ostream &os)
Constructor.
Definition log.cc:510
std::ostream & m_os
Underlying output stream.
Definition log.h:460
Handler for the undocumented print-list token in NS_LOG which triggers printing of the list of log co...
Definition log.cc:119
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:75
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_UNCOND(msg)
Output the requested message unconditionally.
static NodePrinter g_logNodePrinter
The Log NodePrinter.
Definition log.cc:105
static void CheckEnvironmentVariables()
Parse the NS_LOG environment variable.
Definition log.cc:440
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition log.cc:427
static TimePrinter g_logTimePrinter
The Log TimePrinter.
Definition log.cc:100
Debug message logging.
const std::map< std::string, ns3::LogLevel > LOG_LABEL_LEVELS
Mapping of log level text names to values.
Definition log.cc:40
const std::map< ns3::LogLevel, std::string > LOG_LEVEL_LABELS
Inverse mapping of level values to log level text names.
Definition log.cc:70
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:291
static PrintList g_printList
Invoke handler for print-list in NS_LOG environment variable.
Definition log.cc:128
void LogSetTimePrinter(TimePrinter printer)
Set the TimePrinter function to be used to prepend log messages with the simulation time.
Definition log.cc:481
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
void(* NodePrinter)(std::ostream &os)
Function signature for prepending the node id to a log message.
NodePrinter LogGetNodePrinter()
Get the LogNodePrinter function currently in use.
Definition log.cc:505
StringVector SplitString(const std::string &str, const std::string &delim)
Split a string on a delimiter.
Definition string.cc:23
void LogComponentDisable(const std::string &name, LogLevel level)
Disable the logging output associated with that log component.
Definition log.cc:319
LogLevel
Logging severity classes and levels.
Definition log.h:83
@ LOG_LEVEL_ALL
Print everything.
Definition log.h:105
@ LOG_PREFIX_FUNC
Prefix all trace prints with function.
Definition log.h:107
@ LOG_LEVEL_LOGIC
LOG_LOGIC and above.
Definition log.h:99
@ LOG_NONE
No logging.
Definition log.h:84
@ LOG_PREFIX_TIME
Prefix all trace prints with simulation time.
Definition log.h:108
@ LOG_FUNCTION
Function tracing for non-trivial function calls.
Definition log.h:95
@ LOG_ERROR
Serious error messages only.
Definition log.h:86
@ LOG_WARN
Warning messages.
Definition log.h:89
@ LOG_INFO
Something happened to change state.
Definition log.h:92
@ LOG_PREFIX_ALL
All prefixes.
Definition log.h:111
@ LOG_LEVEL_FUNCTION
LOG_FUNCTION and above.
Definition log.h:96
@ LOG_LEVEL_ERROR
LOG_ERROR and above.
Definition log.h:87
@ LOG_ALL
Print everything.
Definition log.h:104
@ LOG_LEVEL_WARN
LOG_WARN and above.
Definition log.h:90
@ LOG_LEVEL_DEBUG
LOG_DEBUG and above.
Definition log.h:102
@ LOG_PREFIX_LEVEL
Prefix all trace prints with log level (severity).
Definition log.h:110
@ LOG_LOGIC
Debugging logs for key branches and decisions in a function.
Definition log.h:98
@ LOG_PREFIX_NODE
Prefix all trace prints with simulation node.
Definition log.h:109
@ LOG_LEVEL_INFO
LOG_INFO and above.
Definition log.h:93
@ LOG_DEBUG
Full voluminous logging to support debugging.
Definition log.h:101
TimePrinter LogGetTimePrinter()
Get the LogTimePrinter function currently in use.
Definition log.cc:493
void LogComponentDisableAll(LogLevel level)
Disable all logging for all components.
Definition log.cc:331
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition log.cc:170
void LogComponentEnableAll(LogLevel level)
Enable the logging output for all registered log components.
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:499
void LogComponentPrintList()
Print the list of logging messages available.
Definition log.cc:341
std::vector< std::string > StringVector
Return type of SplitString.
Definition string.h:26
ns3::StringValue attribute value declarations.