【ns-3】Logging系统

前言

本篇介绍Logging系统。


1. 概述

许多大型系统都会提供一种基于控制台的消息记录功能,用来向用户即时地反馈程序执行情况。ns-3也不例外。ns-3提供了一种可选的、多等级的消息记录功能—Logging系统。Logging功能可以被完全禁用,可以逐个组件启用,也可以全局启用。Logging系统还可以选择所记录消息的详细程度(verbosity level)或严重程度(severity level),以及为消息添加不同的前缀(prefix)。因此,Logging系统提供了一种非常灵活且功能强大,但使用相对简单的消息记录功能 [1] [2]

需要说明的是,Logging系统在ns-3中主要用于:一是通过输出网络组件内部模块执行过程方便用户理解;二是通过输出简单的调试信息方便用户调试,而非收集仿真数据 [3]。ns-3提供了一种收集仿真数据的通用机制—Tracing系统,这是我们收集仿真数据的首选 [2]


2. 基本概念

上面提到,Logging系统提供了一种非常灵活的消息记录功能,不仅可以逐个组件地启用Logging功能,还可以选择所记录消息的详细程度或严重程度,并为消息添加不同的前缀。

因此,在介绍如何使用Logging系统之前,在这一节,我们先介绍日志组件(Log Component)、控制日志输出的详细程度或严重程度选项以及前缀选项等基本概念。

2.1 日志组件

日志组件是Logging系统的最小管理单位。通俗地说,一个日志组件就是指一个C++源代码文件。通过日志组件,Logging系统就可以把信息输出控制精确到某一个C++文件 [1] [4]

而要把一个C++文件添加为日志组件也很容易,只要在C++文件开头在ns3名字空间范围内使用NS_LOG_COMPONENT_DEFINE宏注册即可。日志组件名必须是全局唯一的(通常基于文件名或文件中定义的类的名)。

例如,在first.cc中LogComponentEnable()中的第一个参数即是日志组件名(关于LogComponentEnable函数我们会在后面再介绍),如下图所示:

在这里插入图片描述
UdpEchoClinetApplication日志组件和UdpEchoServerApplication日志组件代表的分别是udp-echo-client.cc文件和udp-echo-server.cc文件,是在各自文件开头在ns3名字空间范围内使用NS_LOG_COMPONENT_DEFINE宏注册的,如下图所示:

在这里插入图片描述
在这里插入图片描述
 

2.2 日志详细程度(严重程度)选项

上面说过,通过日志组件,Logging系统可以把信息输出控制精确到某一个C++文件。而通过日志详细程度(或严重程度)选项,Logging系统可以进一步把信息输出控制精确到某一个C++文件的某一层级。

ns-3中,Logging系统通常提供了7个日志详细程度(或严重程度)选项,输出信息的详细程度由低到高(即输出信息由少到多)或者说信息的严重程度由高到低依次为 [1]

  • 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和NS_LOG_FUNCTION_NOARGS)
  • LOG_LOGIC:记录函数内部逻辑流信息(关联的宏为:NS_LOG_LOGIC)
  • LOG_ALL:记录上述所有信息(无关联的宏)

注释

实际上,ns-3在src/core/model/log.h中还定义了一个日志等级LOG_NONE,其不会记录任何信息。


我们还是以first.cc为例,LogComponentEnable()中的第二个参数是日志详细程度(严重程度)选项,如下图所示:

在这里插入图片描述

需要注意的是,除了LOG_ALL之外,其余6个日志详细程度(或严重程度)选项只能控制其所关联的宏中所输出的信息的输出。例如,LOG_INFO等级只能控制指定日志组件中所有NS_LOG_INFO宏所输出的信息的输出。

为了更加直观地说明这一点,我们看一下下面这个我们自己编写的log-level-demo.cc示例脚本,同时顺便回顾和实战上面介绍的日志组件相关知识:

在这里插入图片描述
首先,我们在文件开头的ns3名字空间范围内使用NS_LOG_COMPONENT_DEFINE宏将该文件注册为一个名为“LogLevelDemo”的日志组件。

接着,我们在main函数中使用LogComponentEnable函数启用了LogLevelDemo日志组件,并将日志详细程度(或严重程度)选项设置为LOG_INFO(关于LogComponentEnable函数的使用,我们稍后再详细介绍)。

然后,我们在ns-3.37目录下,在终端中使用./ns3编译运行该脚本(log-level-demo.cc文件需放在ns-3.37/scratch目录下):

在这里插入图片描述
第一次编译运行log-level-demo.cc文件时会先自动进行默认配置。

结果如下:

在这里插入图片描述

我们可以看到,只有NS_LOG_INFO宏中的信息被输出。

我们可以修改LogComponentEnable的日志详细程度(或严重程度)选项为LOG_DEBUG,再次使用./ns3编译运行该脚本,结果如下:

在这里插入图片描述

我们可以看到,只有NS_LOG_DEBUG宏中的信息被输出。


注释:

  • 如果按照上述步骤操作没有信息被输出,可以检查一下配置选项(./ns3 show profile):

在这里插入图片描述
如果配置选项为optimized,则不会有信息被输出。因为日志声明在optimized配置下不会被编译 [1]

  • 实际上,上述日志等级并没有一个非常严格的界限划分(依赖于关联的NS_LOG_TYPE宏的使用),因此有时候阅读C++源码是在所难免的 [4]

如果我们希望同时输出NS_LOG_INFO宏和NS_LOG_DEBUG宏中的信息,那么我们可以这样:

在这里插入图片描述
再次使用./ns3编译运行该脚本,结果如下:

在这里插入图片描述

NS_LOG_INFO宏和NS_LOG_DEBUG宏中的信息都被输出了!

有时候,我们想把某一详细程度(或严重程度)及更低详细程度(或更高严重程度)的信息一并输出。例如,我们想同时输出LOG_INFO及更低详细程度(或更高严重程度)的信息。如果像上面一样显式指定的话会比较繁琐,因此Logging系统针对每个LOG_TYPE(LOG_NONE除外)还定义了一个对应的LOG_LEVEL_TYPE,可以输出LOG_TYPE及更低详细程度(或更高严重程度)的信息 [1]

  • LOG_LEVEL_ERROR
  • LOG_LEVEL_WARN
  • LOG_LEVEL_DEBUG
  • LOG_LEVEL_INFO
  • LOG_LEVEL_FUNCTION
  • LOG_LEVEL_LOGIC
  • LOG_LEVEL_ALL / LOG_ALL

注释:

实际上,LOG_LEVEL_ERROR和LOG_ERROR是一样的,因为他们都只显示自己层级的日志;LOG_LEVEL_ALL和LOG_ALL也是是一致的,因为他们都显示所有层级的日志。


我们还是以log-level-demo.cc示例脚本为例,将LogComponentEnable函数中的第二个参数做如下修改:

在这里插入图片描述

再次使用./ns3编译运行该脚本,结果如下:

在这里插入图片描述
可以看到LOG_INFO及更低详细程度(或更高严重程度)的信息都被输出了。

2.3 日志前缀选项

除了日志详细程度(严重程度)选项外,Logging系统还提供了日志前缀选项。这些前缀可以帮助识别消息何时来源于何处,以及严重等级 [1]

  • LOG_PREFIX_FUNC:加上调用函数名前缀
  • LOG_PREFIX_TIME:加上仿真时间前缀
  • LOG_PREFIX_NODE:加上节点id前缀
  • LOG_PREFIX_LEVEL:加上详细程度(或严重程度)前缀
  • LOG_PREFIX_ALL:加上所有前缀

我们还是以log-level-demo.cc示例脚本为例,对LogComponentEnable函数做如下修改:

在这里插入图片描述
再次使用./ns3编译运行该脚本,结果如下:

在这里插入图片描述
输出信息前面加上了日志详细程度(或严重程度)前缀。

我们再对LogComponentEnable函数做如下修改:

在这里插入图片描述
再次使用./ns3编译运行该脚本,结果如下:

在这里插入图片描述
输出信息前面加上了日志详细程度(或严重程度)前缀以及调用函数名前缀(需要注意的是函数名前缀main()前面的是日志组件名而非文件名或类名)。

3. 控制日志输出

ns-3提供了两种常用的控制日志输出的方法 [1]

  • 通过LogComponentEnable函数控制日志输出:在main()主函数中通过LogComponentEnable函数显式声明

    在这里插入图片描述

    LogComponentEnable函数的第一个参数是日志组件名(字符串),第二个参数是LogLevel选项,包括日志详细程度(严重程度)选项和日志前缀选项,其语法如下:

    LogComponentEnable(<log-component>, <option>) // 单个日志选项
    LogComponentEnable(<log-component>, LogLevel(<option> | <option> | ...)) // 多个日志选项放在LogLevel()中并用|分开
    

    关于如何通过LogComponentEnable函数控制日志输出,我们不再赘述,具体可参考上面的内容。

  • 通过NS_LOG环境变量控制日志输出

    通过上面log-level-demo.cc示例脚本的大量演示我们其实不难发现,通过LogComponentEnable函数控制日志输出我们需要一遍遍修改源代码,比较繁琐。所以ns-3还提供了通过NS_LOG环境变量的方式控制日志输出,其语法如下:

    /*
    每个日志组件的选项罗列在日志组件的后面,用“|”隔开,日志组件和其所对应的选项之间用“=”连接
    不同日志组件之间用“:”隔开
    */
    NS_LOG="<log-component>=<option>|<option>... : <log-component>=<option>|<option>..." ./ns3 run <script>
    

    但是需要注意的是,在NS_LOG环境变量中,日志详细程度(严重程度)选项和日志前缀选项是由以下token给出的,和LogComponentEnable函数中的相关语法不一样 [1]

    在这里插入图片描述
    在这里插入图片描述
    我们还是以log-level-demo.cc示例脚本为例:
    在这里插入图片描述
    在终端中通过NS_LOG环境变量控制日志输出:
    在这里插入图片描述
    而如果我们和LogComponentEnable函数一样,在NS_LOG环境变量中使用LOG_INFO和LOG_PREFIX_LEVEL控制日志输出的话,那么将不起作用,如下所示:
    在这里插入图片描述


注释:

  • 无论是通过LogComponentEnable函数控制日志输出,还是通过NS_LOG环境变量控制日志输出,都需要使用NS_LOG_COMPONENT_DEFINE宏先注册日志组件。

  • 当通过NS_LOG环境变量控制日志输出时,无需在main()主函数中通过LogComponentEnable函数显式声明开启日志功能,如上个示例所示。

  • NS_LOG=“<log-component>:…”(即在NS_LOG环境变量中不显示指定日志选项),默认的日志详细程度(严重程度)选项为level_all,默认的日志前缀选项为all [1]

  • 如果在main()主函数中通过LogComponentEnable函数显式声明开启日志功能,那么再通过NS_LOG环境变量控制日志输出时,两种方式会一并作用。
    例如:
    我们在main()主函数中通过LogComponentEnable函数显式声明开启日志功能的同时,使用NS_LOG环境变量控制日志输出:
    在这里插入图片描述
    结果如下:
    在这里插入图片描述
    LogComponentEnable函数和NS_LOG环境变量同时作用了!

  • 如果想启用特定详细程度(严重程度)的所有组件,并添加特定前缀,那么可以使用通配符“*”表示所有日志组件 [1]

NS_LOG="*=<option>|<option>“
  • 如果想启用特定日志组件,并打开所有日志详细程度(严重程度),也可以使用通配符“*”代替”all“或者”level_all“。但是日志详细程度(严重程度)的通配符应在”|“符号之前(如果有的话)[1]
NS_LOG="<log-component>=*|<option>“ // 等价于NS_LOG="<log-component>=all|<option>“
                                    // 或者NS_LOG="<log-component>=level_all|<option>“
  • 如果想启用特定日志组件,并添加所有日志前缀,也可以使用通配符“*”代替”all。但是日志前缀的通配符必须在”|“符号之后 [1]
NS_LOG="<log-component>=<option>|*“ // 等价于NS_LOG="<log-component>=<option>|all“
  • 以下命令等价 [1]
    在这里插入图片描述

参考文献

[1]: ns-3 Manual
[2]: ns-3 Tutorial
[3]: ns-3网络模拟器基础及应用
[4]: 开源网络模拟器ns-3:架构与实践

猜你喜欢

转载自blog.csdn.net/Graduate2015/article/details/129481225