1. 背景
在 512MB 内存、256MB 闪存的路由器上面跑了好些年的 telegraf 网络监测,但是由于 telegraf 是 Go 写的,二进制文件体积巨大(~200MB),我甚至需要在路由器上面插个 U 盘来存储这个二进制。为了降低存储和运行的开销,一直设想着用 shell 脚本来做网络监测,毕竟我也只用到了 ICMP 和 DNS 的监测而已。
(此文成于 2026 年,因懒惰拖延至今,今日 AI 甚妙,遂着手了结此未竟之事)
2. telegraf 原配置及对应的 shell 脚本
- telegraf.conf
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
## Input plugins [agent] interval = "60s" flush_interval = "60s" [[inputs.ping]] urls = ["baidu.com", "223.5.5.5", "8.8.8.8", "1.1.1.1"] count = 40 timeout = 2 ping_interval = 1.0 deadline = 50 method = "native" [[inputs.dns_query]] timeout = 3 record_type = "A" servers = ["10.0.0.1"] domains = ["google.com", "twitter.com", "baidu.com", "aliyun.com"] [[outputs.http]] url = "https://prometheus-prod-18-prod-ap-southeast-0.grafana.net/api/prom/push" data_format = "prometheusremotewrite" username = "XXXXXX" password = "XXXXXX" [outputs.http.headers] Content-Type = "application/x-protobuf" Content-Encoding = "snappy" X-Prometheus-Remote-Write-Version = "0.1.0" |
- telegraf.sh
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
#!/bin/sh URL="https://prometheus-prod-18-prod-ap-southeast-0.grafana.net/api/v1/push/influx/write" AUTH="XXXXXX:XXXXXX=" HOST=$(uci -q get system.@system[0].hostname || hostname 2>/dev/null || echo "openwrt") PING_URLS="baidu.com 223.5.5.5 8.8.8.8 1.1.1.1" DNS_DOMAINS="google.com twitter.com baidu.com aliyun.com" DNS_SERVERS="10.0.0.1" probe_ping() { ping -c 40 -W 2 -i 1 -w 50 "$1" 2>/dev/null | awk -v u="$1" -v h="$HOST" ' /transmitted/ { tx=$1; rx=$4 for(i=1;i<=NF;i++) if($i~/%/) { sub(/%/,"",$i); loss=$i } } /min\/avg\/max/ { split($4, a, "/") } END { if (tx > 0) { printf "ping,url=%s,host=%s packets_transmitted=%d,packets_received=%d,percent_packet_loss=%s,result_code=%d", u, h, tx, rx, (loss!=""?loss:100), (rx>0?0:1) if (a[2] != "") printf ",minimum_response_ms=%s,average_response_ms=%s,maximum_response_ms=%s", a[1], a[2], a[3] if (a[4] != "") printf ",standard_deviation_ms=%s", a[4] print "" } else { printf "ping,url=%s,host=%s packets_transmitted=0,packets_received=0,percent_packet_loss=100,result_code=2\n", u, h } }' } probe_dns() { dig @"$1" "$2" A +time=3 +tries=1 +stats 2>/dev/null | awk -v s="$1" -v d="$2" -v h="$HOST" ' /status:/ { split($0, a, "status: "); split(a[2], b, ","); st=b[1] } /Query time:/ { qt=$4 } END { if (qt != "") { rc = (st == "NOERROR") ? 0 : 1 printf "dns_query,server=%s,domain=%s,record_type=A,rcode=%s,result=%s,host=%s query_time_ms=%s,result_code=%d\n", s, d, (st?st:"SERVFAIL"), (rc==0?"success":"error"), h, qt, rc } else { printf "dns_query,server=%s,domain=%s,record_type=A,rcode=TIMEOUT,result=timeout,host=%s query_time_ms=3000,result_code=2\n", s, d, h } }' } while true; do T_START=$(date +%s) { for u in $PING_URLS; do probe_ping "$u" & done for d in $DNS_DOMAINS; do probe_dns "$DNS_SERVERS" "$d" & done wait } | curl -sS -m 10 -u "$AUTH" -X POST "$URL" --data-binary @- >/dev/null 2>&1 SLEEP=$(( 60 - ($(date +%s) - T_START) )) [ "$SLEEP" -gt 0 ] && sleep "$SLEEP" done |