Skip to content

Instantly share code, notes, and snippets.

@dolpen
Last active December 9, 2023 06:13
Show Gist options
  • Save dolpen/6577ad52d5e35a7a2811 to your computer and use it in GitHub Desktop.
Save dolpen/6577ad52d5e35a7a2811 to your computer and use it in GitHub Desktop.
文字コードはSJIS、改行コードはCRLFでの動作を確認しました
--[[
# ルーターメトリック収集スクリプト
## 概要
定期的にルーターのリソースを監視して、プロキシ経由で Mackerel に下記メトリック情報を送信します
* CPU 使用率(整数)
* メモリ使用率(整数)
* 筐体内温度(整数)
* 各LANインターフェースの利用帯域(目安)
## 前提
RT(X)系のLuaスクリプト内で利用可能な rt.httprequest 命令には以下の注意点があります
* https をサポートしていない
* リクエストヘッダのカスタマイズや追加が不可能
このため、このスクリプトの動作には下記の目的で http プロキシを用意する必要があります
* http -> https のプロキシ
* リクエストヘッダへ Mackerel API キー (X-Api-Key) を追加する
http プロキシ側にキー情報を持ち、無条件でAPIリクエストが可能なため、プロキシはローカルネットワーク内に立てることを強くお勧めします
## 導入手順
* このファイルの設定値を適切に変更し RTFS か外部メモリに保存してください
* lua (Luaスクリプトファイル名) でスクリプトを実行してください
* このスクリプトは無限ループします、
* show status lua でスクリプトの実行IDを確認してください
* 停止するときは terminate lua (実行ID) コマンドを実行してください
* schedule at 1 startup * lua (Luaスクリプトファイル名) で、ルーター起動時の自動実行をスケジューリングできます
## ノート
* カスタムメトリックのキー名変更はハードウェアリソース情報テーブル周辺を見ていい感じにおねがいします
* 対象のルーターによっては本体温度など取得できない情報がありますが
その際はハードウェアリソース情報テーブルでコメントアウトしてください
* YamahaのLuaサンプルページからいろいろ持ってくればネットワーク帯域なども収集可能ですが
いろいろややこしくなるので各自いい感じにおねがいします
]]
-------------------------- ## 設定値 ##--------------------------------
-- 監視間隔(1 - 864000 秒)
-- 5分以上の間隔にすると Mackerel の Connectivity アラートが上がるので監視から外すか5分未満にする
idle_time = 180
-- os.time と unix time のオフセット(秒)
os_time_offset = 315532800;
-- Mackerel API に向けた http プロキシのエンドポイントURL
proxy_tsdb = "http://********************/api/v0/tsdb"
-- Mackerel で実行端末用に作成した hostId
-- @see http://help-ja.mackerel.io/entry/spec/api/v0#host-create
host = "********************"
-- カスタムメトリックのプレフィックス
name_prefix = "custom.rtx."
-- ハードウェアリソース定義とメトリック名
res_table = {
cpu_5sec = { pattern = "(%d+)%%%(5sec%)", name = name_prefix .. "cpu.5sec" },
cpu_1min = { pattern = "(%d+)%%%(1min%)", name = name_prefix .. "cpu.1min" },
cpu_5min = { pattern = "(%d+)%%%(5min%)", name = name_prefix .. "cpu.5min" },
memory = { pattern = "(%d+)%% used", name = name_prefix .. "memory.usage" },
packet_small = { pattern = "(%d+)%%%(small%)", name = name_prefix .. "packetbuff.small" },
packet_middle = { pattern = "(%d+)%%%(middle%)", name = name_prefix .. "packetbuff.middle" },
packet_large = { pattern = "(%d+)%%%(large%)", name = name_prefix .. "packetbuff.large" },
packet_huge = { pattern = "(%d+)%%%(huge%)", name = name_prefix .. "packetbuff.huge" },
temp = { pattern = "筐体内温度%(℃%): (%d+)", name = name_prefix .. "temperature.body" }
}
-- LAN3まであるなら3
max_lan_interface = 3
-- LANインターフェースのメトリックのプレフィックス
lan_metric_name_prefix = {
send = name_prefix .. "send.lan",
recv = name_prefix .. "recv.lan"
}
---------------------- ## 設定値ここまで ##----------------------------
------------------------------------------------------------
-- ルーターのハードウェアリソースの使用状況を取得する関数 --
-- サンプルからありがたく拝借して改変
-- @return [metricValue]
------------------------------------------------------------
function rt_res_status()
local rtn, str
local cmd = "show environment"
local rtn_table = {}
rtn, str = rt.command(cmd)
if (rtn) and (str) then
for k, v in pairs(res_table) do
local value = str:match(v.pattern)
if (value) then
table.insert(rtn_table, make_metric_value(v.name, value))
end
end
end
return rtn, rtn_table
end
------------------------------------------------------------
-- LANインターフェースから送受信オクテット数を取得する関数 --
-- サンプルからありがたく拝借、改造
------------------------------------------------------------
function lan_load_info(interface_num)
local rtn, str, send, recv
local cmd = "show status lan" .. tostring(interface_num)
local t = {}
local ptn = "%((%d+)%s+オクテット"
rtn, str = rt.command(cmd)
if (rtn) and (str) then
local n = 1
for w in string.gmatch(str, ptn) do
t[n] = w
n = n + 1
end
end
if (t[1]) then
send = tonumber(t[1])
end
if (t[2]) then
recv = tonumber(t[2])
end
return rtn, send, recv
end
------------------------------------------------------------
-- <metricValue> の name と value のみを持った テーブルを作る --
-- { name , value }
------------------------------------------------------------
function make_metric_value(name, value)
local mv = {}
mv.name = name;
mv.value = tostring(value);
return mv;
end
------------------------------------------------------------
-- Mackerel 向けの MetricValue API Post 文字列生成 --
-- @see http://help-ja.mackerel.io/entry/spec/api/v0#metric-value-post
------------------------------------------------------------
function make_post_text(host, time, metric_table)
local a = "";
for k, v in pairs(metric_table) do
a = a .. string.format("{\"hostId\":\"%s\",\"name\":\"%s\",\"value\":%d,\"time\":%d}", host, v.name, v.value, time) .. ","
end
return "[" .. string.sub(a, 1, -2) .. "]"
end
------------------------------------------------------------
-- メインルーチン --
------------------------------------------------------------
-- HTTPリクエスト用テーブル
local http_req_table = {
url = proxy_tsdb,
method = "POST",
content_type = "application/json"
}
local lan_state_table = {
{ send = 0, recv = 0 },
{ send = 0, recv = 0 },
{ send = 0, recv = 0 }
}
local rtn, str, now, rtn_table, send, recv
while (true) do
local metric_table = {}
-- 1.ハードウェアリソースの取得、成功すればメトリックテーブルに追加
rtn, rtn_table = rt_res_status(rt_res_tbl)
if (rtn) then
for i, v in ipairs(rtn_table) do
table.insert(metric_table, v)
end
end
-- 2.LAN インターフェースの取得、取得できたものだけ
for k = 1, max_lan_interface do
rtn, send, recv = lan_load_info(k)
if (rtn) and (send) and (recv) then
if (lan_state_table[k].send <= 0) then
lan_state_table[k].send = send;
end
if (lan_state_table[k].recv <= 0) then
lan_state_table[k].recv = recv;
end
table.insert(metric_table,
make_metric_value(lan_metric_name_prefix.send .. tostring(k),
(send - lan_state_table[k].send) * 8 / idle_time))
table.insert(metric_table,
make_metric_value(lan_metric_name_prefix.recv .. tostring(k),
(recv - lan_state_table[k].recv) * 8 / idle_time))
lan_state_table[k].send = send;
lan_state_table[k].recv = recv;
end
end
-- 3.現在時刻をエポック秒にする
now = os.time() + os_time_offset
-- リクエストを発行
http_req_table.post_text = make_post_text(
host,
now,
metric_table
)
rt.httprequest(http_req_table)
-- http_res_table = rt.httprequest(http_req_table)
-- print(http_req_table.post_text)
-- print(http_res_table.body)
rt.sleep(idle_time)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment