NS3系列—7———NS3日志


http://www.cnblogs.com/lovemo1314/archive/2011/12/21/2295969.html


NS-3日志子系统的提供了各种查看仿真结果的渠道:
一、使用Logging Module
0、【预备知识】日志级别及其对应的宏
NS-3提供了若干个日志级别来满足不同的Debug需求,每一级的日志内容都涵盖了低一级的内容。这些级别对应的宏从低到高排列为:
  *NS_LOG_ERROR — Log error messages;
  *NS_LOG_WARN — Log warning messages;
  *NS_LOG_DEBUG — Log relatively rare, ad-hoc debugging messages;
  *NS_LOG_INFO — Log informational messages about program progress;
  *NS_LOG_FUNCTION — Log a message describing each function called;
  *NS_LOG_LOGIC — Log messages describing logical flow within a function;
  *NS_LOG_ALL — Log everything.
  *NS_LOG_UNCOND — 无条件输出

方式1、通过设置shell环境变量NS_LOG使用日志系统
 1.1)首先,定义好一个日志模块:
  可以在脚本中使用宏NS_LOG_COMPONENT_DEFINE(name)定义一个日志模块。(注意,为了使用宏NS_LOG(name, level)来输出这个模块所定义的内容,这个定义语句必须写在每个脚本文件的开始。宏NS_LOG将在方式2中进行介绍。)
  也有一些日志模块是内置的,比如上文的名为“UdpEchoClientApplication”“UdpEchoServerApplication”的模块就是UdpEcho应用程序内置的日志模块,只要使用了相应的类,就可以启用相应的日志模块。
 1.2)在shell中通过设置环境变量NS_LOG,来控制仿真输出级别:
  $~/ns-3.2.1 > export NS_LOG = '<日志模块名称> =level_all | prefix_func | prefix_time'
   *level_all表示启用所有级别(=error | warn | debug | info | function | logic)
   *prefix_func表示记录输出该消息的函数
   *prefix_time表示加上时间前缀
  $~/ns-3.2.1 > export NS_LOG = '<日志模块名称1>=level_all : <日志模块名称2>=info'
   *符号:隔开两个不同的日志模块
  $~/ns-3.2.1 > export NS_LOG = * = level_all
   *符号*作为通配符。上行命令表示启用所有可用模块的所有日志级别。
   *这一般会形成大量的数据,此时可以使用shell的输出重定向保存日志到文件里面:
    $~/ns-3.2.1 > ./waf --run scratch/example >& log.out

方式2、通过在脚本里使用宏NS_LOG调用日志模块
 2.0)宏NS_LOG(level, msg)用于定义对应level的输出内容;为了方便使用,系统预定义了各个级别的NS_LOG宏NS_LOG_ERROR等(参见【预备知识】):
  #define NS_LOG_ERROR(msg)   NS_LOG(ns3::LOG_ERROR, msg)
 2.1)如上文,在脚本里使用宏NS_LOG_COMPONENT_DEFINE(name)定义一个日志模块;
 2.2)使用宏LogComponentEnable(name, level)启用日志(对应地,有宏LogComponentDisable(name, level)用于禁用日志);
 2.3)使用【预备知识】里定义的各种级别的宏输出内容,注意程序只会输出低于等于已经启用的level的宏内容。
  NS_LOG_COMPONENT_DEFINE("Example");
  LogComponentEnable("Example", LOG_LEVEL_INFO);   //等价于shell中:export NS_LOG = 'Example=info'

//运行时显示程序中用语句NS_LOG_INFO(“字符串”)定义的字符串,便于检查错误。
  NS_LOG_WARN("Message:level_warn");
  NS_LOG_INFO("Message:level_info");
  NS_LOG_LOGIC("Message:level_logic");
   //由于我们启用的日志level是INFO,因此编译运行后,程序会输出低于和等于INFO级别的内容,而高于INFO级别的宏内容不会被输出
   //即,Message:level_warn和Message:level_info会被输出,而Message:level_logic不会被输出

===============================================================================================================

二、使用Command Line参数
仿真一般是为了收集各种不同条件下的数据,常常需要改变一些变量。NS-3提供了Command Line参数接口,可以在运行时对脚本中的变量进行设置,免去了每次更改变量后要重新编译的麻烦。(相当于在运行前进行变量的scanf/cin操作,但因为有默认值,CLI更灵活一些。)
1、在脚本中添加语句
int main (int argc, char *argv[])
{
  ...
  CommandLine cmd;
  cmd.Parse (argc, argv);  //将命令行输入的参数作为类CommandLine的参数进行分析
  ...
}
  这样可以在shell中使用某些附加参数如PrintHelp:
   $~/ns-3.2.1 > ./waf --run "scratch/example --PrintHelp"
  这条命令将会列出example当前可用的命令参数:
   Entering directory '/home/craigdo/repos/ns-3-dev/build'
   Compilation finished successfully
   --PrintHelp: Print this help message.
   --PrintGroups: Print the list of groups.
   --PrintTypeIds: Print all TypeIds.
   --PrintGroup=[group]: Print all TypeIds of group.
   --PrintAttributes=[typeid]: Print all attributes of typeid.
   --PrintGlobals: Print the list of globals.
  从输出中(倒数第二行)我们知道可以打印某些类的属性:
   $~/ns-3.2.1 > ./waf --run "scratch/example --PrintAttributes=ns3::PointToPointNetDevice"
  这条命令将会列出类型为PointToPointNetDevice的设备的属性:
   --ns3::PointToPointNetDevice::DataRate=[32768bps]:
   The default data rate for point to point links
  知道了属性名称,我们也可以使用命令更改这个属性:
   $~/ns-3.2.1 > ./waf --run "scratch/example --ns3::PointToPointNetDevice::DataRate=5Mbps"

2、使用CommandLine::AddValue添加自己的变量,使之成为CommandLine可以使用的参数
   CommandLine cmd;
   cmd.AddValue("nPackets", "Number of packets to echo", nPackets);   //(属性名称,属性说明,变量)
   cmd.Parse(argc, argv);
  这样在shell中我们可以在命令中更改这个属性:
   $~/ns-3.2.1 > ./waf --run "scratch/example --nPackets=2"

===============================================================================================================

三、使用Tracing System
1、启用ASCII Tracing
  NS-3提供了类似NS-2的日志输出(*.tr文件),记录系统中的动作。在Simulator::Run()之前添加语句:
   #include <fstream>
   ...
   std::ofstream ascii;
   ascii.open ("example.tr");
   PointToPointHelper::EnableAsciiAll (ascii);
  则运行后我们可以在example.tr文件中看到系统的日志(使用ASCII文本阅读器即可),其中每一行都是以+/-/d/r开头的:
   +: An enqueue operation occurred on the device queue;
   -: A dequeue operation occurred on the device queue;
   d: A packet was dropped, typically because the queue was full;
   r: A packet was received by the net device.
  例如我们可以看到文件中的第一行(为了说明方便,这里分段编号显示),显示了一个入队操作:
   00 +
   01 2
   02 /NodeList/0/DeviceList/0/$ns3::PointToPointNetDevice/TxQueue/Enqueue
   03 ns3::PppHeader (
   04  Point-to-Point Protocol: IP (0x0021))
   05  ns3::Ipv4Header (
   06   tos 0x0 ttl 64 id 0 offset 0 flags [none]
   07   length: 1052 10.1.1.1 > 10.1.1.2)
   08   ns3::UdpHeader (
   09    length: 1032 49153 > 9)
   10    Payload (size=1024)
  其中编号为02的部分显示了发生操作的路径:根/NodeList是NS-3维护的所有节点列表,因此/NodeList/0表示编号为0的节点;随后的/DeviceList/0表示在该节点上的编号为0的NetDivece(比如网卡);接下来的$ns3::PointToPointNetDevice指明了该NetDivece的类型;最后的TxQueue/Enqueue表示在传送队列上发生了入队操作,也就是行开头的+所表现的意义。

2、启用PCAP Tracing
  NS-3也可以生成*.pcap文件,从而可以使用诸如Wireshark、tcpdump(前文NS-3入门[1]概念引入介绍过)等工具进行分析。
 2.1)在脚本Simulator::Run()之前添加语句:
   PointToPointHelper::EnablePcapAll ("example");
  这个语句将会产生若干*.pcap文件,命名为example-<Node编号>-<NetDevice编号>.pcap,分别记录每个设备的日志。也可以使用语句***Helper::EnablePcap (filename, NodeId, DeviceId)来只产生特定设备的pcap文件:
   PointToPointHelper::EnablePcap ("example", p2pNodes.Get (0)->GetId (), 0);  //只产生example-0-0.pcap文件
 2.2)使用tcpdump在命令行阅读pcap文件:
   ~/ns-3.2.1 > tcpdump -r example-0-0.pcap -nn -tt
   reading from file second-0-0.pcap, link-type PPP (PPP)
   2.000000 IP 10.1.1.1.49153 > 10.1.2.4.9: UDP, length 1024
   2.007382 IP 10.1.2.4.9 > 10.1.1.1.49153: UDP, length 1024
 2.3)使用Wireshark等软件打开pcap文件。

=======End===================================================================


posted @ 2016-08-31 16:35  张同光  阅读(286)  评论(0编辑  收藏  举报