Python實現(xiàn)自動分析Windows事件日志
凌晨 3 點,告警響了——服務(wù)器無響應(yīng)。你 SSH 上去一看,日志文件幾 GB,手動翻到天亮也沒找到原因。如果我告訴你,Python 3 分鐘就能搞定呢?
為什么需要自動化日志分析?
Windows 事件日志(Event Log)記錄了系統(tǒng)中幾乎所有重要事件:
| 日志類型 | 內(nèi)容 | 重要性 |
|---|---|---|
| System | 系統(tǒng)啟動/關(guān)閉、驅(qū)動錯誤、服務(wù)狀態(tài) | ????? |
| Application | 應(yīng)用程序崩潰、.NET 異常 | ???? |
| Security | 登錄嘗試、權(quán)限變更、審計事件 | ????? |
| Setup | 系統(tǒng)更新、補丁安裝 | ??? |
| ForwardedEvents | 從其他機器轉(zhuǎn)發(fā)的事件 | ???? |
手動用"事件查看器"(Event Viewer)翻日志的痛點:
- 日志量巨大,一次藍(lán)屏可能產(chǎn)生上萬條事件
- 無法跨多臺機器關(guān)聯(lián)分析
- 沒有智能過濾,關(guān)鍵信息淹沒在噪音中
- 無法做趨勢分析和預(yù)警
方案對比:三種讀取方式
- 方案一:win32evtlog(速度最快,但需要 pywin32)
- 方案二:PowerShell Get-WinEvent(無需額外庫)
- 方案三:wevtutil 命令行(最通用,但解析麻煩)
我們?nèi)N都講,但推薦方案一(win32evtlog)用于生產(chǎn)環(huán)境。
方案一:win32evtlog 直接讀取(推薦)
import win32evtlog
import win32evtlogutil
import datetime
# 事件級別常量
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)程計算機名(None=本地)
count: 最多讀取條數(shù)
level: 過濾級別 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
# 過濾條件
if level and evt_level != level:
continue
if event_id and event.EventID & 0xFFFF != event_id:
continue
if source and event.SourceName != source:
continue
# 解析時間
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)錯誤
errors = read_event_log("System", count=50, level=1)
print(f"發(fā)現(xiàn) {len(errors)} 條系統(tǒng)錯誤:\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 橋接(無需安裝 pywin32)
如果你的環(huán)境不方便安裝 pywin32,可以通過 PowerShell 橋接:
import subprocess
import json
def get_events_via_powershell(
log_name="System",
max_events=100,
level=None,
start_time=None
):
"""
通過 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 錯誤: {result.stderr}")
return []
try:
data = json.loads(result.stdout)
if isinstance(data, dict):
data = [data]
return data
except json.JSONDecodeError:
return []
# 示例:獲取最近的系統(tǒng)錯誤
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
實戰(zhàn)一:日志異常檢測引擎
手動翻日志效率太低,我們需要一個能自動發(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)核電源錯誤(意外斷電/藍(lán)屏)",
1001: "Windows Error Reporting 故障存儲",
1074: "系統(tǒng)重啟/關(guān)機事件",
6008: "意外關(guān)機(上次關(guān)閉不干凈)",
6009: "系統(tǒng)啟動(記錄系統(tǒng)版本)",
6013: "系統(tǒng)運行時間統(tǒng)計",
# 服務(wù)相關(guān)
7036: "服務(wù)狀態(tài)變更",
7040: "服務(wù)啟動類型變更",
7034: "服務(wù)意外終止",
7031: "服務(wù)崩潰后自動重啟",
# 磁盤相關(guān)
7: "壞扇區(qū)檢測",
9: "設(shè)備超時",
11: "驅(qū)動器控制器錯誤",
51: "磁盤頁文件錯誤",
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è)備檢測",
}
def __init__(self):
self.events = []
self.stats = defaultdict(lambda: Counter())
def load_events(self, events):
"""加載事件列表"""
self.events = events
def analyze(self, hours=24):
"""執(zhí)行全面分析,返回分析報告"""
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 = {
"時間范圍": f"最近 {hours} 小時",
"總事件數(shù)": len(recent),
"summary": {},
"alerts": [],
"top_errors": [],
"top_sources": [],
}
# 1. 按級別統(tǒng)計
level_counts = Counter(e.get("level", "UNKNOWN") for e in recent)
report["summary"]["按級別統(tǒng)計"] = 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 錯誤事件
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 錯誤來源
source_counter = Counter(e.get("source", "Unknown") for e in error_events)
report["top_sources"] = source_counter.most_common(10)
# 5. 檢測異常模式
report["patterns"] = self._detect_patterns(recent)
return report
def _detect_patterns(self, events):
"""檢測異常模式"""
patterns = []
# 模式1:短時間大量同類錯誤(可能是攻擊或故障)
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+ 錯誤
for i in range(len(error_times) - 10):
if (error_times[i + 9] - error_times[i]).total_seconds() < 60:
patterns.append({
"type": "錯誤風(fēng)暴",
"severity": "HIGH",
"detail": f"1分鐘內(nèi)出現(xiàn) {10}+ 條錯誤事件",
})
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)機
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)機",
"severity": "HIGH",
"detail": f"檢測到 {unexpected_shutdowns} 次意外關(guān)機",
})
return patterns
def print_report(self, report):
"""打印分析報告"""
print("=" * 60)
print(f" Windows 事件日志分析報告")
print(f" {report['時間范圍']}")
print("=" * 60)
print(f"\n?? 總事件數(shù): {report['總事件數(shù)']}")
print("\n?? 按級別統(tǒng)計:")
for level, count in report["summary"]["按級別統(tǒng)計"].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? 檢測到 {len(report['patterns'])} 個異常模式:")
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 錯誤事件:")
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)
實戰(zhàn)二:跨機器日志聚合
生產(chǎn)環(huán)境往往需要同時分析多臺服務(wù)器:
import win32evtlog
from concurrent.futures import ThreadPoolExecutor, as_completed
def collect_logs_from_servers(
servers, log_name="System", hours=24, max_workers=10
):
"""
從多臺服務(wù)器收集事件日志
返回 {server_name: [events]}
"""
results = {}
def fetch_from_server(server):
try:
events = read_event_log(log_name, server=server, count=200)
# 過濾時間范圍
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):
"""
找出多臺服務(wù)器共有的錯誤
"""
from collections import Counter
# 統(tǒng)計每臺服務(wù)器的錯誤
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
# 找共有的錯誤
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?? 多臺服務(wù)器共有的錯誤:")
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
實戰(zhàn)三:日志趨勢分析與預(yù)警
import time
class LogMonitor:
"""實時日志監(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() # 基線:正常情況下的錯誤頻率
self.alert_threshold = 3 # 超過基線 N 倍則告警
def calibrate(self, duration_hours=24):
"""
校準(zhǔn)基線:統(tǒng)計正常情況下的錯誤頻率
建議在系統(tǒng)正常運行時執(zhí)行
"""
print(f"正在校準(zhǔn)基線(分析過去 {duration_hours} 小時的日志)...")
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())} 條錯誤")
return self.baseline
def check_new_events(self):
"""檢查自上次檢查以來的新事件"""
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):
"""評估新事件是否異常"""
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, # 每小時平均
"description": (
f"EventID {key[0]} ({key[1]}) 當(dāng)前 {count} 次,"
f"基線平均 {baseline_count/24:.1f} 次/小時"
),
})
return alerts
def run_once(self):
"""執(zhí)行一次檢查"""
new_events = self.check_new_events()
if not new_events:
print(" 無新事件")
return []
print(f" 發(fā)現(xiàn) {len(new_events)} 條新事件,"
f"{sum(1 for e in new_events if e['level']=='ERROR')} 條錯誤")
alerts = self.evaluate(new_events)
if alerts:
print(" ?? 異常檢測:")
for a in alerts:
print(f" {a['description']}")
return alerts
def start_monitoring(self):
"""啟動持續(xù)監(jiān)控"""
print("開始持續(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() # 單次檢查
實戰(zhàn)四:IIS 日志分析
Web 服務(wù)器運維中,IIS 日志分析是剛需:
from pathlib import Path
from collections import Counter
import re
class IISLogAnalyzer:
"""IIS 日志分析器"""
# IIS 日志字段(常見格式)
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 請求路徑
top_urls = Counter(
e.get("cs-uri-stem", "") for e in events
)
report["TOP 請求路徑"] = 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)時間
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)時間"] = {
"平均": 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),
"請求數(shù)": len(response_times),
}
# 5. 慢請求(超過 3 秒)
slow_requests = [
e for e in events
if e.get("time-taken") and int(e["time-taken"]) > 3000
]
report["慢請求 (>3s)"] = len(slow_requests)
# 6. 4xx/5xx 錯誤詳情
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["錯誤頁面"] = error_pages.most_common(10)
return report
def print_report(self, report):
"""打印分析報告"""
print("=" * 60)
print(" IIS 日志分析報告")
print("=" * 60)
print("\n?? 狀態(tài)碼分布:")
for code, count in report["狀態(tài)碼分布"][:10]:
print(f" [code]: {count}")
if "響應(yīng)時間" in report:
rt = report["響應(yīng)時間"]
print(f"\n?? 響應(yīng)時間 (ms):")
print(f" 平均: {rt['平均']:.0f}ms | "
f"中位數(shù): {rt['中位數(shù)']}ms | "
f"P95: {rt['P95']}ms")
print(f"\n?? 慢請求: {report['慢請求 (>3s)']} 個")
print("\n?? TOP 5 請求路徑:")
for url, count in report["TOP 請求路徑"][:5]:
print(f" {url}: {count} 次")
print("\n?? TOP 5 錯誤頁面:")
for (code, url), count in report["錯誤頁面"][: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)
自動化報告生成
把分析結(jié)果導(dǎo)出為 HTML 報告:
def generate_html_report(report, output_file="event_report.html"):
"""生成 HTML 格式的分析報告"""
html = f"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Windows 事件日志分析報告</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 事件日志分析報告</h1>
<p>分析時間: {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>
"""
# 添加級別統(tǒng)計
level_icons = {"ERROR": "??", "WARNING": "??", "INFORMATION": "??"}
for level, count in report["summary"]["按級別統(tǒng)計"].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"報告已生成: {output_file}")
return output_file
# 生成報告
# generate_html_report(report)小結(jié)
| 需求 | 方案 | 優(yōu)勢 |
|---|---|---|
| 讀取本地日志 | win32evtlog | 速度最快,功能最全 |
| 無 pywin32 | PowerShell 橋接 | 零依賴 |
| 跨機器收集 | WMI + 多線程 | 批量高效 |
| 異常檢測 | 統(tǒng)計基線 + 閾值 | 自動發(fā)現(xiàn)故障 |
| IIS 日志 | 文件解析 + 統(tǒng)計 | 網(wǎng)站排障必備 |
| 報告輸出 | HTML 自動生成 | 可視化分享 |
日志分析是 IT 運維的核心技能。Windows 事件日志包含了排障所需的大部分信息,關(guān)鍵是你能不能快速找到那條關(guān)鍵事件。
以上就是Python實現(xiàn)自動分析Windows事件日志的詳細(xì)內(nèi)容,更多關(guān)于Python分析Windows事件日志的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python模塊對Redis數(shù)據(jù)庫的連接與使用講解
這篇文章主要介紹了Python模塊對Redis數(shù)據(jù)庫的連接與使用,通過實例代碼給大家介紹了Python連接Redis數(shù)據(jù)庫方法,Python使用連接池連接Redis數(shù)據(jù)庫方法,感興趣的朋友跟隨小編一起看看吧2021-07-07
利用Python將時間或時間間隔轉(zhuǎn)為ISO 8601格式方法示例
國際標(biāo)準(zhǔn)化組織的國際標(biāo)準(zhǔn)ISO8601是日期和時間的表示方法,全稱為《數(shù)據(jù)存儲和交換形式·信息交換·日期和時間的表示方法》,下面這篇文章主要給大家介紹了關(guān)于利用Python將時間或時間間隔轉(zhuǎn)為ISO 8601格式的相關(guān)資料,需要的朋友可以參考下。2017-09-09
Python語法學(xué)習(xí)之正則表達(dá)式的使用詳解
要想成功的進(jìn)行字符串的匹配需要使用到正則表達(dá)式模塊,正則表達(dá)式匹配規(guī)則以及需要被匹配的字符串。本文詳細(xì)為大家介紹了如何利用正則表達(dá)式實現(xiàn)字符的匹配,感興趣的可以了解一下2022-04-04

