diff --git a/deploy/bootstrap/bootstrap.env.example b/deploy/bootstrap/bootstrap.env.example index 4b196f6..1681325 100644 --- a/deploy/bootstrap/bootstrap.env.example +++ b/deploy/bootstrap/bootstrap.env.example @@ -23,9 +23,11 @@ TELEGRAM_BOT_TOKEN="" TELEGRAM_CHAT_ID="" # 本节点在告警里显示的名字 NODE_NAME="racknerd-la" -# 上报间隔(分钟) -MONITOR_INTERVAL_MIN=5 -# 阈值(百分比);超过即告警 +# 采集间隔(分钟) +MONITOR_INTERVAL_MIN=1 +# 连续几次采集都异常才告警(去抖)。间隔 1min × 5 次 = 持续 5 分钟异常才报。 +MONITOR_BREACH_RUNS=5 +# 阈值(百分比);超过即算一次异常采样 CPU_ALERT_PCT=80 MEM_ALERT_PCT=80 DISK_ALERT_PCT=80 @@ -33,5 +35,3 @@ DISK_ALERT_PCT=80 MONITOR_UNITS="sing-box pangolin-agent" # 出网连通探测目标 MONITOR_NET_PROBE="https://www.cloudflare.com/cdn-cgi/trace" -# 周期性"健康"心跳是否也推送(true=每次都报,false=仅异常时报) -MONITOR_SEND_OK_PULSE=false diff --git a/deploy/bootstrap/init.sh b/deploy/bootstrap/init.sh index fe2e389..1738d87 100755 --- a/deploy/bootstrap/init.sh +++ b/deploy/bootstrap/init.sh @@ -34,13 +34,13 @@ FW_ALLOW_UDP="443" TELEGRAM_BOT_TOKEN="" TELEGRAM_CHAT_ID="" NODE_NAME="$(hostname)" -MONITOR_INTERVAL_MIN=5 +MONITOR_INTERVAL_MIN=1 +MONITOR_BREACH_RUNS=5 CPU_ALERT_PCT=80 MEM_ALERT_PCT=80 DISK_ALERT_PCT=80 MONITOR_UNITS="sing-box pangolin-agent" MONITOR_NET_PROBE="https://www.cloudflare.com/cdn-cgi/trace" -MONITOR_SEND_OK_PULSE=false if [ -f "$SCRIPT_DIR/bootstrap.env" ]; then log "读取配置 $SCRIPT_DIR/bootstrap.env" @@ -199,7 +199,7 @@ MEM_ALERT_PCT=${MEM_ALERT_PCT} DISK_ALERT_PCT=${DISK_ALERT_PCT} MONITOR_UNITS="${MONITOR_UNITS}" MONITOR_NET_PROBE="${MONITOR_NET_PROBE}" -MONITOR_SEND_OK_PULSE=${MONITOR_SEND_OK_PULSE} +MONITOR_BREACH_RUNS=${MONITOR_BREACH_RUNS} MENV umask 022 sed -e "s/__INTERVAL__/${MONITOR_INTERVAL_MIN}/g" \ @@ -207,7 +207,7 @@ MENV install -m 644 "$SCRIPT_DIR/monitor/pangolin-monitor.service" /etc/systemd/system/pangolin-monitor.service systemctl daemon-reload systemctl enable --now pangolin-monitor.timer >/dev/null - log " 监控已装:每 ${MONITOR_INTERVAL_MIN} 分钟上报;发送一条启动通知" + log " 监控已装:每 ${MONITOR_INTERVAL_MIN} 分钟采集,连续 ${MONITOR_BREACH_RUNS} 次异常才告警;发送一条启动通知" /usr/local/bin/pangolin-monitor --boot || true } diff --git a/deploy/bootstrap/monitor/pangolin-monitor.sh b/deploy/bootstrap/monitor/pangolin-monitor.sh index 186a111..9eb6a35 100755 --- a/deploy/bootstrap/monitor/pangolin-monitor.sh +++ b/deploy/bootstrap/monitor/pangolin-monitor.sh @@ -2,8 +2,9 @@ # pangolin-monitor —— 节点自监控:采集 CPU/内存/磁盘/进程/网络,经 Telegram 上报。 # 由 systemd timer 定期触发(见 pangolin-monitor.timer)。配置在 /etc/pangolin-monitor.env。 # -# 阈值越界 / 受监控单元掉线 / 出网不通 → 标 🔴 并必报; -# 一切正常 → 🟢,是否推送由 MONITOR_SEND_OK_PULSE 决定(心跳)。 +# 阈值越界 / 受监控单元掉线 / 出网不通 = 一次"异常采样"; +# 连续 MONITOR_BREACH_RUNS 次异常才告警一次(去抖),恢复后发一条恢复通知。 +# 建议配合 1 分钟一次的 timer:连续 5 次 = 持续 5 分钟异常才报。 # --boot:发送一条"初始化完成"启动通知。 # # 注意:节点宕机后无法自报("不上报"类告警)需在常在线主机上跑 deadman-watch.sh(见 README)。 @@ -17,7 +18,7 @@ ENV_FILE=/etc/pangolin-monitor.env : "${NODE_NAME:=$(hostname)}" : "${CPU_ALERT_PCT:=90}"; : "${MEM_ALERT_PCT:=90}"; : "${DISK_ALERT_PCT:=85}" : "${MONITOR_UNITS:=}"; : "${MONITOR_NET_PROBE:=https://www.cloudflare.com/cdn-cgi/trace}" -: "${MONITOR_SEND_OK_PULSE:=true}" +: "${MONITOR_BREACH_RUNS:=5}" # 连续几次采样异常才告警(去抖) send_tg() { local text="$1" @@ -73,21 +74,36 @@ main() { if curl -fsS --max-time 8 "$MONITOR_NET_PROBE" >/dev/null 2>&1; then net="ok"; else net="FAIL"; alert=1; fi lines+=("出网: ${net}") - local head body ts + local ts metrics l ts="$(date -u '+%Y-%m-%d %H:%M:%SZ')" - if $boot; then - head="🟢 [${NODE_NAME}] 初始化完成 / 监控已上线" - elif [ "$alert" -eq 1 ]; then - head="🔴 [${NODE_NAME}] 异常告警" - else - head="🟢 [${NODE_NAME}] 正常" - fi - body="${head}\n${ts}\n" - printf -v body '%s\n%s\n' "$head" "$ts" - local l; for l in "${lines[@]}"; do body+="${l}"$'\n'; done + metrics="" + for l in "${lines[@]}"; do metrics+="${l}"$'\n'; done - if $boot || [ "$alert" -eq 1 ] || [ "$MONITOR_SEND_OK_PULSE" = "true" ]; then - send_tg "$body" + # ── 去抖:每次采集,但连续 MONITOR_BREACH_RUNS 次异常才告警(避免瞬时尖峰/重启误报)── + local sdir=/var/lib/pangolin-monitor cntf alertedf cnt + mkdir -p "$sdir" + cntf="$sdir/breach_count"; alertedf="$sdir/alerted" + + if $boot; then + send_tg "🟢 [${NODE_NAME}] 初始化完成 / 监控已上线"$'\n'"${ts}"$'\n'"${metrics}" + echo 0 > "$cntf"; rm -f "$alertedf" + return 0 + fi + + if [ "$alert" -eq 1 ]; then + cnt=$(( $(cat "$cntf" 2>/dev/null || echo 0) + 1 )) + echo "$cnt" > "$cntf" + # 达到连续阈值且尚未告警过 → 发一次(不重复刷屏) + if [ "$cnt" -ge "$MONITOR_BREACH_RUNS" ] && [ ! -f "$alertedf" ]; then + send_tg "🔴 [${NODE_NAME}] 异常告警(连续 ${cnt} 次采样异常)"$'\n'"${ts}"$'\n'"${metrics}" + touch "$alertedf" + fi + else + # 恢复:若此前已告警,发一条恢复通知 + if [ -f "$alertedf" ]; then + send_tg "🟢 [${NODE_NAME}] 已恢复正常"$'\n'"${ts}"$'\n'"${metrics}" + fi + echo 0 > "$cntf"; rm -f "$alertedf" fi return 0 }