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