最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python實(shí)現(xiàn)自動(dòng)分析Windows事件日志

 更新時(shí)間:2026年05月07日 08:10:30   作者:紅魔Y  
Windows事件日志是排障的第一現(xiàn)場(chǎng),本文教你用 Python 的 win32evtlog 模塊和 PowerShell 橋接方案,自動(dòng)化收集過(guò)濾和分析事件日志,感興趣的小伙伴可以了解下

凌晨 3 點(diǎn),告警響了——服務(wù)器無(wú)響應(yīng)。你 SSH 上去一看,日志文件幾 GB,手動(dòng)翻到天亮也沒(méi)找到原因。如果我告訴你,Python 3 分鐘就能搞定呢?

為什么需要自動(dòng)化日志分析?

Windows 事件日志(Event Log)記錄了系統(tǒng)中幾乎所有重要事件:

日志類型內(nèi)容重要性
System系統(tǒng)啟動(dòng)/關(guān)閉、驅(qū)動(dòng)錯(cuò)誤、服務(wù)狀態(tài)?????
Application應(yīng)用程序崩潰、.NET 異常????
Security登錄嘗試、權(quán)限變更、審計(jì)事件?????
Setup系統(tǒng)更新、補(bǔ)丁安裝???
ForwardedEvents從其他機(jī)器轉(zhuǎn)發(fā)的事件????

手動(dòng)用"事件查看器"(Event Viewer)翻日志的痛點(diǎn):

  • 日志量巨大,一次藍(lán)屏可能產(chǎn)生上萬(wàn)條事件
  • 無(wú)法跨多臺(tái)機(jī)器關(guān)聯(lián)分析
  • 沒(méi)有智能過(guò)濾,關(guān)鍵信息淹沒(méi)在噪音中
  • 無(wú)法做趨勢(shì)分析和預(yù)警

方案對(duì)比:三種讀取方式

  • 方案一:win32evtlog(速度最快,但需要 pywin32)
  • 方案二:PowerShell Get-WinEvent(無(wú)需額外庫(kù))
  • 方案三:wevtutil 命令行(最通用,但解析麻煩)

我們?nèi)N都講,但推薦方案一(win32evtlog)用于生產(chǎn)環(huán)境。

方案一:win32evtlog 直接讀?。ㄍ扑])

import win32evtlog
import win32evtlogutil
import datetime

# 事件級(jí)別常量
EVENT_LEVELS = {
    1: "CRITICAL",
    2: "ERROR",
    3: "WARNING",
    4: "INFORMATION",
    5: "VERBOSE",
}

def read_event_log(
    log_name="System",
    server=None,
    count=100,
    level=None,
    event_id=None,
    source=None
):
    """
    讀取 Windows 事件日志
    log_name: System / Application / Security / Setup
    server: 遠(yuǎn)程計(jì)算機(jī)名(None=本地)
    count: 最多讀取條數(shù)
    level: 過(guò)濾級(jí)別 1-5
    """
    hand = win32evtlog.OpenEventLog(server, log_name)
    flags = (
        win32evtlog.EVENTLOG_BACKWARDS_READ
        | win32evtlog.EVENTLOG_SEQUENTIAL_READ
    )

    events = []
    total = 0
    read_count = 0

    while True:
        events_batch = win32evtlog.ReadEventLog(hand, flags, 0)
        if not events_batch:
            break

        for event in events_batch:
            total += 1
            evt_level = event.EventType  # 1=Error, 2=Warning, 4=Info

            # 過(guò)濾條件
            if level and evt_level != level:
                continue
            if event_id and event.EventID & 0xFFFF != event_id:
                continue
            if source and event.SourceName != source:
                continue

            # 解析時(shí)間
            time_generated = event.TimeGenerated.Format()
            # 轉(zhuǎn)為 datetime
            evt_time = datetime.datetime.strptime(
                time_generated, "%m/%d/%Y %H:%M:%S"
            )

            record = {
                "time": evt_time,
                "level": EVENT_LEVELS.get(evt_level, f"UNKNOWN({evt_level})"),
                "source": event.SourceName,
                "event_id": event.EventID & 0xFFFF,
                "computer": event.ComputerName,
                "message": win32evtlogutil.SafeFormatMessage(event, log_name),
            }
            events.append(record)
            read_count += 1

            if read_count >= count:
                break

        if read_count >= count:
            break

    win32evtlog.CloseEventLog(hand)
    return events


# 示例:讀取最近 50 條系統(tǒng)錯(cuò)誤
errors = read_event_log("System", count=50, level=1)
print(f"發(fā)現(xiàn) {len(errors)} 條系統(tǒng)錯(cuò)誤:\n")
for e in errors[:10]:
    print(f"[{e['time']}] {e['level']} | {e['source']} | "
          f"EventID: {e['event_id']}")
    print(f"  {e['message'][:120]}...")
    print()

方案二:PowerShell 橋接(無(wú)需安裝 pywin32)

如果你的環(huán)境不方便安裝 pywin32,可以通過(guò) PowerShell 橋接:

import subprocess
import json

def get_events_via_powershell(
    log_name="System",
    max_events=100,
    level=None,
    start_time=None
):
    """
    通過(guò) PowerShell Get-WinEvent 讀取事件日志
    返回結(jié)構(gòu)化字典列表
    """
    # 構(gòu)建 PowerShell 命令
    filter_parts = [f"LogName='{log_name}'"]
    if level:
        level_map = {1: 1, 2: 2, 3: 3, 4: 4}  # Error, Warning, Info
        filter_parts.append(f"Level={level_map.get(level, level)}")
    if start_time:
        filter_parts.append(f"StartTime='{start_time}'")

    filter_xml = f"<QueryList><Query Id='0' Path='{log_name}'>" \
                 f"<Select>*[{f' and '.join(filter_parts)}]</Select>" \
                 f"</Query></QueryList>"

    ps_cmd = f'''
    Get-WinEvent -FilterXml "{filter_xml}" -MaxEvents {max_events} |
    Select-Object TimeCreated, LevelDisplayName, ProviderName,
                  Id, MachineName, Message |
    ConvertTo-Json -Depth 3
    '''

    result = subprocess.run(
        ["powershell", "-Command", ps_cmd],
        capture_output=True, text=True, timeout=60
    )

    if result.returncode != 0:
        print(f"PowerShell 錯(cuò)誤: {result.stderr}")
        return []

    try:
        data = json.loads(result.stdout)
        if isinstance(data, dict):
            data = [data]
        return data
    except json.JSONDecodeError:
        return []


# 示例:獲取最近的系統(tǒng)錯(cuò)誤
events = get_events_via_powershell("System", max_events=20, level=1)
for e in events:
    print(f"[{e['TimeCreated']}] {e['LevelDisplayName']} | "
          f"{e['ProviderName']} | ID: {e['Id']}")

方案三:wevtutil 命令行(最通用)

def export_events_wevtutil(
    log_name="System",
    output_file="events.xml"
):
    """
    使用 wevtutil 導(dǎo)出事件日志為 XML
    """
    cmd = f'wevtutil epl {log_name} "{output_file}"'

    result = subprocess.run(
        cmd, shell=True, capture_output=True, text=True
    )

    if result.returncode == 0:
        print(f"日志已導(dǎo)出到: {output_file}")
        return True
    else:
        print(f"導(dǎo)出失敗: {result.stderr}")
        return False

def query_events_wevtutil(log_name="System", count=50):
    """
    使用 wevtutil 查詢事件(純文本格式)
    """
    cmd = f'wevtutil qe {log_name} /c:{count} /f:text /rd:true'

    result = subprocess.run(
        cmd, shell=True, capture_output=True, text=True
    )
    return result.stdout

實(shí)戰(zhàn)一:日志異常檢測(cè)引擎

手動(dòng)翻日志效率太低,我們需要一個(gè)能自動(dòng)發(fā)現(xiàn)異常的引擎:

from collections import Counter, defaultdict
from datetime import datetime, timedelta
import re

class EventLogAnalyzer:
    """Windows 事件日志智能分析引擎"""

    # 已知的關(guān)鍵事件 ID 和含義
    KNOWN_EVENTS = {
        # 系統(tǒng)崩潰相關(guān)
        41: "內(nèi)核電源錯(cuò)誤(意外斷電/藍(lán)屏)",
        1001: "Windows Error Reporting 故障存儲(chǔ)",
        1074: "系統(tǒng)重啟/關(guān)機(jī)事件",
        6008: "意外關(guān)機(jī)(上次關(guān)閉不干凈)",
        6009: "系統(tǒng)啟動(dòng)(記錄系統(tǒng)版本)",
        6013: "系統(tǒng)運(yùn)行時(shí)間統(tǒng)計(jì)",

        # 服務(wù)相關(guān)
        7036: "服務(wù)狀態(tài)變更",
        7040: "服務(wù)啟動(dòng)類型變更",
        7034: "服務(wù)意外終止",
        7031: "服務(wù)崩潰后自動(dòng)重啟",

        # 磁盤相關(guān)
        7: "壞扇區(qū)檢測(cè)",
        9: "設(shè)備超時(shí)",
        11: "驅(qū)動(dòng)器控制器錯(cuò)誤",
        51: "磁盤頁(yè)文件錯(cuò)誤",
        57: "磁盤扇區(qū)修復(fù)",

        # 網(wǎng)絡(luò)相關(guān)
        2020: "網(wǎng)絡(luò)連接中斷后恢復(fù)",

        # DNS 客戶端
        1014: "DNS 解析失敗",

        # 安全相關(guān)
        4625: "登錄失敗",
        4624: "登錄成功",
        4634: "注銷",
        4648: "使用顯式憑據(jù)登錄",
        4720: "創(chuàng)建用戶賬戶",
        4732: "添加本地組成員",
        4740: "賬戶被鎖定",
        6416: "新外部設(shè)備檢測(cè)",
    }

    def __init__(self):
        self.events = []
        self.stats = defaultdict(lambda: Counter())

    def load_events(self, events):
        """加載事件列表"""
        self.events = events

    def analyze(self, hours=24):
        """執(zhí)行全面分析,返回分析報(bào)告"""
        now = datetime.now()
        cutoff = now - timedelta(hours=hours)
        recent = [
            e for e in self.events
            if isinstance(e.get("time"), datetime) and e["time"] >= cutoff
        ]

        report = {
            "時(shí)間范圍": f"最近 {hours} 小時(shí)",
            "總事件數(shù)": len(recent),
            "summary": {},
            "alerts": [],
            "top_errors": [],
            "top_sources": [],
        }

        # 1. 按級(jí)別統(tǒng)計(jì)
        level_counts = Counter(e.get("level", "UNKNOWN") for e in recent)
        report["summary"]["按級(jí)別統(tǒng)計(jì)"] = dict(level_counts)

        # 2. 檢查關(guān)鍵事件
        for e in recent:
            eid = e.get("event_id")
            if eid in self.KNOWN_EVENTS and e.get("level") in ("ERROR", "WARNING"):
                report["alerts"].append({
                    "time": e["time"],
                    "event_id": eid,
                    "description": self.KNOWN_EVENTS[eid],
                    "source": e.get("source", ""),
                    "message": e.get("message", "")[:200],
                })

        # 3. TOP 錯(cuò)誤事件
        error_events = [e for e in recent if e.get("level") == "ERROR"]
        error_counter = Counter(
            (e.get("event_id"), e.get("source"))
            for e in error_events
        )
        report["top_errors"] = [
            {"event_id": eid, "source": src, "count": cnt, "description": self.KNOWN_EVENTS.get(eid, "未知")}
            for (eid, src), cnt in error_counter.most_common(10)
        ]

        # 4. TOP 錯(cuò)誤來(lái)源
        source_counter = Counter(e.get("source", "Unknown") for e in error_events)
        report["top_sources"] = source_counter.most_common(10)

        # 5. 檢測(cè)異常模式
        report["patterns"] = self._detect_patterns(recent)

        return report

    def _detect_patterns(self, events):
        """檢測(cè)異常模式"""
        patterns = []

        # 模式1:短時(shí)間大量同類錯(cuò)誤(可能是攻擊或故障)
        error_times = [
            e["time"] for e in events
            if e.get("level") == "ERROR" and isinstance(e.get("time"), datetime)
        ]
        if len(error_times) >= 10:
            error_times.sort()
            # 檢查 1 分鐘內(nèi)是否有 10+ 錯(cuò)誤
            for i in range(len(error_times) - 10):
                if (error_times[i + 9] - error_times[i]).total_seconds() < 60:
                    patterns.append({
                        "type": "錯(cuò)誤風(fēng)暴",
                        "severity": "HIGH",
                        "detail": f"1分鐘內(nèi)出現(xiàn) {10}+ 條錯(cuò)誤事件",
                    })
                    break

        # 模式2:服務(wù)反復(fù)重啟
        service_restarts = Counter()
        for e in events:
            if e.get("event_id") == 7031 and isinstance(e.get("time"), datetime):
                # 從消息中提取服務(wù)名
                msg = e.get("message", "")
                match = re.search(r"服務(wù)\s+(.+?)\s+意外終止", msg)
                if match:
                    service_restarts[match.group(1)] += 1

        for svc, cnt in service_restarts.items():
            if cnt >= 3:
                patterns.append({
                    "type": "服務(wù)頻繁重啟",
                    "severity": "HIGH",
                    "detail": f"服務(wù) '{svc}' 在分析期間重啟了 {cnt} 次",
                })

        # 模式3:連續(xù)登錄失?。赡艿谋┝ζ平猓?
        login_failures = Counter()
        for e in events:
            if e.get("event_id") == 4625 and isinstance(e.get("time"), datetime):
                login_failures[e.get("computer", "Unknown")] += 1

        for comp, cnt in login_failures.items():
            if cnt >= 5:
                patterns.append({
                    "type": "暴力破解嫌疑",
                    "severity": "CRITICAL",
                    "detail": f"{comp} 出現(xiàn) {cnt} 次登錄失敗",
                })

        # 模式4:意外關(guān)機(jī)
        unexpected_shutdowns = sum(
            1 for e in events
            if e.get("event_id") == 6008 and isinstance(e.get("time"), datetime)
        )
        if unexpected_shutdowns > 0:
            patterns.append({
                "type": "意外關(guān)機(jī)",
                "severity": "HIGH",
                "detail": f"檢測(cè)到 {unexpected_shutdowns} 次意外關(guān)機(jī)",
            })

        return patterns

    def print_report(self, report):
        """打印分析報(bào)告"""
        print("=" * 60)
        print(f"  Windows 事件日志分析報(bào)告")
        print(f"  {report['時(shí)間范圍']}")
        print("=" * 60)

        print(f"\n?? 總事件數(shù): {report['總事件數(shù)']}")
        print("\n?? 按級(jí)別統(tǒng)計(jì):")
        for level, count in report["summary"]["按級(jí)別統(tǒng)計(jì)"].items():
            icon = {"ERROR": "??", "WARNING": "??", "INFORMATION": "??"}.get(level, "?")
            print(f"  {icon} {level}: {count}")

        if report["alerts"]:
            print(f"\n?? 關(guān)鍵事件 ({len(report['alerts'])} 條):")
            for alert in report["alerts"][:10]:
                print(f"  [{alert['time']}] EventID {alert['event_id']}")
                print(f"  {alert['description']}")
                print()

        if report["patterns"]:
            print(f"\n? 檢測(cè)到 {len(report['patterns'])} 個(gè)異常模式:")
            for p in report["patterns"]:
                severity_icon = {"CRITICAL": "??", "HIGH": "??", "MEDIUM": "??"}.get(p["severity"], "?")
                print(f"  {severity_icon} [{p['type']}] {p['detail']}")

        if report["top_errors"]:
            print("\n?? TOP 錯(cuò)誤事件:")
            for item in report["top_errors"][:5]:
                print(f"  EventID {item['event_id']} ({item['source']}): "
                      f"{item['count']} 次 - {item['description']}")

        print("\n" + "=" * 60)


# 使用示例
events = read_event_log("System", count=500)
analyzer = EventLogAnalyzer()
analyzer.load_events(events)
report = analyzer.analyze(hours=24)
analyzer.print_report(report)

實(shí)戰(zhàn)二:跨機(jī)器日志聚合

生產(chǎn)環(huán)境往往需要同時(shí)分析多臺(tái)服務(wù)器:

import win32evtlog
from concurrent.futures import ThreadPoolExecutor, as_completed

def collect_logs_from_servers(
    servers, log_name="System", hours=24, max_workers=10
):
    """
    從多臺(tái)服務(wù)器收集事件日志
    返回 {server_name: [events]}
    """
    results = {}

    def fetch_from_server(server):
        try:
            events = read_event_log(log_name, server=server, count=200)
            # 過(guò)濾時(shí)間范圍
            cutoff = datetime.datetime.now() - datetime.timedelta(hours=hours)
            filtered = [
                e for e in events
                if isinstance(e.get("time"), datetime) and e["time"] >= cutoff
            ]
            return server, filtered
        except Exception as e:
            return server, []

    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        futures = {
            executor.submit(fetch_from_server, s): s
            for s in servers
        }

        for future in as_completed(futures):
            server, events = future.result()
            results[server] = events
            print(f"  ? {server}: 獲取 {len(events)} 條事件")

    return results


def find_common_errors(server_events_map):
    """
    找出多臺(tái)服務(wù)器共有的錯(cuò)誤
    """
    from collections import Counter

    # 統(tǒng)計(jì)每臺(tái)服務(wù)器的錯(cuò)誤
    error_sets = {}
    for server, events in server_events_map.items():
        errors = Counter(
            (e.get("event_id"), e.get("source"))
            for e in events if e.get("level") == "ERROR"
        )
        if errors:
            error_sets[server] = errors

    # 找共有的錯(cuò)誤
    servers = list(error_sets.keys())
    common = None

    for server in servers:
        current_keys = set(error_sets[server].keys())
        if common is None:
            common = current_keys
        else:
            common &= current_keys

    if common:
        print("\n?? 多臺(tái)服務(wù)器共有的錯(cuò)誤:")
        for eid, src in sorted(common):
            desc = EventLogAnalyzer.KNOWN_EVENTS.get(eid, "未知")
            print(f"  EventID {eid} ({src}): {desc}")
            for server in servers:
                count = error_sets[server].get((eid, src), 0)
                print(f"    {server}: {count} 次")

    return common

實(shí)戰(zhàn)三:日志趨勢(shì)分析與預(yù)警

import time

class LogMonitor:
    """實(shí)時(shí)日志監(jiān)控器"""

    def __init__(self, log_name="System", check_interval=60):
        self.log_name = log_name
        self.check_interval = check_interval
        self.last_check_time = datetime.datetime.now()
        self.baseline = Counter()  # 基線:正常情況下的錯(cuò)誤頻率
        self.alert_threshold = 3  # 超過(guò)基線 N 倍則告警

    def calibrate(self, duration_hours=24):
        """
        校準(zhǔn)基線:統(tǒng)計(jì)正常情況下的錯(cuò)誤頻率
        建議在系統(tǒng)正常運(yùn)行時(shí)執(zhí)行
        """
        print(f"正在校準(zhǔn)基線(分析過(guò)去 {duration_hours} 小時(shí)的日志)...")
        events = read_event_log(self.log_name, count=5000)
        cutoff = datetime.datetime.now() - datetime.timedelta(hours=duration_hours)

        for e in events:
            if isinstance(e.get("time"), datetime) and e["time"] >= cutoff:
                if e.get("level") == "ERROR":
                    key = (e.get("event_id"), e.get("source"))
                    self.baseline[key] += 1

        print(f"基線校準(zhǔn)完成,記錄了 {sum(self.baseline.values())} 條錯(cuò)誤")
        return self.baseline

    def check_new_events(self):
        """檢查自上次檢查以來(lái)的新事件"""
        hand = win32evtlog.OpenEventLog(None, self.log_name)
        flags = (
            win32evtlog.EVENTLOG_BACKWARDS_READ
            | win32evtlog.EVENTLOG_SEQUENTIAL_READ
        )

        new_events = []
        while True:
            batch = win32evtlog.ReadEventLog(hand, flags, 0)
            if not batch:
                break

            for event in batch:
                evt_time = datetime.datetime.strptime(
                    event.TimeGenerated.Format(), "%m/%d/%Y %H:%M:%S"
                )
                if evt_time > self.last_check_time:
                    new_events.append({
                        "time": evt_time,
                        "level": EVENT_LEVELS.get(event.EventType, "INFO"),
                        "source": event.SourceName,
                        "event_id": event.EventID & 0xFFFF,
                    })
                else:
                    break

            break

        win32evtlog.CloseEventLog(hand)

        if new_events:
            self.last_check_time = new_events[0]["time"]

        return new_events

    def evaluate(self, new_events):
        """評(píng)估新事件是否異常"""
        errors = [
            e for e in new_events if e.get("level") == "ERROR"
        ]
        current = Counter(
            (e.get("event_id"), e.get("source")) for e in errors
        )

        alerts = []
        for key, count in current.items():
            baseline_count = self.baseline.get(key, 0)
            if baseline_count > 0 and count > baseline_count * self.alert_threshold:
                alerts.append({
                    "severity": "HIGH",
                    "key": key,
                    "current": count,
                    "baseline_avg": baseline_count / 24,  # 每小時(shí)平均
                    "description": (
                        f"EventID {key[0]} ({key[1]}) 當(dāng)前 {count} 次,"
                        f"基線平均 {baseline_count/24:.1f} 次/小時(shí)"
                    ),
                })

        return alerts

    def run_once(self):
        """執(zhí)行一次檢查"""
        new_events = self.check_new_events()
        if not new_events:
            print("  無(wú)新事件")
            return []

        print(f"  發(fā)現(xiàn) {len(new_events)} 條新事件,"
              f"{sum(1 for e in new_events if e['level']=='ERROR')} 條錯(cuò)誤")

        alerts = self.evaluate(new_events)
        if alerts:
            print("  ?? 異常檢測(cè):")
            for a in alerts:
                print(f"    {a['description']}")

        return alerts

    def start_monitoring(self):
        """啟動(dòng)持續(xù)監(jiān)控"""
        print("開(kāi)始持續(xù)監(jiān)控...")
        print("按 Ctrl+C 停止\n")

        try:
            while True:
                now = datetime.datetime.now().strftime("%H:%M:%S")
                print(f"[{now}] 檢查 {self.log_name} 日志...")
                self.run_once()
                time.sleep(self.check_interval)
        except KeyboardInterrupt:
            print("\n監(jiān)控已停止")


# 使用示例
monitor = LogMonitor("System", check_interval=60)
monitor.calibrate(duration_hours=24)
# monitor.start_monitoring()  # 生產(chǎn)環(huán)境啟用
monitor.run_once()  # 單次檢查

實(shí)戰(zhàn)四:IIS 日志分析

Web 服務(wù)器運(yùn)維中,IIS 日志分析是剛需:

from pathlib import Path
from collections import Counter
import re

class IISLogAnalyzer:
    """IIS 日志分析器"""

    # IIS 日志字段(常見(jiàn)格式)
    FIELDS = [
        "date", "time", "s-ip", "cs-method", "cs-uri-stem",
        "cs-uri-query", "s-port", "cs-username", "c-ip",
        "cs(User-Agent)", "cs(Referer)", "sc-status",
        "sc-substatus", "sc-win32-status", "time-taken",
    ]

    def parse_log(self, log_file):
        """解析 IIS 日志文件"""
        events = []
        in_header = True

        with open(log_file, "r", encoding="utf-8", errors="ignore") as f:
            for line in f:
                line = line.strip()
                if not line or line.startswith("#"):
                    continue

                parts = line.split()
                if len(parts) != len(self.FIELDS):
                    continue

                event = dict(zip(self.FIELDS, parts))
                events.append(event)

        return events

    def analyze(self, events):
        """分析 IIS 日志"""
        report = {}

        # 1. 狀態(tài)碼分布
        status_codes = Counter(e.get("sc-status", "0") for e in events)
        report["狀態(tài)碼分布"] = status_codes.most_common()

        # 2. TOP 請(qǐng)求路徑
        top_urls = Counter(
            e.get("cs-uri-stem", "") for e in events
        )
        report["TOP 請(qǐng)求路徑"] = top_urls.most_common(20)

        # 3. TOP 客戶端 IP
        top_ips = Counter(e.get("c-ip", "") for e in events)
        report["TOP 客戶端 IP"] = top_ips.most_common(20)

        # 4. 平均響應(yīng)時(shí)間
        response_times = []
        for e in events:
            try:
                rt = int(e.get("time-taken", 0))
                if rt > 0:
                    response_times.append(rt)
            except (ValueError, TypeError):
                pass

        if response_times:
            response_times.sort()
            report["響應(yīng)時(shí)間"] = {
                "平均": sum(response_times) / len(response_times),
                "中位數(shù)": response_times[len(response_times) // 2],
                "P95": response_times[int(len(response_times) * 0.95)],
                "最大": max(response_times),
                "請(qǐng)求數(shù)": len(response_times),
            }

        # 5. 慢請(qǐng)求(超過(guò) 3 秒)
        slow_requests = [
            e for e in events
            if e.get("time-taken") and int(e["time-taken"]) > 3000
        ]
        report["慢請(qǐng)求 (>3s)"] = len(slow_requests)

        # 6. 4xx/5xx 錯(cuò)誤詳情
        error_pages = Counter(
            (e.get("sc-status"), e.get("cs-uri-stem"))
            for e in events
            if e.get("sc-status", "").startswith(("4", "5"))
        )
        report["錯(cuò)誤頁(yè)面"] = error_pages.most_common(10)

        return report

    def print_report(self, report):
        """打印分析報(bào)告"""
        print("=" * 60)
        print("  IIS 日志分析報(bào)告")
        print("=" * 60)

        print("\n?? 狀態(tài)碼分布:")
        for code, count in report["狀態(tài)碼分布"][:10]:
            print(f"  [code]: {count}")

        if "響應(yīng)時(shí)間" in report:
            rt = report["響應(yīng)時(shí)間"]
            print(f"\n?? 響應(yīng)時(shí)間 (ms):")
            print(f"  平均: {rt['平均']:.0f}ms | "
                  f"中位數(shù): {rt['中位數(shù)']}ms | "
                  f"P95: {rt['P95']}ms")

        print(f"\n?? 慢請(qǐng)求: {report['慢請(qǐng)求 (>3s)']} 個(gè)")

        print("\n?? TOP 5 請(qǐng)求路徑:")
        for url, count in report["TOP 請(qǐng)求路徑"][:5]:
            print(f"  {url}: {count} 次")

        print("\n?? TOP 5 錯(cuò)誤頁(yè)面:")
        for (code, url), count in report["錯(cuò)誤頁(yè)面"][:5]:
            print(f"  [[code]] {url}: {count} 次")

        print("\n?? TOP 5 客戶端 IP:")
        for ip, count in report["TOP 客戶端 IP"][:5]:
            print(f"  {ip}: {count} 次")


# 使用
analyzer = IISLogAnalyzer()
# events = analyzer.parse_log(r"C:\inetpub\logs\LogFiles\W3SVC1\u_ex260506.log")
# report = analyzer.analyze(events)
# analyzer.print_report(report)

自動(dòng)化報(bào)告生成

把分析結(jié)果導(dǎo)出為 HTML 報(bào)告:

def generate_html_report(report, output_file="event_report.html"):
    """生成 HTML 格式的分析報(bào)告"""
    html = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Windows 事件日志分析報(bào)告</title>
    <style>
        body {{ font-family: 'Segoe UI', sans-serif; background: #1a1a2e; color: #eee; padding: 20px; }}
        h1 {{ color: #00d4ff; border-bottom: 2px solid #00d4ff; padding-bottom: 10px; }}
        .section {{ background: #16213e; border-radius: 8px; padding: 20px; margin: 20px 0; }}
        .alert {{ background: #2d1f1f; border-left: 4px solid #ff4444; padding: 10px 15px; margin: 5px 0; }}
        .warning {{ background: #2d2d1f; border-left: 4px solid #ffaa00; padding: 10px 15px; margin: 5px 0; }}
        table {{ width: 100%; border-collapse: collapse; }}
        th, td {{ padding: 8px 12px; text-align: left; border-bottom: 1px solid #333; }}
        th {{ color: #00d4ff; }}
        .stat {{ display: inline-block; background: #0f3460; padding: 10px 20px; border-radius: 5px; margin: 5px; }}
        .stat .num {{ font-size: 24px; font-weight: bold; color: #00d4ff; }}
    </style>
</head>
<body>
    <h1>Windows 事件日志分析報(bào)告</h1>
    <p>分析時(shí)間: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
    <div class="section">
        <h2>概覽</h2>
        <div class="stat"><div class="num">{report['總事件數(shù)']}</div>總事件數(shù)</div>
"""
    # 添加級(jí)別統(tǒng)計(jì)
    level_icons = {"ERROR": "??", "WARNING": "??", "INFORMATION": "??"}
    for level, count in report["summary"]["按級(jí)別統(tǒng)計(jì)"].items():
        icon = level_icons.get(level, "?")
        html += f'        <div class="stat"><div class="num">{icon} {count}</div>{level}</div>\n'
    # 添加異常模式
    if report["patterns"]:
        html += '    <div class="section"><h2>異常模式</h2>\n'
        for p in report["patterns"]:
            css = "alert" if p["severity"] in ("HIGH", "CRITICAL") else "warning"
            html += f'    <div class="{css}"><strong>[{p["type"]}]</strong> {p["detail"]}</div>\n'
        html += '</div>\n'
    html += '</body></html>'
    with open(output_file, "w", encoding="utf-8") as f:
        f.write(html)
    print(f"報(bào)告已生成: {output_file}")
    return output_file
# 生成報(bào)告
# generate_html_report(report)

小結(jié)

需求方案優(yōu)勢(shì)
讀取本地日志win32evtlog速度最快,功能最全
無(wú) pywin32PowerShell 橋接零依賴
跨機(jī)器收集WMI + 多線程批量高效
異常檢測(cè)統(tǒng)計(jì)基線 + 閾值自動(dòng)發(fā)現(xiàn)故障
IIS 日志文件解析 + 統(tǒng)計(jì)網(wǎng)站排障必備
報(bào)告輸出HTML 自動(dòng)生成可視化分享

日志分析是 IT 運(yùn)維的核心技能。Windows 事件日志包含了排障所需的大部分信息,關(guān)鍵是你能不能快速找到那條關(guān)鍵事件。

以上就是Python實(shí)現(xiàn)自動(dòng)分析Windows事件日志的詳細(xì)內(nèi)容,更多關(guān)于Python分析Windows事件日志的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python模塊對(duì)Redis數(shù)據(jù)庫(kù)的連接與使用講解

    Python模塊對(duì)Redis數(shù)據(jù)庫(kù)的連接與使用講解

    這篇文章主要介紹了Python模塊對(duì)Redis數(shù)據(jù)庫(kù)的連接與使用,通過(guò)實(shí)例代碼給大家介紹了Python連接Redis數(shù)據(jù)庫(kù)方法,Python使用連接池連接Redis數(shù)據(jù)庫(kù)方法,感興趣的朋友跟隨小編一起看看吧
    2021-07-07
  • 教你使用一行Python代碼玩遍童年的小游戲

    教你使用一行Python代碼玩遍童年的小游戲

    這篇文章主要介紹了一行Python代碼玩遍童年的小游戲,幫助大家重回童年快樂(lè)時(shí)光,代碼簡(jiǎn)單易懂,感興趣的朋友一起學(xué)習(xí)下吧
    2021-08-08
  • Python獲取腳本所在目錄的正確方法

    Python獲取腳本所在目錄的正確方法

    這篇文章主要介紹了Python獲取腳本所在目錄的正確方法,需要的朋友可以參考下
    2014-04-04
  • python實(shí)現(xiàn)對(duì)數(shù)組按指定列排序

    python實(shí)現(xiàn)對(duì)數(shù)組按指定列排序

    這篇文章主要介紹了python實(shí)現(xiàn)對(duì)數(shù)組按指定列排序方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • python爬蟲(chóng)請(qǐng)求頁(yè)面urllib庫(kù)詳解

    python爬蟲(chóng)請(qǐng)求頁(yè)面urllib庫(kù)詳解

    這篇文章主要介紹了python爬蟲(chóng)請(qǐng)求頁(yè)面urllib庫(kù)詳解,python3將urllib和urllib2模塊整合并命名為urllib模塊,urllib模塊有多個(gè)子模塊,各有不同的功能,需要的朋友可以參考下
    2023-07-07
  • 基于python3的socket聊天編程

    基于python3的socket聊天編程

    這篇文章主要為大家詳細(xì)介紹了基于python3的socket聊天編程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • Python中的反射知識(shí)點(diǎn)總結(jié)

    Python中的反射知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理了一篇關(guān)于Python中的反射知識(shí)點(diǎn)總結(jié)內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)參考下。
    2021-11-11
  • 利用Python將時(shí)間或時(shí)間間隔轉(zhuǎn)為ISO 8601格式方法示例

    利用Python將時(shí)間或時(shí)間間隔轉(zhuǎn)為ISO 8601格式方法示例

    國(guó)際標(biāo)準(zhǔn)化組織的國(guó)際標(biāo)準(zhǔn)ISO8601是日期和時(shí)間的表示方法,全稱為《數(shù)據(jù)存儲(chǔ)和交換形式·信息交換·日期和時(shí)間的表示方法》,下面這篇文章主要給大家介紹了關(guān)于利用Python將時(shí)間或時(shí)間間隔轉(zhuǎn)為ISO 8601格式的相關(guān)資料,需要的朋友可以參考下。
    2017-09-09
  • Python語(yǔ)法學(xué)習(xí)之正則表達(dá)式的使用詳解

    Python語(yǔ)法學(xué)習(xí)之正則表達(dá)式的使用詳解

    要想成功的進(jìn)行字符串的匹配需要使用到正則表達(dá)式模塊,正則表達(dá)式匹配規(guī)則以及需要被匹配的字符串。本文詳細(xì)為大家介紹了如何利用正則表達(dá)式實(shí)現(xiàn)字符的匹配,感興趣的可以了解一下
    2022-04-04
  • python3 實(shí)現(xiàn)驗(yàn)證碼圖片切割的方法

    python3 實(shí)現(xiàn)驗(yàn)證碼圖片切割的方法

    今天小編就為大家分享一篇python3 實(shí)現(xiàn)驗(yàn)證碼圖片切割的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12

最新評(píng)論

巩留县| 南昌县| 罗城| 田林县| 三江| 攀枝花市| 宜阳县| 休宁县| 化隆| 宜良县| 鄂伦春自治旗| 曲周县| 建水县| 栾川县| 民县| 望都县| 汽车| 新干县| 呼图壁县| 栖霞市| 新龙县| 天祝| 缙云县| 高台县| 且末县| 贡山| 桐城市| 鹤山市| 凭祥市| 益阳市| 双辽市| 麻阳| 无棣县| 屯门区| 车致| 肥乡县| 宝鸡市| 嵩明县| 普洱| 延吉市| 遂平县|