Python 怎么筛选日志并做简单统计:错误、状态码、关键词一次找出来
用运维和接口排查场景讲清 Python 如何读取日志文件、筛选关键词、提取状态码、统计错误次数并导出结果。
相关工具
日志分析先从小问题开始
日志文件可能很大,但排查问题时通常不是一开始就做复杂分析。更常见的问题是:今天有多少 500 错误,某个用户 ID 出现在哪些行,某个接口从什么时候开始报错,哪些状态码最多,某个关键词附近有什么上下文。Python 很适合做这种轻量筛选和统计。
处理日志前先明确目标。是找错误行,还是统计状态码?是看某个时间段,还是搜索某个订单号?目标不同,代码也不同。不要一上来写一个“大而全日志分析器”。先解决一个具体问题,脚本会更可靠。
如果日志特别大,不建议一次性 read_text 全部读入内存。更稳的方式是逐行读取。这样即使日志有几百 MB,也能慢慢处理,不容易卡住。
逐行筛选包含关键词的日志
最简单的日志筛选是按关键词查找:
from pathlib import Path
log_path = Path('app.log')
keyword = 'ERROR'
with log_path.open('r', encoding='utf-8', errors='ignore') as f:
for line_no, line in enumerate(f, start=1):
if keyword in line:
print(line_no, line.strip())errors='ignore' 可以避免少量异常字符导致整个脚本中断。日志来自不同系统时,编码不一定完全干净。正式分析时最好知道日志编码,但临时排查可以先保证脚本跑完。
如果要把筛选结果保存到文件,可以写到 output.log:
with log_path.open('r', encoding='utf-8', errors='ignore') as src, open('error_lines.log', 'w', encoding='utf-8') as out:
for line in src:
if 'ERROR' in line:
out.write(line)这样比在终端里翻大量输出更方便。
用正则提取 HTTP 状态码
如果日志里包含 HTTP 状态码,可以用正则提取。假设日志行里有类似 `status=500` 或 `status=200` 的内容:
import re
from collections import Counter
from pathlib import Path
counter = Counter()
pattern = re.compile(r'status=(\d{3})')
with Path('access.log').open('r', encoding='utf-8', errors='ignore') as f:
for line in f:
match = pattern.search(line)
if match:
counter[match.group(1)] += 1
print(counter.most_common())Counter 用来统计次数,非常适合做状态码、接口路径、错误类型这类计数。输出可能是 `[('200', 1234), ('404', 56), ('500', 12)]`。看到 500、502、503 这类状态码明显增加,就可以继续筛选对应日志行。
如果你的日志格式不同,比如状态码在引号后面、空格分隔或 JSON 字段里,正则也要相应调整。不要照搬规则。先复制几行真实日志,在正则工具里测试命中,再写入脚本。
统计接口路径和错误类型
如果日志里有接口路径,可以统计哪些接口报错最多。假设日志里有 `path=/api/order` 和 `status=500`:
import re
from collections import Counter
path_pattern = re.compile(r'path=([^\s]+)')
status_pattern = re.compile(r'status=(\d{3})')
errors = Counter()
with open('access.log', 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
status_match = status_pattern.search(line)
path_match = path_pattern.search(line)
if not status_match or not path_match:
continue
status = int(status_match.group(1))
if status >= 500:
errors[path_match.group(1)] += 1
print(errors.most_common(20))这个脚本只统计 500 以上的服务端错误,并按接口路径计数。它不能替代完整监控系统,但很适合临时排查。比如上线后某个接口突然报错,你可以快速知道错误集中在哪里。
如果日志是 JSON Lines,也就是每行一个 JSON 对象,最好用 json.loads 解析,而不是用正则硬提取。结构化日志应该用结构化方式处理,文本日志才更适合正则。
导出 CSV 方便继续分析
统计结果可以导出成 CSV,方便用表格工具或图表工具继续处理:
import csv
with open('status_count.csv', 'w', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['status', 'count'])
for status, count in counter.most_common():
writer.writerow([status, count])导出后可以用 CSV 柱状图工具画出状态码分布,或者用 CSV 工具检查数据。对周报、事故复盘、接口排查来说,图表比一堆终端输出更容易沟通。
日志里可能包含用户信息、手机号、Token、IP、订单号等敏感内容。导出和分享前要注意脱敏。临时排查可以看原始日志,但对外沟通或沉淀文档时,应该只保留必要字段。
日志脚本的实用边界
Python 日志脚本适合临时分析、一次性排查、小规模统计。它不适合替代成熟日志平台。如果你需要实时告警、长期趋势、多服务关联、链路追踪,还是应该用专门的监控和日志系统。不要把临时脚本硬改成复杂平台。
但临时脚本依然很有价值。它能帮助你快速验证猜想,比如某个错误是否从某个时间点开始,某个接口是否集中报错,某类状态码是否异常增加。很多问题先用脚本跑一遍,就能决定下一步该查代码、查数据库、查配置还是查外部服务。
写日志脚本时保留可读性。变量名写清楚,正则单独定义,输出结果简单明确。排查问题时,人已经很累了,脚本越直白越好。
常见问题
日志很大可以一次性读取吗?
不建议。大日志最好逐行读取,避免占用太多内存。
日志是 JSON 格式还要用正则吗?
如果每行是 JSON,优先用 json.loads 解析。结构化日志用结构化方式处理更稳。
状态码统计有什么用?
可以快速发现 4xx、5xx 是否异常增加,帮助判断问题集中在请求参数、权限、路径还是服务端。