纯shell日志预警脚本需聚焦关键行为:登录失败暴增、高危命令非工作时间执行、服务假死、磁盘临界、内核报错;通过路径变量、tail截取、时间窗口匹配、冷却期、聚合告警及webhook推送实现稳定落地。

用脚本做日志预警,核心是“盯住关键行为 + 及时通知 + 别被刷屏”。不需要复杂平台,纯 Shell 就能跑起来,关键是路径、权限、匹配逻辑和告警节奏这几个点卡准了。
盯住哪些日志和行为
别全盘扫描,先聚焦高频异常信号:
- 登录失败暴增:/var/log/auth.log 里 5 分钟内同一 IP 出现 ≥5 次 “Failed password”
- 高危命令执行:sudo、su、passwd、systemctl restart 等操作在非工作时间(如 00:00–06:00)集中出现
- 服务假死:mysqladmin ping 失败,或 nginx -t 返回非零状态,但进程还在
- 磁盘临界:df / | awk 'NR==2 {print $5}' | sed 's/%//' 输出 ≥90
- 内核报错:dmesg -T | tail -20 包含 “Oops”、“segfault”、“hardware error”
脚本怎么写才稳
一个能落地的预警脚本,得扛住环境差异和临时故障:
- 所有路径用变量定义,比如 LOG_FILE="/var/log/auth.log",并加存在性检查:
[[ -f "$LOG_FILE" ]] || { echo "日志文件不存在"; exit 1; } - 用
tail -n 200 "$LOG_FILE" | grep ...替代全文 grep,避免越扫越慢;配合date -d '5 minutes ago' '+%b %d %H:%M'截取时间窗口 - 匹配结果存临时文件,再用
wc -l统计次数,防止空行误判 - 加
set -e让出错即停,但对非致命命令(如邮件发不出)用|| true容错 - 每步输出带时间戳:
echo "$(date '+%F %T') INFO: Checking SSH failures..." >> /var/log/alert.log
告警别乱发,得管得住
没人想半夜被 50 条重复邮件吵醒:
- 同一类告警设冷却期,例如用
touch /tmp/ssh_alert_lock && sleep 300 && rm /tmp/ssh_alert_lock控制 5 分钟内只报一次 - 聚合同类事件:把 3 个不同 IP 的失败登录合并成一条消息,“检测到 3 个IP暴力尝试SSH(192.168.1.100/101/102)”
- 优先走企业微信或钉钉 Webhook,比邮件快且支持免打扰;curl 发送示例:
curl -X POST -H "Content-Type: application/json" -d '{"msgtype":"text","text":{"content":"【告警】磁盘使用超90%:$(df / | awk '\''NR==2 {print $5}'\'')"}}' $WEBHOOK_URL - 严重事件(如 root 被 sudo 提权)才触发短信或电话,走第三方网关 API
定时执行与日志留存
脚本写完不等于自动化,调度和归档才是闭环:
- 放进 crontab 用绝对路径,重定向必须完整:
*/3 * * * * /opt/scripts/log-alert.sh >> /var/log/alert.log 2>&1 - 脚本开头加
cd "$(dirname "$0")"避免路径错乱;调用命令尽量写全路径,如/usr/bin/grep - 日志每天轮转,加一行清理:
find /var/log/alert.log.* -mtime +7 -delete,防止占满磁盘 - 首次部署后手动执行一次,检查权限(脚本需 +x)、mailx 或 curl 是否可用、Webhook 地址是否通











