Programming Tips blog

テキトーにTIPSを紹介します

ラズパイ + Python + ping + RRDtoolでネットワーク監視

 ネットワーク監視のため、pingで対象機器の応答時間とNG個数、NG割合を測定します。
 python3-rrdtoolを使う方法もあるようなのですが、ここでは原始的にsubprocessを使います。

主なハードウェア

主なソフトウェア

RRDtoolインストール

 RRDtoolをインストールします。

apt install rrdtool

RRDtoolデータベース作成

 RRDtoolデータベースを作成します。

応答時間

rrdtool create /home/user/rrdtool/pingtime.rrd --step 10 DS:pingtime:GAUGE:600:U:U RRA:AVERAGE:0.5:30:69120 RRA:MAX:0.5:30:69120 RRA:MIN:0.5:30:69120

NG個数

rrdtool create /home/user/rrdtool/pingng.rrd --step 300 DS:pingng:GAUGE:600:U:U RRA:MAX:0.5:1:69120

NG割合

rrdtool create /home/user/rrdtool/pingngratio.rrd --step 300 DS:pingngratio:GAUGE:600:U:U RRA:MAX:0.5:1:69120

Pythonプログラム

 Pythonプログラムです。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

##########
# インポート
##########

import datetime
import subprocess
import time


##########
# メイン
##########

# メイン関数
# 引数:なし
# 返値:なし
def main():
	# 変数定義、初期化
	counter = 0
	all_counter = 0
	
	# コマンド作成
	cmd = ["ping", "-c", "1", "-W", "1", "192.168.1.254"]
	
	# ping試し打ち(NG回避)
	for i in range(10):
		subprocess.run(cmd)
		time.sleep(1)
	
	# ping NGカウンタリセット時刻
	m_expire = datetime.datetime.now()
	minute = (int(m_expire.minute / 5) + 1) * 5
	if 59 < minute:
		expire = datetime.datetime(m_expire.year, m_expire.month, m_expire.day, m_expire.hour) + datetime.timedelta(hours=1)
	else:
		expire = datetime.datetime(m_expire.year, m_expire.month, m_expire.day, m_expire.hour, minute)
	
	try:
		while True:
			# ping NGカウンタリセット時刻を超過していた場合
			if expire <= datetime.datetime.now():
				# カウンタ値を記録する
				subprocess.run(["rrdtool", "update", "/home/user/rrdtool/pingng.rrd", "-t", "pingng", str(int(expire.timestamp())) + ":" + str(counter)])
				subprocess.run(["rrdtool", "update", "/home/user/rrdtool/pingngratio.rrd", "-t", "pingngratio", str(int(expire.timestamp())) + ":" + str(counter * 100.0 / all_counter)])
				
				# カウンタをリセットする
				counter = 0
				all_counter = 0
				# ping NGカウンタリセット時刻を更新する
				m_expire = datetime.datetime.now()
				minute = (int(m_expire.minute / 5) + 1) * 5
				if 59 < minute:
					expire = datetime.datetime(m_expire.year, m_expire.month, m_expire.day, m_expire.hour) + datetime.timedelta(hours=1)
				else:
					expire = datetime.datetime(m_expire.year, m_expire.month, m_expire.day, m_expire.hour, minute)
			
			# ping実行(stdout:保存、stderr:破棄)
			response = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
			# カウンタを増分する
			all_counter += 1
			# ping結果
			result = response.stdout.decode("utf-8")
			# ping OKの場合
			if "1 received" in result:
				idx = result.find("rtt")
				avg = result[idx:].split("/")[4]
				print(avg)
				subprocess.run(["rrdtool", "update", "/home/user/rrdtool/pingtime.rrd", "-t", "pingtime", "N:" + avg])
			# ping NGの場合
			else:
				print("PING NG")
				# ping NGカウンタを増分する
				counter += 1
			
			# 休む
			time.sleep(1)
	except KeyboardInterrupt:
		pass
	
	return


# メイン関数
# 備考:main()に投げるだけ
if __name__ == "__main__":
	main()

cron設定

 5分毎にグラフ作成するcronです。

応答時間

1-56/5 * * * * /usr/bin/rrdtool graph /home/user/public_html/rrdtool/pingtime.png --title "ping RESPONSE TIME - 192.168.1.254 [ms]" --height 200 --width 800 --lower-limit 100 --upper-limit 500 --rigid --start end-50h --x-grid HOUR:1:HOUR:6:HOUR:6:0:"\%m/\%d \%H:\%M" --slope-mode DEF:px=/home/user/rrdtool/pingtime.rrd:pingtime:MAX DEF:pa=/home/user/rrdtool/pingtime.rrd:pingtime:AVERAGE DEF:pn=/home/user/rrdtool/pingtime.rrd:pingtime:MIN LINE2:px#FF0000:"5min(Max)" GPRINT:px:LAST:"Cur\: \%.1lf [ms]" GPRINT:px:MIN:"Min\: \%.1lf [ms]" GPRINT:px:MAX:"Max\: \%.1lf [ms]\n" LINE2:pa#00FF00:"5min(Ave)" GPRINT:pa:LAST:"Cur\: \%.1lf [ms]" GPRINT:pa:MIN:"Min\: \%.1lf [ms]" GPRINT:pa:MAX:"Max\: \%.1lf [ms]\n" LINE2:pn#0000FF:"5min(Min)" GPRINT:pn:LAST:"Cur\: \%.1lf [ms]" GPRINT:pn:MIN:"Min\: \%.1lf [ms]" GPRINT:pn:MAX:"Max\: \%.1lf [ms]" TEXTALIGN:left

NG個数

1-56/5 * * * * /usr/bin/rrdtool graph /home/user/public_html/rrdtool/pingng.png --title "ping NG count - 192.168.1.254" --height 200 --width 800 --start end-50h --x-grid HOUR:1:HOUR:6:HOUR:6:0:"\%m/\%d \%H:\%M" --slope-mode DEF:pingngmax=/home/user/rrdtool/pingng.rrd:pingng:MAX LINE2:pingngmax#FF0000:"5min" GPRINT:pingngmax:LAST:"Cur\: \%.0lf " GPRINT:pingngmax:MIN:"Min\: \%.0lf " GPRINT:pingngmax:MAX:"Max\: \%.0lf" TEXTALIGN:left

NG割合

1-56/5 * * * * /usr/bin/rrdtool graph /home/user/public_html/rrdtool/pingngratio.png --title "ping NG RATIO [\%] - 192.168.1.254" --height 200 --width 800 --start end-50h --x-grid HOUR:1:HOUR:6:HOUR:6:0:"\%m/\%d \%H:\%M" --slope-mode DEF:pingngratiomax=/home/user/rrdtool/pingngratio.rrd:pingngratio:MAX LINE2:pingngratiomax#FF0000:"5min" GPRINT:pingngratiomax:LAST:"Cur\: \%.2lf [\%\%] " GPRINT:pingngratiomax:MIN:"Min\: \%.2lf [\%\%] " GPRINT:pingngratiomax:MAX:"Max\: \%.2lf [\%\%]" TEXTALIGN:left