LTE Manual ——Logging(翻译)

(本文为个人学习笔记,如有不当的地方,欢迎指正!)

9 Logging

 
ns-3 日志功能可以用于监测或调试仿真程序的进展。日志输出可以通过 main()  程序中的语句或通过使用 NS_LOG 环境变量来启用。
 
日志语句并没有编译成 ns-3 的优化版本(Logging statements are not compiled into optimized builds of ns-3)。为了使用日志,必须 build  ns-3  的默认调试 build 。
 
这个项目并不能保证日志输出会随时间而保持不变。提醒用户不要在日志代码顶部建立仿真输出框架,因为输出和启用输出的方式可能会随时间改变。
 

9.1 概述

 
ns-3 日志语句通常用于记录各种程序执行事件,例如仿真事件的发生或特定函数的使用。
 
例如,这个代码片段来自  Ipv4L3Protocol::IsDestinationAddress():
 
if (address == iaddr.GetBroadcast ())
{
NS_LOG_LOGIC ("For me (interface broadcast address)");
return true;
}
如果 Ipv4L3Protocol component 在 大于或等于 LOGIC severity 级别上开启日志功能,那么日志声明会被打印输出;否则会被抑制。
 

9.1.1 启用输出

 
用户通常使用两种方式控制日志输出。第一种是设置 NS_LOG 环境变量;例如:
 
$ NS_LOG="*" ./waf --run first
 
上述代码将运行 first tutorial 程序,得到所有的日志输出。 (下面将讨论特定的 NS_LOG 格式。)
 
通过选择单独的组件,日志输出可以变得更详细:
 
$ NS_LOG="Ipv4L3Protocol" ./waf --run first
 
输出可以进一步根据前缀选项来定制。
 
第二种启用输出的方式是在程序中使用明确的语句。例如在 first tutorial 程序中添加下列代码:
 
int main (int argc, char *argv[]){
LogComponentEnable ("UdpEchoClientApplication", LOG_LEVEL_INFO);
LogComponentEnable ("UdpEchoServerApplication", LOG_LEVEL_INFO);
...
(下面讨论 LOG_LEVEL_INFO  的含义和其他可能的值。 )
 

9.1.2 NS_LOG 语法

 
NS_LOG 环境变量包含一系列日志组件和选项。日志组件通过冒号':' 隔开:
 
$ NS_LOG="<log-component>:<log-component>..."
每个日志组件选项通过标识符(flags)给定,位于日志组件后面:
 
$ NS_LOG="<log-component>=<option>|<option>...:<log-component>..."
选项(options)控制该组件的 severity 和 level ,以及是否应包含可选信息,例如仿真时间、仿真节点、函数名和象征性的 severity。
 

9.1.3 日志组件

 
通常来说,一个日志组件指的是单个的 .cc 源码文件,并且包含整个文件。
 
一些 helpers 有特殊的方法用于启用 一个模块中所有组件的日志功能,跨越不同的编译单位,但是逻辑上能组合在一起,例如  ns-3 wifi 代码:
 
WifiHelper wifiHelper;wifiHelper.EnableLogComponents ();
 
NS_LOG 日志组件通配符 '*' 启用所有的组件。
 
为了查看日志组件的定义,使用下面任何一个都可以:
 
$ NS_LOG="print-list" ./waf --run ...

$ NS_LOG="foo"  # a token not matching any log-component
 
第一种形式会打印输出所有日志组件的名称和启用标识符(flags);可以使用 scratch-simulator 去尝试。第二种形式会打印输出所有注册的日志组件,然后以一个错误退出。
 

9.1.4 Severity 和 Level 选项

 
单个的消息属于单个的 “severity class” ,由宏创建消息。在上述例子中, NS_LOG_LOGIC(..)  在 LOG_LOGIC severity 类中创建消息。
 
下列 severity 类定义为 enum 常量:
 
Severity Class Meaning
LOG_NONE The default, no logging
LOG_ERROR Serious error messages only
LOG_WARN Warning messages
LOG_DEBUG For use in debugging
LOG_INFO Informational
LOG_FUNCTION Function tracing
LOG_LOGIC Control flow tracing within functions
 
通常情况下, 人们想在给定的 severity 类和更高的类上看到消息。这可以通过定义包含的日志 “levels”来定义:
 
Level Meaning
LOG_LEVEL_ERROR Only LOG_ERROR severity class messages.
LOG_LEVEL_WARN LOG_WARN and above.
LOG_LEVEL_DEBUG LOG_DEBUG and above.
LOG_LEVEL_INFO LOG_INFO and above.
LOG_LEVEL_FUNCTION LOG_FUNCTION and above.
LOG_LEVEL_LOGIC LOG_LOGIC and above.
LOG_LEVEL_ALL All severity classes.
LOG_ALL Synonym for LOG_LEVEL_ALL
 
severity 类和 level 选项可以通过这些令牌在 NS_LOG 环境变量中给定 :
 
Class Level
error level_error
warn level_warn
debug level_debug
info level_info
function level_function
logic level_logic
  level_allall*
 
使用一个 severity 类令牌只能启用该 severity 的日志消息。 例如, NS_LOG="*=warn" 不会输出 severity 为  error 的消息。 NS_LOG="*=level_debug" 只会输出 severity 级别为 debug 及以上的日志消息。
 
severity 类和级别可以使用 `|’ 运算符进行结合: NS_LOG="*=level_warn|logic" 将输出 severity 级别为 error、 warn 和 logic 的消息。
 
NS_LOG severity 级别的通配符'*' 与  all 的同义词为  level_all。
 
对于只在 NS_LOG 中提到的日志组件:
 
$ NS_LOG="<log-component>:..."
 
默认的 severity 为 LOG_LEVEL_ALL。
 

9.1.5 前缀选项

 
很多前缀有助于确定消息起源于何时何地,是什么 severity。
 
可用的前缀选项 (如同 enum 常量)有
 
Prefix Symbol Meaning
LOG_PREFIX_FUNC Prefix the name of the calling function.
LOG_PREFIX_TIME Prefix the simulation time.
LOG_PREFIX_NODE Prefix the node id.
LOG_PREFIX_LEVEL Prefix the severity level.
LOG_PREFIX_ALL Enable all prefixes.
 
下面简要描述前缀选项。
 
选项可以通过这些令牌在 NS_LOG 环境变量中给出:
 
Token Alternate
prefix_func func
prefix_time time
prefix_node node
prefix_level level
prefix_all all*
 
对于只在 NS_LOG 中提到的日志组件:
 
$ NS_LOG="<log-component>:..."
 
默认的前缀选项为 LOG_PREFIX_ALL。
 
(1)Severity 前缀
 
一个消息的 severity 类包含在选项 prefix_level 或 level 中。 例如, NS_LOG 的值启用所有日志组件 ('*') 和所有 severity 类 (=all) 的日志功能,并且给 severity 类 (|prefix_level) 的消息添加前缀。
 
$ NS_LOG="*=all|prefix_level" ./waf --run scratch-simulator
Scratch Simulator
[ERROR] error message
[WARN] warn message
[DEBUG] debug message
[INFO] info message
[FUNCT] function message
[LOGIC] logic message
 
(2)时间前缀
 
仿真时间包含在选项 prefix_time 后 time 中,以秒为单位输出仿真时间。
 
(3)节点前缀
 
仿真节点 id 包含在选项 prefix_node 或 node 中。
 
(4)函数前缀
 
调用的函数名包含在选项 prefix_func 或  func 中。
 
(5)NS_LOG 通配符
 
日志组件通配符 '*' 表示启用所有的组件。 在特定的 severity 级别启用所有组件,可以使用 *=<severity> 。
 
severity 级别选项通配符 '*' 是  all 的同义词。 它必须出现在任何 '|' 字符分隔选项之前。为了启用所有的 severity 类,可以使用  <log-component>=*  或 <log-component>=*|<options>。
 
选项通配符 '*' 或令牌 all 开启所有的前缀选项,但是必须出现 '|' 字符的后面。为了启用特定的 severity 类或级别,以及所有的前缀,可以使用 <log-component>=<severity>|*。
 
结合选项通配符  ** 表示启用所有的 severities 和所有的前缀;例如, <log-component>=**。
 
 uber-wildcard *** 表示启用所有日志组件的所有 severities 和所有前缀。这些都是等价的:
 
$ NS_LOG="***" ...      $ NS_LOG="*=all|*" ...        $ NS_LOG="*=*|all" ...
$ NS_LOG="*=**" ... $ NS_LOG="*=level_all|*" ... $ NS_LOG="*=*|prefix_all" ...
$ NS_LOG="*=*|*" ...
 
建议: 使用 NS_LOG="***",甚至连微不足道的 scratch-simulator 也会产生超过 46K 行的输出!
 
 

9.2 如何在代码中添加日志功能

在你的代码中添加日志功能非常重要:

(1)调用 namespace ns3 里的 NS_LOG_COMPONENT_DEFINE (...); 宏。

 
创建唯一的字符串标识符(通常基于文件名或文件内定义的类名),并使用宏调用注册它,例如:
 
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");...
 
它会注册 Ipv4L3Protocol 为一个日志组件。
 
(宏是精心编写的,目的是允许其包含在命名空间 ns3 内部或外部,并且整个代码库的使用情况有所不同,但是最初的目的是在命名空间 ns3 的外部、在文件全局范围内注册宏。)
 

(2)在函数和函数体中添加日志声明(宏调用)。

 

9.2.1 Logging Macros(日志宏)

 
日志宏和相关的 severity 等级为
 
Severity Class Macro
LOG_NONE (none needed)
LOG_ERROR NS_LOG_ERROR (...);
LOG_WARN NS_LOG_WARN (...);
LOG_DEBUG NS_LOG_DEBUG (...);
LOG_INFO NS_LOG_INFO (...);
LOG_FUNCTION NS_LOG_FUNCTION (...);
LOG_LOGIC NS_LOG_LOGIC (...);
 
宏的功能为输出 streamers,因此发送 std::cout、使用  << 运算符连接的任何东西都是允许的:
 
void MyClass::Check (int value, char * item){
NS_LOG_FUNCTION (this << arg << item);
if (arg > )
{
NS_LOG_ERROR ("encountered bad value " << value <<
" while checking " << name << "!");
}
...}
 
注意 NS_LOG_FUNCTION 自动会在每个参数间插入一个 ',' (comma-space) 分隔符。 这简化了函数参数的日志; 只是如同上述例子一样,将它们用 << 运算符进行连接。
 
 

9.2.2 Unconditional Logging(无条件的日志)

 
为方便起见, NS_LOG_UNCOND (...); 宏将总是记录它的参数,即使相关的日志组件没有在任何 severity 开启。 该宏不会使用任何前缀选项。注意日志只能在调试 builds 中启用;该宏不会在优化的 builds 中产生输出。
 

9.2.3 Guidelines(指南)

  • 使用 NS_LOG_FUNCTION (this << args...); 开始每个类的方法。 这会启用简单的函数调用  tracing 。
    • 除了: 不要记录运算符或明确的副本构造函数,因为这些会造成无穷递归和堆栈溢出。
    • 对于没有参数的方法,使用相同形式:NS_LOG_FUNCTION (this);
    • 对于静态函数:
      • 有参数的话,像往常一样使用 NS_LOG_FUNCTION (...); 。
      • 没有参数的话使用 NS_LOG_FUNCTION_NOARGS ();
  • NS_LOG_ERROR 用于错误严重的条件(可能使仿真执行无效)。
  • NS_LOG_WARN 用于不寻常的条件(可以纠正的)。 请给出问题本质以及如何纠正它的的有关提示。
  • NS_LOG_DEBUG  通常以一种特别的方式使用,目的是理解模型的执行。
  • NS_LOG_INFO 用于执行的附加信息,例如数据结构的大小(当添加/移除数据结构时)。
  • NS_LOG_LOGIC 用于 trace 一个函数的重要逻辑分支
  • 测试你的日志变化不会打破代码(break the code)。运行一些启用所有日志组件的示例程序(例如 NS_LOG="***")。
  • 使用显式类型转换,用于任何类型的变量 uint8_t 或 int8_t,例如, NS_LOG_LOGIC ("Variable i is " << static_cast<int> (i));。没有了 cast, 整数会被理解为一个字符,结果最可能不符合期望。这是一个有据可查的 C++ ‘feature’。
 
 
 
 
 参考文献:https://www.nsnam.org/docs/manual/singlehtml/index.html#document-logging

LTE Manual ——Logging(翻译)的更多相关文章

  1. 【socket编程】select manual page翻译

    原文: select manual page 依赖的头文件 /* According to POSIX.1-2001, POSIX.1-2008 */ #include <sys/select. ...

  2. trove manual installation 翻译

    目标 此文件提供了一步一步的指导手动安装trove在一个现有OpenStack的环境为了开发. 该文件将不包括: OpenStack的设置 trove服务配置 要求 正在运行的OpenStack的环境 ...

  3. 开始进行lammps手册的学习啦,跟着Manual一边翻译一边做吧!(转载)

    转载自:http://blog.sina.com.cn/s/blog_64813e370100ngsz.html 注明:黄色部分基本上为不懂的部分,红色字体为所做注释 一.各种文件的介绍: 1 in ...

  4. Manual——Test (翻译1)

    LTE Manual ——Logging(翻译) (本文为个人学习笔记,如有不当的地方,欢迎指正!) 1.17.3 Testing framework(测试框架)   ns-3 包含一个仿真核心引擎. ...

  5. day18 logging模块 sys shelve

    昨日回顾 re 正则表达式 匹配字符串 场景 例如:爬虫,密码规则验证,邮箱地址验证,手机号码 学习re主要学习的就是 那一堆特殊符号 hashlib hash是一种算法 lib表示库 该模块包含了一 ...

  6. 如何使用Python的logging模块

    几个学习连接: Python官方链接: https://docs.python.org/3.4/library/logging.html?highlight=logging 翻译(不过是2.3版本的) ...

  7. MySQL - Show Processlist 整理

    MySQL - Show Processlist 整理   原文来源:MySQL 5.5 Reference Manual 部分翻译取自:<MySQL_5.1中文参考手册> 转载请注明原文 ...

  8. MySQL - Show Processlist 整理(转)

      原文来源:MySQL 5.5 Reference Manual 部分翻译取自:<MySQL_5.1中文参考手册> 转载请注明原文链接http://www.cnblogs.com/len ...

  9. Show Global Status 整理

    原文来源:MySQL 5.5 Reference Manual 部分翻译取自:<MySQL_5.1中文参考手册> 转载请注明原文链接http://www.cnblogs.com/lenag ...

随机推荐

  1. servlet获取参数时,request.getParameter("id")参数获取失败

    servlet获取参数时,request.getParameter("id")参数获取失败,这里的参数是“index”里面href中的参数 要注意,取不到值,是不是要取的参数有没有 ...

  2. css元素排列

    有时候元素的排列没有预想的效果,考虑是不是margin和padding的影响

  3. JavaScript 的倒计时

    一年前,在网上找到的例子,现在已经找不到出处,对不住原作者,请原谅.修改了一下,在刷新页面的情况下,倒计时不重来. 没有任何样式,纯文字倒计时. <!DOCTYPE html> <h ...

  4. 【Arduino】旋转编码器的Arduino使用方法

    以前用CRT显示器的时候,调整显示器的时候用一个圆盘转动和点击的方法就可以实现选择菜单和修改设置项的值,比多个按钮的方式方便很多. 鼠标滚轮也是这种操作方法,旋转+点击,只是方向不同.最近在网上买了旋 ...

  5. 移动设备如何打开RMS加密的文档

    关键字:RMS. AZure RMS.IPhone.Android.Office365.Sharepoint.Exchange 最近总是碰到要求用苹果手机及安卓手机阅读RMS加密文档的需求,经过查找相 ...

  6. c#的逻辑运算符重载

    不光是C++,实际上C#中同样可以对操作符重载.如:namespace Com.EVSoft.Math{  public class Vector3:BaseObject  {    ...    . ...

  7. FC400A与400B的区别

    FC400B就比400A多了一个功能,那就是联动,也就是说主机关了后,电子净化箱也会被关掉,这样就不需要去手动关闭电源,更加方便,估计是很多工业企业上需要这样的功能,所以就升级了这么个版本.

  8. GirdView 追忆学生时代的百思不得解

    临近年关,越多越多的园友开始了对工作.生活的总结,以及对来年目标的确立.这很励志,人是一根能思想的苇草,想来想去,我实在没什么惊天地.泣鬼神的英勇事迹,16年毕业季,按部就班的在时间的马车上颠簸,阅读 ...

  9. MVC,MVP 和 MVVM

    复杂的软件必须有清晰合理的架构,否则无法开发和维护.MVC(Model-View-Controller)是最常见的软件架构之一,业界有着广泛应用.它本身很容易理解,但是要讲清楚,它与衍生的 MVP 和 ...

  10. 自己写的java excel导出工具类

    最近项目要用到excel导出功能,之前也写过类似的代码.因为这次项目中多次用到excel导出.这次长了记性整理了一下 分享给大伙 欢迎一起讨论 生成excel的主工具类: public class E ...