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 return m_levels == 0;
239}
240
241void
243{
244 m_mask |= level;
245}
246
247void
249{
250 m_levels |= (level & ~m_mask);
251}
252
253void
255{
256 m_levels &= ~level;
257}
258
259std::string
261{
262 return m_name;
263}
264
265std::string
267{
268 return m_file;
269}
270
271/* static */
272std::string
274{
275 auto it = LOG_LEVEL_LABELS.find(level);
276 if (it != LOG_LEVEL_LABELS.end())
277 {
278 return it->second;
279 }
280 return "unknown";
281}
282
283void
284LogComponentEnable(const std::string& name, LogLevel level)
285{
287 auto logComponent = components->find(name);
288
289 if (logComponent == components->end())
290 {
291 NS_LOG_UNCOND("Logging component \"" << name << "\" not found.");
293 NS_FATAL_ERROR("Logging component \""
294 << name << "\" not found."
295 << " See above for a list of available log components");
296 }
297
298 logComponent->second->Enable(level);
299}
300
301void
303{
305 for (auto i = components->begin(); i != components->end(); i++)
306 {
307 i->second->Enable(level);
308 }
309}
310
311void
312LogComponentDisable(const std::string& name, LogLevel level)
313{
315 auto logComponent = components->find(name);
316
317 if (logComponent != components->end())
318 {
319 logComponent->second->Disable(level);
320 }
321}
322
323void
325{
327 for (auto i = components->begin(); i != components->end(); i++)
328 {
329 i->second->Disable(level);
330 }
331}
332
333void
335{
336 // Create sorted map of components by inserting them into a map
337 std::map<std::string, LogComponent*> componentsSorted;
338
339 for (const auto& component : *LogComponent::GetComponentList())
340 {
341 componentsSorted.insert(component);
342 }
343
344 // Iterate through sorted components
345 for (const auto& [name, component] : componentsSorted)
346 {
347 std::cout << name << "=";
348 if (component->IsNoneEnabled())
349 {
350 std::cout << "0" << std::endl;
351 continue;
352 }
353 if (component->IsEnabled(LOG_LEVEL_ALL))
354 {
355 std::cout << "all";
356 }
357 else
358 {
359 if (component->IsEnabled(LOG_ERROR))
360 {
361 std::cout << "error";
362 }
363 if (component->IsEnabled(LOG_WARN))
364 {
365 std::cout << "|warn";
366 }
367 if (component->IsEnabled(LOG_DEBUG))
368 {
369 std::cout << "|debug";
370 }
371 if (component->IsEnabled(LOG_INFO))
372 {
373 std::cout << "|info";
374 }
375 if (component->IsEnabled(LOG_FUNCTION))
376 {
377 std::cout << "|function";
378 }
379 if (component->IsEnabled(LOG_LOGIC))
380 {
381 std::cout << "|logic";
382 }
383 }
384 if (component->IsEnabled(LOG_PREFIX_ALL))
385 {
386 std::cout << "|prefix_all";
387 }
388 else
389 {
390 if (component->IsEnabled(LOG_PREFIX_FUNC))
391 {
392 std::cout << "|func";
393 }
394 if (component->IsEnabled(LOG_PREFIX_TIME))
395 {
396 std::cout << "|time";
397 }
398 if (component->IsEnabled(LOG_PREFIX_NODE))
399 {
400 std::cout << "|node";
401 }
402 if (component->IsEnabled(LOG_PREFIX_LEVEL))
403 {
404 std::cout << "|level";
405 }
406 }
407 std::cout << std::endl;
408 }
409}
410
411/**
412 * @ingroup logging
413 * Check if a log component exists.
414 * This is private to the logging implementation.
415 *
416 * @param [in] componentName The putative log component name.
417 * @returns \c true if \c componentName exists.
418 */
419static bool
420ComponentExists(std::string componentName)
421{
423
424 return components->find(componentName) != components->end();
425}
426
427/**
428 * @ingroup logging
429 * Parse the \c NS_LOG environment variable.
430 * This is private to the logging implementation.
431 */
432static void
434{
435 auto dict = EnvironmentVariable::GetDictionary("NS_LOG", ":")->GetStore();
436
437 for (auto& [component, value] : dict)
438 {
439 if (component != "*" && component != "***" && !ComponentExists(component))
440 {
441 NS_LOG_UNCOND("Invalid or unregistered component name \"" << component << "\"");
444 "Invalid or unregistered component name \""
445 << component
446 << "\" in env variable NS_LOG, see above for a list of valid components");
447 }
448
449 // No valid component or wildcard
450 if (value.empty())
451 {
452 continue;
453 }
454
455 // We have a valid component or wildcard, check the flags present in value
456 StringVector flags = SplitString(value, "|");
457 for (const auto& flag : flags)
458 {
459 // Handle wild cards
460 if (flag == "*" || flag == "**")
461 {
462 continue;
463 }
464 bool ok = LOG_LABEL_LEVELS.find(flag) != LOG_LABEL_LEVELS.end();
465 if (!ok)
466 {
467 NS_FATAL_ERROR("Invalid log level \""
468 << flag << "\" in env variable NS_LOG for component name "
469 << component);
470 }
471 }
472 }
473}
474
475void
477{
478 g_logTimePrinter = printer;
479 /**
480 * @internal
481 * This is the only place where we are more or less sure that all log variables
482 * are registered. See \bugid{1082} for details.
483 */
485}
486
489{
490 return g_logTimePrinter;
491}
492
493void
495{
496 g_logNodePrinter = printer;
497}
498
501{
502 return g_logNodePrinter;
503}
504
506 : m_os(os)
507{
508}
509
510void
512{
513 if (m_first)
514 {
515 m_first = false;
516 }
517 else
518 {
519 m_os << ", ";
520 }
521}
522
523} // 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:248
std::string File() const
Get the compilation unit defining this LogComponent.
Definition log.cc:266
int32_t m_levels
Enabled LogLevels.
Definition log.h:417
void Disable(const LogLevel level)
Disable logging at level for this LogComponent.
Definition log.cc:254
static std::string GetLevelLabel(const LogLevel level)
Get the string label for the given LogLevel.
Definition log.cc:273
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:420
bool IsNoneEnabled() const
Check if all levels are disabled.
Definition log.cc:236
std::string Name() const
Get the name of this LogComponent.
Definition log.cc:260
std::unordered_map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition log.h:396
int32_t m_mask
Blocked LogLevels.
Definition log.h:418
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:242
std::string m_name
LogComponent name.
Definition log.h:419
void CommaRest()
Add , before every parameter after the first.
Definition log.cc:511
bool m_first
First argument flag, doesn't get ,.
Definition log.h:469
ParameterLogger(std::ostream &os)
Constructor.
Definition log.cc:505
std::ostream & m_os
Underlying output stream.
Definition log.h:470
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:433
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition log.cc:420
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:284
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:476
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:500
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:312
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:488
void LogComponentDisableAll(LogLevel level)
Disable all logging for all components.
Definition log.cc:324
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:302
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition log.cc:494
void LogComponentPrintList()
Print the list of logging messages available.
Definition log.cc:334
std::vector< std::string > StringVector
Return type of SplitString.
Definition string.h:26
ns3::StringValue attribute value declarations.