Files

65 lines
2.1 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
"""nginx 访问日志慢请求/大响应分析(只读)
用法: python3 nginx-slow.py <logfile> [host子串] [最近N行] [起始时间标记]
"""
import re
import sys
log = sys.argv[1]
host = sys.argv[2] if len(sys.argv) > 2 else ''
tail_lines = int(sys.argv[3]) if len(sys.argv) > 3 else 20000
since = sys.argv[4] if len(sys.argv) > 4 else ''
LINE = re.compile(
r'^(?P<ip>\S+) \S+ \S+ \[(?P<time>[^\]]+)\] "(?P<req>[^"]*)" (?P<status>\d{3}) (?P<bytes>\d+)'
r'(?: "[^"]*" "[^"]*")?(?P<rest>.*)$'
)
rows = []
with open(log, 'r', errors='replace') as fh:
lines = fh.readlines()[-tail_lines:]
for line in lines:
if host and host not in line:
continue
if since and since not in line:
continue
m = LINE.match(line)
if not m:
continue
times = re.findall(r'(\d+\.\d+)', m.group('rest'))
rt = float(times[-1]) if times else None
rows.append(
{
'ip': m.group('ip'),
'time': m.group('time'),
'req': m.group('req'),
'status': int(m.group('status')),
'bytes': int(m.group('bytes')),
'rt': rt,
}
)
print(f'匹配请求数: {len(rows)}')
if not rows:
sys.exit(0)
withrt = [r for r in rows if r['rt'] is not None]
if withrt:
ts = [r['rt'] for r in withrt]
slow = [r for r in withrt if r['rt'] > 1]
print(f'耗时: 平均 {sum(ts)/len(ts):.3f}s 中位 {sorted(ts)[len(ts)//2]:.3f}s 最大 {max(ts):.2f}s >1s 的 {len(slow)} 个')
print('\n== 最慢 12 个 ==')
for r in sorted(withrt, key=lambda x: -x['rt'])[:12]:
print(f" {r['rt']:8.2f}s {r['status']} {r['bytes']:>9} B {r['time'][12:]} {r['req']}")
print('\n== 响应体最大 8 个 ==')
for r in sorted(rows, key=lambda x: -x['bytes'])[:8]:
rt = f"{r['rt']:.2f}s" if r['rt'] is not None else ' ? '
print(f" {r['bytes']:>9} B {rt} {r['status']} {r['req']}")
from collections import Counter
c = Counter(r['req'].split(' ')[1].split('?')[0] if ' ' in r['req'] else r['req'] for r in rows)
print('\n== 路径 TOP 10 ==')
for path, n in c.most_common(10):
print(f' {n:5} {path}')