1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

YAMAHAルーターからPingを実行して障害時にSLACKへ通知する

Last updated at Posted at 2025-12-16

ちょっとした端末監視が必要になった時に利用したLUAを公開します。
別途 SLACKのWebhook設定が必要です。
json.lua を取り込んでいます。

--------------------------##  設定値  ##--------------------------------

-- 実行している拠点名
branch_name = "テスト拠点"

-- 監視間隔(1 - 864000 秒)
idle_time = 30

-- ping を実行する宛先 IP アドレス
dst_tbl = {
	"192.168.100.201",
	"192.168.100.202"
}

-- ping への応答がない、または応答が回復したと判断する連続回数(1, 2 ..)
count = 6

-- 応答が回復したときにも通知を送るかどうか(送る: true / 送らない: false)
down_mail = true

-- Slack の設定
slack_tbl = {
	webhook_url = "https://hooks.slack.com/services/xxxxxxxxx/yyyyyyyyy/zzzzzzzzzzzzzzzzzzzzzzzz",
	channel = "#general",
	username = "YAMAHA LUA Notice",
	icon_emoji = ":warning:"
}

-- 通知の送信に失敗したときに出力する SYSLOG のレベル(info, debug, notice)
log_level = "notice"

----------------------##  設定値ここまで  ##----------------------------

json = require("json")

------------------------------------------------------------
-- ping を実行し、到達したかどうかを返す関数              --
------------------------------------------------------------
function ping_reach(adr)
	local rtn, str, loss
	local reach = false
	local cmd = "ping " .. adr
	local ptn = "(%d+)%.%d+%%"

	rtn, str = rt.command(cmd)
	if (rtn) and (str) then
		loss = str:match(ptn)
		if (loss) then
			loss = tonumber(loss)
			if (loss == 0) then
				reach = true
			end
		end
	end

	return rtn, reach, str
end

--------------------------------------------------------------
-- 連続何回 ping に応答がないかを示すカウンターの処理関数   --
--------------------------------------------------------------
function count_proc(t, reach, th)
	local rtn = 0

	if (not reach) then
		if (not t.flag) then
			t.ng = t.ng + 1
			if (t.ng == th) then
				rtn = 1
				t.flag = true
			end
		else
			if (t.ok > 0) then
				t.ok = 0
			end
		end
	else
		if (t.flag) then
			t.ok = t.ok + 1
			if (t.ok == th) then
				rtn = -1
				t.flag = false
				t.ng = 0
				t.ok = 0
			end
		else
			if (t.ng > 0) then
				t.ng = 0
			end
		end
	end

	return rtn
end

------------------------------------------------------------
-- Slack通知メッセージを作成する関数                      --
-- 戻り値: メッセージ文字列(状況変化がない場合は空文字) --
------------------------------------------------------------
function make_pingmsg(tbl, reach, adr, cnt, sec, down)
	local rtn
	local str = ""
	local emoji = ""

	rtn = count_proc(tbl, reach, cnt)
	-- rtn = 1: 異常発生、rtn = -1: 復旧、rtn = 0: 状況変化なし
	if (rtn < 0) then
		-- 復旧時
		if (down) then
			emoji = ":white_check_mark:"
			str = emoji .. " *Ping応答が回復しました*\n"
			str = str .. "```送信先: " .. adr .. "\n"
			str = str .. "監視間隔: " .. sec .. "秒```"
		end
	elseif (rtn > 0) then
		-- 異常発生時
		emoji = ":x:"
		str = emoji .. " *Ping応答がありません*\n"
		str = str .. "```送信先: " .. adr .. "\n"
		str = str .. "応答がなかった回数: " .. cnt .. "回 " .. "\n"
		str = str .. "監視間隔: " .. sec .. "秒```"
	end
	-- rtn = 0 の場合は str = "" のまま(状況変化なし)

	return str
end

------------------------------------------------------------
-- 連続不応答回数を記録するテーブルの初期化関数           --
------------------------------------------------------------
function init_count_tbl(n, cnt_t)
	for i = 1, n do
		cnt_t[i] = {ng = 0, ok = 0, flag = false}
	end
end

------------------------------------------------------------
-- 現在の日時を取得する関数                               --
------------------------------------------------------------
function time_stamp()
	local t

	t = os.date("*t")
	return string.format("%d/%02d/%02d %02d:%02d:%02d", 
		t.year, t.month, t.day, t.hour, t.min, t.sec)
end

------------------------------------------------------------
-- Slackに通知を送信する関数                              --
------------------------------------------------------------
function send_slack(message)
	local req_t = {}
	req_t.url = slack_tbl.webhook_url
	req_t.content_type = "application/json;charset=UTF-8"
	req_t.method = "POST"

	local req_b = {
		channel = slack_tbl.channel,
		icon_emoji = slack_tbl.icon_emoji,
		username = slack_tbl.username,
		text = message
	}

	req_t.post_text = json.encode(req_b)
	local res_t = rt.httprequest(req_t)
	
	return res_t
end

------------------------------------------------------------
-- メインルーチン                                         --
------------------------------------------------------------
local rtn, reach, str, adr
local cnt_tbl = {}

init_count_tbl(#dst_tbl, cnt_tbl)

while (true) do
	local notification_text = ""

	for i, adr in ipairs(dst_tbl) do
		rtn, reach, str = ping_reach(adr)
		if (rtn) then
			local msg = make_pingmsg(cnt_tbl[i], reach, adr, count, idle_time, down_mail)
			if msg:len() > 0 then
				notification_text = notification_text .. msg .. "\n\n"
			end
		else
			notification_text = notification_text .. 
				":warning: *Pingコマンドエラー*\n```送信先: " .. adr .. "\n" ..
				"エラー: " .. str .. "```\n\n"
		end
	end

	if (notification_text:len() > 0) then
		local full_message = string.format("*[%s - Ping監視通知] %s*\n\n%s", 
			branch_name, time_stamp(), notification_text)
		
		local res = send_slack(full_message)
		if (not res) then
			rt.syslog(log_level, "failed to send Slack notification. (pingCheck_slack.lua)")
		end
	end

	rt.sleep(idle_time)
end

過去に同じようなことを書いたときのもの。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?