用python3分析PING log

最近家裏WiFi網絡有點不穩定。因而用PING來檢查是否真的有掉包狀況。Windows的PING在有丟包的狀況,會隨機出現卡住的狀況,即不更新PING的反饋,直接到你按ctrl+c,它纔會繼續。因而用Linux的PING來試試。我用的是一臺Fedora,直接接到AP所鏈接的上行以太網口,先確認以太網口是否有問題。python

$ uname -a
Linux Fedora 5.3.7-301.fc31.x86_64 #1 SMP Mon Oct 21 19:18:58 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

在shell輸入PING命令,打開O選項,提示丟包(默認狀況下,不提示丟包,你只能經過不連續的icmp序號發現丟包,不方便),打開D選項,即提供時間戳。利用tee命令在shell獲取ping的返回的同時,存到一個文本文件,用來分析:正則表達式

$ ping 192.168.1.1 -OD | tee ping.log

ping.log的內容大概是這樣的:shell

PING 192.168.2.1 (192.168.2.1) 56(84) bytes of data.
[1582125725.624008] 64 bytes from 192.168.2.1: icmp_seq=1 ttl=64 time=0.497 ms
[1582125726.627403] 64 bytes from 192.168.2.1: icmp_seq=2 ttl=64 time=0.551 ms
[1582125727.651623] 64 bytes from 192.168.2.1: icmp_seq=3 ttl=64 time=0.668 ms

咱們將用python3或GNU awk腳本(兩者的效果至關)來分析這個log,統計丟包率、環回時延等指標。先把最終的分析結果呈上來:網絡

--- 192.168.2.1 ping statistics ---
34706 packets transmitted, 34702 received, 0.01% packet loss, time 9 hours 3129 seconds.
rtt min/avg/max=0.307/0.645/1024.000 ms

1. python3

獲取目標主機地址:函數

try:
            with open(log_file_name, 'r') as f:
                line_list = f.readlines()
                lines = ''.join(line_list)

                host_match = re.search(r'PING\s+(\d+\.\d+\.\d+\.\d+)', line_list[0])
                self._dst_host = host_match.group(1) if host_match else None

獲取第1個和最後1個icmp序號,這樣就能夠知道一共發送了多少個包,計算丟包率的時候做爲分母:code

ts_match = re.search(r'\[(\d+\.\d+)\][\w\.\s:]+\s+icmp_seq=(\d+)', lines)
                self._ts_begin =  float(ts_match.group(1))
                self._icmp_seq_begin = int(ts_match.group(2))
                ts_match = re.search(r'\[(\d+\.\d+)\][\w\.\s:]+\s+icmp_seq=(\d+)', \
                        line_list[-1])

                self._ts_end = float(ts_match.group(1))
                self._icmp_seq_end = int(ts_match.group(2))

正常響應的ICMP reply,特徵是有rtt時間,若是是丟包,則是報告"no answer yet"。咱們依靠正常返回的字符串格式,提取全部的正常返回,數一數個數,接下來計算丟包率用得上。ip

self._match_list = re.findall(\
                        r'\[(\d+\.\d+)\].*?:\s+icmp_seq=(\d+).*?time=(\d+\.?\d+)', lines)

re.findall返回的是一個list of tuple,由於咱們在正則表達式裏定義了3個組。將它轉化爲3個list。字符串

raw_ts_tuple, raw_icmp_seq_tuple, raw_rtt_tuple =  \
                        zip(*self._match_list)
                self._ts_list = list(map(float, list(raw_ts_tuple)))
                self._icmp_seq_list = list(map(int, list(raw_icmp_seq_tuple)))
                self._rtt_list = list(map(float, list(raw_rtt_tuple)))`

計算丟包率等統計量。it

duration = self._ts_end - self._ts_begin
            total_packets = self._icmp_seq_end - self._icmp_seq_begin + 1
            received_packets = len(self._icmp_seq_list) 
            print('---%s  ping stattistics ---' % (self._dst_host))
            print('%d packets transmitted, %d received, %.2f%% packet loss, time %d hours %d seconds.' % \
                    (total_packets, \
                    received_packets, \
                    100 - received_packets/total_packets * 100, \
                    (duration) // 3600, \
                    (duration) % 3600 ) )

            print('rtt min/avg/max=%.3f/%.3f/%.3f ms' % ( min(self._rtt_list) ,\
                    mean(self._rtt_list), max(self._rtt_list)))

PING了一個晚上。丟包率是萬分之一,應該說挺穩定的。下次接上WLAN AP再來PING看看,可否發現丟包。io

對於格式化的文本分析,awk也是很應景的。因而用awk也來試試。

2. awk

$ awk -f ping.awk ping.log

將得出以下結果:

--- 192.168.2.1 ping statistics ---
34706 packets transmitted, 34702 received, 0.01% packet loss, time 9 hours 3129 seconds.
rtt min/avg/max=0.307/0.645/1024.000 ms

ping.awk的內容下面來解釋。初始化一下變量:

BEGIN {
    lineno=0;
    rtt_sum=0.0;
    pkt_count_recv = 0;
    is_init="False";
}

在awk, $ n就是第n個字符串,字符串之間的分隔符默認是空格,也能夠用選項來自定義分隔符。$1就是第1個字符串[1582125725.624008],$6是icmp_seq=1。

ts = $1;
    icmp_seq = $6;
    rtt = $8;

這些字符串有些多餘的東東,好比[1582125725.624008],方括號是多餘的;icmp_seq=1,icmp=是多餘的。用gsub函數把多餘的東東去掉。

gsub(/^\[/, "", ts);
    gsub(/$\]/, "", ts);
    gsub(/[a-z_]+=/, "", icmp_seq);

咱們剛纔也提到,ICMP reply正常的標誌是有"time="字符串,若是能用sub函數把它找出來,說明是一個正常的ICMP reply。

is_answer = sub(/time=/,"", rtt);

咱們統計這些正常的ICMP reply, 平均rtt=rtt累加 / ICMP reply個數。

if (is_answer>0) {
        if (is_init=="False") {
                rtt_min = rtt
                rtt_max = rtt
                is_init="True"
        }
        rtt += 0.0
        rtt_sum += rtt;
        pkt_count_recv ++;
        if (rtt_min>rtt) rtt_min=rtt;
        if (rtt_max<rtt) rtt_max=rtt;
    }

在END段處理咱們剛纔統計的東東

END {
    pkt_count_trans = the_icmp_seq["end"]-the_icmp_seq["begin"]+1; 
    loss_ratio = (pkt_count_trans-pkt_count_recv) / pkt_count_trans * 100;
    duration = (the_ts["end"] - the_ts["begin"]);
    time_seconds = duration % 3600;
    time_hours = (duration - time_seconds)/3600;
    printf("--- %s ping statistics ---\n", dest_host);
    printf("%d packets transmitted, %d received, %.2f%% packet loss, time %d hours %d seconds.\n",\
        pkt_count_trans, pkt_count_recv, loss_ratio, time_hours, time_seconds);
    printf("rtt min/avg/max=%.3f/%.3f/%.3f ms\n", rtt_min, (rtt_sum / pkt_count_recv), rtt_max);
}
相關文章
相關標籤/搜索