2. 日志文件监控与告警

任务说明

监控指定日志文件(默认 /var/log/syslog),当新增日志行中出现错误关键字(如 ERROR、CRITICAL、Traceback)时,立即发送邮件告警。脚本需持续运行,支持自定义日志路径、关键字列表与邮件接收人。

实现思路

使用 tail -f 子进程实时跟踪文件追加内容,逐行匹配关键字;命中后通过 SMTP 发送告警邮件。采用 subprocess.Popen 而非 time.sleep 轮询,确保日志产生后毫秒级响应,且不遗漏重启期间产生的日志。

完整代码

#!/usr/bin/env python3
import subprocess
import smtplib
import sys
import re
from email.mime.text import MIMEText
from email.header import Header

# ========== 配置区 ==========
LOG_FILE = "/var/log/syslog"          # 监控的日志文件
KEYWORDS = ["ERROR", "CRITICAL", "Traceback"]  # 触发告警的关键字
MAIL_SMTP = "smtp.example.com"        # SMTP服务器
MAIL_PORT = 465                       # SSL端口
MAIL_USER = "monitor@example.com"     # 发件邮箱
MAIL_PASS = "your_password"           # 邮箱授权码
MAIL_TO = ["admin@example.com"]       # 收件人列表
# ============================

def send_alert(line: str):
    """发送告警邮件,内容为匹配到的日志行"""
    subject = f"[日志告警] {LOG_FILE} 出现异常"
    body = f"时间: {__import__('time').strftime('%Y-%m-%d %H:%M:%S')}\n文件: {LOG_FILE}\n内容: {line.strip()}"
    msg = MIMEText(body, "plain", "utf-8")
    msg["Subject"] = Header(subject, "utf-8")
    msg["From"] = MAIL_USER
    msg["To"] = ", ".join(MAIL_TO)

    try:
        with smtplib.SMTP_SSL(MAIL_SMTP, MAIL_PORT) as server:
            server.login(MAIL_USER, MAIL_PASS)
            server.sendmail(MAIL_USER, MAIL_TO, msg.as_string())
        print(f"[告警已发送] {line.strip()[:80]}")
    except Exception as e:
        print(f"[邮件发送失败] {e}", file=sys.stderr)

def main():
    # 启动 tail -f 跟踪文件新增内容
    proc = subprocess.Popen(
        ["tail", "-F", LOG_FILE],
        stdout=subprocess.PIPE,
        stderr=subprocess.DEVNULL,
        universal_newlines=True,
        bufsize=1
    )
    print(f"开始监控 {LOG_FILE},关键字: {KEYWORDS}")

    # 预编译正则,忽略大小写
    pattern = re.compile("|".join(map(re.escape, KEYWORDS)), re.IGNORECASE)

    for raw_line in proc.stdout:
        line = raw_line.rstrip("\n")
        if pattern.search(line):
            send_alert(line)

if __name__ == "__main__":
    main()

运行与验证

  1. 安装依赖:仅使用 Python 3 标准库,无需 pip 安装。
  2. 修改配置:将 MAIL_SMTP、MAIL_USER、MAIL_PASS、MAIL_TO 替换为真实邮箱信息(推荐使用 465 端口 SSL)。
  3. 启动监控:sudo python3 log_monitor.py(读取 /var/log/syslog 通常需要 root 权限)。
  4. 模拟触发:另开终端执行 logger -p user.err "测试 ERROR 告警",该命令会向 syslog 写入一条含 ERROR 的新日志。
  5. 判定通过:脚本终端输出 [告警已发送],且收件邮箱收到标题为“日志告警”的邮件,内容包含触发行的完整信息。

常见问题

  • 收不到邮件:检查 SMTP 服务器地址、端口、授权码是否正确;部分邮箱需在设置中开启 SMTP 服务并生成专用授权码。
  • 监控不生效:确认脚本有日志文件读取权限;tail -F 会处理文件轮转,但若文件被删除且不再创建,进程会等待。
  • 关键字误报:修改 KEYWORDS 列表为精确匹配词,或改用正则表达式(如 r"ERROR.*timeout")以缩小范围。