LTE Manual ——Logging(翻譯)

 

 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 (...); 宏。html

 
建立惟一的字符串標識符(一般基於文件名或文件內定義的類名),並使用宏調用註冊它,例如:
 
namespace ns3 {
NS_LOG_COMPONENT_DEFINE ("Ipv4L3Protocol");...
 
它會註冊 Ipv4L3Protocol 爲一個日誌組件。
 
(宏是精心編寫的,目的是容許其包含在命名空間 ns3 內部或外部,而且整個代碼庫的使用狀況有所不一樣,可是最初的目的是在命名空間 ns3 的外部、在文件全局範圍內註冊宏。)
 

(2)在函數和函數體中添加日誌聲明(宏調用)。node

 

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 > 10)
    {
      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
相關文章
相關標籤/搜索