如何用脚本自动分析Apache错误日志?

wen 实用脚本 1

本文目录导读:

如何用脚本自动分析Apache错误日志?

  1. 通用的Shell脚本(快速分析)
  2. Python脚本(可扩展,适合定期执行)
  3. 实时监控 + 告警(使用 tail -f + 分析脚本)
  4. 进阶:使用正则提取结构化字段并存入数据库(适合大数据)
  5. 关键注意事项

要用脚本自动分析Apache错误日志,通常可以结合Shell (awk, grep, sort)PythonGo 来实现,下面我会从最常见的场景(统计错误类型、高频IP、404请求)到更专业的风控/监控给出几种实用的脚本方法。


通用的Shell脚本(快速分析)

适用于Linux/Mac的终端,直接运行即可。

示例:分析 /var/log/apache2/error.log

#!/bin/bash
LOG_FILE="/var/log/apache2/error.log"
echo "========== Apache 错误日志分析 =========="
# 1. 错误级别统计([error], [warn], [notice])
echo ""
echo "--- 错误级别分布 ---"
grep -oP '\[\K[^\]]+' "$LOG_FILE" | sort | uniq -c | sort -rn
# 2. 出现最多的IP地址(如果日志包含IP)
echo ""
echo "--- 高频错误来源IP ---"
grep -oP 'client \K[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20
# 3. 最常见的错误消息(去掉时间前缀后)
echo ""
echo "--- 高频错误消息 (Top 20) ---"
grep -oP '\[.*?\] \[.*?\] \[.*?\] \K.*' "$LOG_FILE" | sort | uniq -c | sort -rn | head -20
# 4. 统计404错误相关(假如日志里记录)
echo ""
echo "--- 404错误统计 ---"
grep "File does not exist" "$LOG_FILE" | wc -l

运行方法
chmod +x analyze_apache_error.sh && ./analyze_apache_error.sh

优点:零依赖,快速上手。
缺点:不擅长复杂的模式匹配和告警。


Python脚本(可扩展,适合定期执行)

Python适合写更复杂的分析逻辑,比如按时间聚合、发送邮件告警、生成图表。

#!/usr/bin/env python3
import re
import sys
from collections import Counter
from datetime import datetime
LOG_FILE = "/var/log/apache2/error.log"
def parse_apache_error_line(line):
    """解析典型的Apache error日志行"""
    # 示例行: [Mon Oct 10 12:00:00.123456 2024] [php:notice] [pid 12345] [client 192.168.1.1:51234] File not found
    pattern = r'\[([^\]]+)\]'  # 提取所有中括号内容
    matches = re.findall(pattern, line)
    if len(matches) < 3:
        return None
    # 第一个是时间戳,第二个是模块:级别,后面是pid等
    timestamp_str = matches[0]
    level_module = matches[1]  # "php:notice"
    # 尝试解析标准Apache时间格式
    try:
        # 去除微秒部分
        ts_clean = re.sub(r'\..*', '', timestamp_str)
        dt = datetime.strptime(ts_clean, '%a %b %d %H:%M:%S %Y')
    except:
        dt = None
    # 提取消息部分(最后一个中括号之后)
    msg_start = line.rfind(']') + 1
    message = line[msg_start:].strip()
    # 提取client IP
    client_ip = None
    ip_match = re.search(r'client (\d+\.\d+\.\d+\.\d+)', line)
    if ip_match:
        client_ip = ip_match.group(1)
    return {
        'time': dt,
        'level': level_module,
        'client_ip': client_ip,
        'message': message
    }
def analyze_log(filepath):
    errors = []
    with open(filepath, 'r', errors='ignore') as f:
        for line in f:
            parsed = parse_apache_error_line(line)
            if parsed:
                errors.append(parsed)
    print(f"总错误行数: {len(errors)}")
    # 按错误级别统计
    level_counter = Counter(e['level'] for e in errors)
    print("\n--- 错误级别分布 ---")
    for level, count in level_counter.most_common():
        print(f"{level}: {count}")
    # 按IP统计
    ip_counter = Counter(e['client_ip'] for e in errors if e['client_ip'])
    print("\n--- 高频IP (Top 20) ---")
    for ip, count in ip_counter.most_common(20):
        print(f"{ip}: {count}")
    # 按消息聚合(忽略动态PID等信息)
    msg_counter = Counter(e['message'] for e in errors)
    print("\n--- 高频消息 (Top 20) ---")
    for msg, count in msg_counter.most_common(20):
        print(f"{count}x {msg[:100]}")
if __name__ == "__main__":
    log_path = sys.argv[1] if len(sys.argv) > 1 else LOG_FILE
    analyze_log(log_path)

运行python3 analyze_apache_error.py /var/log/apache2/error.log


实时监控 + 告警(使用 tail -f + 分析脚本)

适合生产环境:实时读取日志,当特定错误出现(如PHP Fatal Error、连接超时)时自动发邮件或推送到企业微信。

#!/usr/bin/env python3
import time
import re
import smtplib
from collections import deque
ALERT_THRESHOLD = 10   # 10次相同错误触发告警
WATCH_KEYWORDS = ['PHP Fatal error', 'Out of memory', 'Connection refused']
def send_alert(message):
    # 示例:发送邮件(需配置SMTP)
    # 实际代码可替换为 webhook 或钉钉机器人
    print(f"[ALERT] {message}")
def monitor_log(filepath, interval=5):
    """每5秒检查新增日志行"""
    with open(filepath, 'r') as f:
        # 跳到文件末尾
        f.seek(0, 2)
        error_window = deque(maxlen=100)  # 保存最近100条
        while True:
            line = f.readline()
            if not line:
                time.sleep(interval)
                continue
            # 检查是否包含敏感关键字
            for keyword in WATCH_KEYWORDS:
                if keyword in line:
                    print(f"检测到严重错误: {line.strip()}")
                    send_alert(line)
            error_window.append(line.strip())
            # 简单统计:最近100行中同一错误次数
            if len(error_window) == 100:
                counter = {}
                for e in error_window:
                    # 取消息部分作为key
                    msg = e.split(']')[-1] if ']' in e else e
                    counter[msg] = counter.get(msg, 0) + 1
                # 阈值告警
                for msg, cnt in counter.items():
                    if cnt >= ALERT_THRESHOLD:
                        send_alert(f"高频错误: {msg} 出现{cnt}次/最近100行")
if __name__ == "__main__":
    monitor_log('/var/log/apache2/error.log')

进阶:使用正则提取结构化字段并存入数据库(适合大数据)

如果日志量极大,建议:

  1. 使用 logstash + elasticsearch 或商业化Splunk。
  2. 自己写脚本将解析后的JSON字段写入 SQLitePostgreSQL,然后使用SQL进行灵活分析。

关键注意事项

场景 建议方案
临时排错 Shell + grep/awk
定期巡检/报告 Python脚本 + cron
实时告警 Python tail + webhook 或 Sentry
大规模分析 ELK / Loki / Grafana

额外提示

  • 如果日志格式是自定义的(比如加了虚拟主机名),需要调整正则表达式。
  • 当心 IP伪造:日志中的client IP也可能是反向代理IP(如Nginx),需要看 X-Forwarded-For 是否被记录。
  • 不要在生产环境用 tail -f 阻塞脚本可能导致资源泄漏,建议用 asynciologging.handlers.RotatingFileHandler 读取。

如果你能提供具体的日志格式示例想分析的目标(统计某时刻段错误数、找出导致503的URL),我可以帮你定制更精准的脚本。

抱歉,评论功能暂时关闭!