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 "fatal-error.h"
23
24#include "ns3/core-config.h"
25
26#include <cstdlib> // getenv
27#include <cstring> // strlen
28#include <iostream>
29#include <list>
30#include <stdexcept>
31#include <utility>
32
39namespace ns3
40{
41
53
61{
62 public:
63 PrintList(); //<! Constructor, prints the list and exits.
64};
65
71
72/* static */
75{
76 static LogComponent::ComponentList components;
77 return &components;
78}
79
81{
82 const char* envVar = std::getenv("NS_LOG");
83 if (envVar == nullptr || std::strlen(envVar) == 0)
84 {
85 return;
86 }
87 std::string env = envVar;
88 std::string::size_type cur = 0;
89 std::string::size_type next = 0;
90 while (next != std::string::npos)
91 {
92 next = env.find_first_of(':', cur);
93 std::string tmp = std::string(env, cur, next - cur);
94 if (tmp == "print-list")
95 {
97 exit(0);
98 break;
99 }
100 cur = next + 1;
101 }
102}
103
104LogComponent::LogComponent(const std::string& name,
105 const std::string& file,
106 const enum LogLevel mask /* = 0 */)
107 : m_levels(0),
108 m_mask(mask),
109 m_name(name),
110 m_file(file)
111{
112 EnvVarCheck();
113
115 for (LogComponent::ComponentList::const_iterator i = components->begin();
116 i != components->end();
117 i++)
118 {
119 if (i->first == name)
120 {
121 NS_FATAL_ERROR("Log component \"" << name << "\" has already been registered once.");
122 }
123 }
124 components->insert(std::make_pair(name, this));
125}
126
128GetLogComponent(const std::string name)
129{
131 LogComponent* ret;
132
133 try
134 {
135 ret = components->at(name);
136 }
137 catch (std::out_of_range&)
138 {
139 NS_FATAL_ERROR("Log component \"" << name << "\" does not exist.");
140 }
141 return *ret;
142}
143
144void
146{
147 const char* envVar = std::getenv("NS_LOG");
148 if (envVar == nullptr || std::strlen(envVar) == 0)
149 {
150 return;
151 }
152 std::string env = envVar;
153
154 std::string::size_type cur = 0;
155 std::string::size_type next = 0;
156 while (next != std::string::npos)
157 {
158 next = env.find_first_of(':', cur);
159 std::string tmp = std::string(env, cur, next - cur);
160 std::string::size_type equal = tmp.find('=');
161 std::string component;
162 if (equal == std::string::npos)
163 {
164 component = tmp;
165 if (component == m_name || component == "*" || component == "***")
166 {
167 int level = LOG_LEVEL_ALL | LOG_PREFIX_ALL;
168 Enable((enum LogLevel)level);
169 return;
170 }
171 }
172 else
173 {
174 component = tmp.substr(0, equal);
175 if (component == m_name || component == "*")
176 {
177 int level = 0;
178 std::string::size_type cur_lev;
179 std::string::size_type next_lev = equal;
180 bool pre_pipe = true; // before the first '|', enables positional 'all', '*'
181 do
182 {
183 cur_lev = next_lev + 1;
184 next_lev = tmp.find('|', cur_lev);
185 std::string lev = tmp.substr(cur_lev, next_lev - cur_lev);
186 if (lev == "error")
187 {
188 level |= LOG_ERROR;
189 }
190 else if (lev == "warn")
191 {
192 level |= LOG_WARN;
193 }
194 else if (lev == "debug")
195 {
196 level |= LOG_DEBUG;
197 }
198 else if (lev == "info")
199 {
200 level |= LOG_INFO;
201 }
202 else if (lev == "function")
203 {
204 level |= LOG_FUNCTION;
205 }
206 else if (lev == "logic")
207 {
208 level |= LOG_LOGIC;
209 }
210 else if (pre_pipe && ((lev == "all") || (lev == "*")))
211 {
212 level |= LOG_LEVEL_ALL;
213 }
214 else if ((lev == "prefix_func") || (lev == "func"))
215 {
216 level |= LOG_PREFIX_FUNC;
217 }
218 else if ((lev == "prefix_time") || (lev == "time"))
219 {
220 level |= LOG_PREFIX_TIME;
221 }
222 else if ((lev == "prefix_node") || (lev == "node"))
223 {
224 level |= LOG_PREFIX_NODE;
225 }
226 else if ((lev == "prefix_level") || (lev == "level"))
227 {
228 level |= LOG_PREFIX_LEVEL;
229 }
230 else if ((lev == "prefix_all") ||
231 (!pre_pipe && ((lev == "all") || (lev == "*"))))
232 {
233 level |= LOG_PREFIX_ALL;
234 }
235 else if (lev == "level_error")
236 {
237 level |= LOG_LEVEL_ERROR;
238 }
239 else if (lev == "level_warn")
240 {
241 level |= LOG_LEVEL_WARN;
242 }
243 else if (lev == "level_debug")
244 {
245 level |= LOG_LEVEL_DEBUG;
246 }
247 else if (lev == "level_info")
248 {
249 level |= LOG_LEVEL_INFO;
250 }
251 else if (lev == "level_function")
252 {
253 level |= LOG_LEVEL_FUNCTION;
254 }
255 else if (lev == "level_logic")
256 {
257 level |= LOG_LEVEL_LOGIC;
258 }
259 else if (lev == "level_all")
260 {
261 level |= LOG_LEVEL_ALL;
262 }
263 else if (lev == "**")
264 {
265 level |= LOG_LEVEL_ALL | LOG_PREFIX_ALL;
266 }
267
268 pre_pipe = false;
269 } while (next_lev != std::string::npos);
270
271 Enable((enum LogLevel)level);
272 }
273 }
274 cur = next + 1;
275 }
276}
277
278bool
279LogComponent::IsEnabled(const enum LogLevel level) const
280{
281 // LogComponentEnableEnvVar ();
282 return (level & m_levels) ? 1 : 0;
283}
284
285bool
287{
288 return m_levels == 0;
289}
290
291void
293{
294 m_mask |= level;
295}
296
297void
299{
300 m_levels |= (level & ~m_mask);
301}
302
303void
305{
306 m_levels &= ~level;
307}
308
309const char*
311{
312 return m_name.c_str();
313}
314
315std::string
317{
318 return m_file;
319}
320
321/* static */
322std::string
324{
325 if (level == LOG_ERROR)
326 {
327 return "ERROR";
328 }
329 else if (level == LOG_WARN)
330 {
331 // whitespace left at the end for alignment
332 return "WARN ";
333 }
334 else if (level == LOG_DEBUG)
335 {
336 return "DEBUG";
337 }
338 else if (level == LOG_INFO)
339 {
340 // whitespace left at the end for alignment
341 return "INFO ";
342 }
343 else if (level == LOG_FUNCTION)
344 {
345 return "FUNCT";
346 }
347 else if (level == LOG_LOGIC)
348 {
349 return "LOGIC";
350 }
351 else
352 {
353 return "unknown";
354 }
355}
356
357void
358LogComponentEnable(const char* name, enum LogLevel level)
359{
361 LogComponent::ComponentList::const_iterator i;
362 for (i = components->begin(); i != components->end(); i++)
363 {
364 if (i->first == name)
365 {
366 i->second->Enable(level);
367 return;
368 }
369 }
370 if (i == components->end())
371 {
372 // nothing matched
374 NS_FATAL_ERROR("Logging component \""
375 << name << "\" not found. See above for a list of available log components");
376 }
377}
378
379void
381{
383 for (LogComponent::ComponentList::const_iterator i = components->begin();
384 i != components->end();
385 i++)
386 {
387 i->second->Enable(level);
388 }
389}
390
391void
392LogComponentDisable(const char* name, enum LogLevel level)
393{
395 for (LogComponent::ComponentList::const_iterator i = components->begin();
396 i != components->end();
397 i++)
398 {
399 if (i->first == name)
400 {
401 i->second->Disable(level);
402 break;
403 }
404 }
405}
406
407void
409{
411 for (LogComponent::ComponentList::const_iterator i = components->begin();
412 i != components->end();
413 i++)
414 {
415 i->second->Disable(level);
416 }
417}
418
419void
421{
423 for (LogComponent::ComponentList::const_iterator i = components->begin();
424 i != components->end();
425 i++)
426 {
427 std::cout << i->first << "=";
428 if (i->second->IsNoneEnabled())
429 {
430 std::cout << "0" << std::endl;
431 continue;
432 }
433 if (i->second->IsEnabled(LOG_LEVEL_ALL))
434 {
435 std::cout << "all";
436 }
437 else
438 {
439 if (i->second->IsEnabled(LOG_ERROR))
440 {
441 std::cout << "error";
442 }
443 if (i->second->IsEnabled(LOG_WARN))
444 {
445 std::cout << "|warn";
446 }
447 if (i->second->IsEnabled(LOG_DEBUG))
448 {
449 std::cout << "|debug";
450 }
451 if (i->second->IsEnabled(LOG_INFO))
452 {
453 std::cout << "|info";
454 }
455 if (i->second->IsEnabled(LOG_FUNCTION))
456 {
457 std::cout << "|function";
458 }
459 if (i->second->IsEnabled(LOG_LOGIC))
460 {
461 std::cout << "|logic";
462 }
463 }
464 if (i->second->IsEnabled(LOG_PREFIX_ALL))
465 {
466 std::cout << "|prefix_all";
467 }
468 else
469 {
470 if (i->second->IsEnabled(LOG_PREFIX_FUNC))
471 {
472 std::cout << "|func";
473 }
474 if (i->second->IsEnabled(LOG_PREFIX_TIME))
475 {
476 std::cout << "|time";
477 }
478 if (i->second->IsEnabled(LOG_PREFIX_NODE))
479 {
480 std::cout << "|node";
481 }
482 if (i->second->IsEnabled(LOG_PREFIX_LEVEL))
483 {
484 std::cout << "|level";
485 }
486 }
487 std::cout << std::endl;
488 }
489}
490
499static bool
500ComponentExists(std::string componentName)
501{
502 const char* name = componentName.c_str();
504 LogComponent::ComponentList::const_iterator i;
505 for (i = components->begin(); i != components->end(); i++)
506 {
507 if (i->first == name)
508 {
509 return true;
510 }
511 }
512 NS_ASSERT(i == components->end());
513 // nothing matched
514 return false;
515}
516
522static void
524{
525 const char* envVar = std::getenv("NS_LOG");
526 if (envVar == nullptr || std::strlen(envVar) == 0)
527 {
528 return;
529 }
530
531 std::string env = envVar;
532 std::string::size_type cur = 0;
533 std::string::size_type next = 0;
534
535 while (next != std::string::npos)
536 {
537 next = env.find_first_of(':', cur);
538 std::string tmp = std::string(env, cur, next - cur);
539 std::string::size_type equal = tmp.find('=');
540 std::string component;
541 if (equal == std::string::npos)
542 {
543 // ie no '=' characters found
544 component = tmp;
545 if (ComponentExists(component) || component == "*" || component == "***")
546 {
547 return;
548 }
549 else
550 {
553 "Invalid or unregistered component name \""
554 << component
555 << "\" in env variable NS_LOG, see above for a list of valid components");
556 }
557 }
558 else
559 {
560 component = tmp.substr(0, equal);
561 if (ComponentExists(component) || component == "*")
562 {
563 std::string::size_type cur_lev;
564 std::string::size_type next_lev = equal;
565 do
566 {
567 cur_lev = next_lev + 1;
568 next_lev = tmp.find('|', cur_lev);
569 std::string lev = tmp.substr(cur_lev, next_lev - cur_lev);
570 if (lev == "error" || lev == "warn" || lev == "debug" || lev == "info" ||
571 lev == "function" || lev == "logic" || lev == "all" ||
572 lev == "prefix_func" || lev == "func" || lev == "prefix_time" ||
573 lev == "time" || lev == "prefix_node" || lev == "node" ||
574 lev == "prefix_level" || lev == "level" || lev == "prefix_all" ||
575 lev == "level_error" || lev == "level_warn" || lev == "level_debug" ||
576 lev == "level_info" || lev == "level_function" || lev == "level_logic" ||
577 lev == "level_all" || lev == "*" || lev == "**")
578 {
579 continue;
580 }
581 else
582 {
583 NS_FATAL_ERROR("Invalid log level \""
584 << lev << "\" in env variable NS_LOG for component name "
585 << component);
586 }
587 } while (next_lev != std::string::npos);
588 }
589 else
590 {
593 "Invalid or unregistered component name \""
594 << component
595 << "\" in env variable NS_LOG, see above for a list of valid components");
596 }
597 }
598 cur = next + 1; // parse next component
599 }
600}
601
602void
604{
605 g_logTimePrinter = printer;
611}
612
615{
616 return g_logTimePrinter;
617}
618
619void
621{
622 g_logNodePrinter = printer;
623}
624
627{
628 return g_logNodePrinter;
629}
630
632 : m_os(os)
633{
634}
635
636void
638{
639 if (m_first)
640 {
641 m_first = false;
642 }
643 else
644 {
645 m_os << ", ";
646 }
647}
648
649template <>
651ParameterLogger::operator<< <std::string>(const std::string& param)
652{
653 CommaRest();
654 m_os << "\"" << param << "\"";
655 return *this;
656}
657
659ParameterLogger::operator<<(const char* param)
660{
661 (*this) << std::string(param);
662 return *this;
663}
664
665template <>
667ParameterLogger::operator<< <int8_t>(const int8_t param)
668{
669 (*this) << static_cast<int16_t>(param);
670 return *this;
671}
672
673template <>
674ParameterLogger&
675ParameterLogger::operator<< <uint8_t>(const uint8_t param)
676{
677 (*this) << static_cast<uint16_t>(param);
678 return *this;
679}
680
681} // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
A single log component configuration.
Definition: log.h:328
const char * Name() const
Get the name of this LogComponent.
Definition: log.cc:310
static ComponentList * GetComponentList()
Get the list of LogComponnents.
Definition: log.cc:74
void Enable(const enum LogLevel level)
Enable this LogComponent at level.
Definition: log.cc:298
std::string File() const
Get the compilation unit defining this LogComponent.
Definition: log.cc:316
int32_t m_levels
Enabled LogLevels.
Definition: log.h:421
static std::string GetLevelLabel(const enum LogLevel level)
Get the string label for the given LogLevel.
Definition: log.cc:323
void EnvVarCheck()
Parse the NS_LOG environment variable for options relating to this LogComponent.
Definition: log.cc:145
void Disable(const enum LogLevel level)
Disable logging at level for this LogComponent.
Definition: log.cc:304
std::string m_file
File defining this LogComponent.
Definition: log.h:424
bool IsNoneEnabled() const
Check if all levels are disabled.
Definition: log.cc:286
void SetMask(const enum LogLevel level)
Prevent the enabling of a specific LogLevel.
Definition: log.cc:292
LogComponent(const std::string &name, const std::string &file, const enum LogLevel mask=LOG_NONE)
Constructor.
Definition: log.cc:104
int32_t m_mask
Blocked LogLevels.
Definition: log.h:422
std::map< std::string, LogComponent * > ComponentList
LogComponent name map.
Definition: log.h:400
std::string m_name
LogComponent name.
Definition: log.h:423
bool IsEnabled(const enum LogLevel level) const
Check if this LogComponent is enabled for level.
Definition: log.cc:279
Insert , when streaming function arguments.
Definition: log.h:440
ParameterLogger & operator<<(T param)
Write a function parameter on the output stream, separating parameters after the first by ,...
Definition: log.h:500
void CommaRest()
Add , before every parameter after the first.
Definition: log.cc:637
bool m_first
First argument flag, doesn't get ,.
Definition: log.h:494
ParameterLogger(std::ostream &os)
Constructor.
Definition: log.cc:631
std::ostream & m_os
Underlying output stream.
Definition: log.h:495
Handler for print-list token in NS_LOG to print the list of log components.
Definition: log.cc:61
PrintList()
Definition: log.cc:80
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_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:160
static NodePrinter g_logNodePrinter
The Log NodePrinter.
Definition: log.cc:52
static void CheckEnvironmentVariables()
Parse the NS_LOG environment variable.
Definition: log.cc:523
static bool ComponentExists(std::string componentName)
Check if a log component exists.
Definition: log.cc:500
static TimePrinter g_logTimePrinter
The Log TimePrinter.
Definition: log.cc:47
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static PrintList g_printList
Invoke handler for print-list in NS_LOG environment variable.
Definition: log.cc:70
void LogComponentDisableAll(enum LogLevel level)
Disable all logging for all components.
Definition: log.cc:408
void LogSetTimePrinter(TimePrinter printer)
Set the TimePrinter function to be used to prepend log messages with the simulation time.
Definition: log.cc:603
void(* TimePrinter)(std::ostream &os)
Function signature for features requiring a time formatter, such as logging or ShowProgress.
Definition: time-printer.h:43
void LogComponentDisable(const char *name, enum LogLevel level)
Disable the logging output associated with that log component.
Definition: log.cc:392
void(* NodePrinter)(std::ostream &os)
Function signature for prepending the node id to a log message.
Definition: node-printer.h:40
NodePrinter LogGetNodePrinter()
Get the LogNodePrinter function currently in use.
Definition: log.cc:626
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_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_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:614
LogComponent & GetLogComponent(const std::string name)
Get the LogComponent registered with the given name.
Definition: log.cc:128
void LogComponentEnable(const char *name, enum LogLevel level)
Enable the logging output associated with that log component.
Definition: log.cc:358
void LogSetNodePrinter(NodePrinter printer)
Set the LogNodePrinter function to be used to prepend log messages with the node id.
Definition: log.cc:620
void LogComponentPrintList()
Print the list of logging messages available.
Definition: log.cc:420
void LogComponentEnableAll(enum LogLevel level)
Enable the logging output for all registered log components.
Definition: log.cc:380