Files
admin e6207aa691
build / build-and-scan (push) Waiting to run
chore(仓库对齐): 文档库结构治理 + IM/插件线落地
文档库:目录改为编号制(01-规范/02-架构设计/03-数据库/04-调整方案/
05-交接单/06-ops/07-scripts/08-skills/09-archive),顶层散文件归入 01-规范/;
INDEX.md 与 docs-manifest.json 重刷(档案 146 篇);旧目录名引用全量对齐。

IM 线:src/im/**(SDK / hub / store / presence / ws / gateway-token)、
src/web/routes/im.ts、src/db/plugin-data/**、src/supervisor/plugin-assembly.ts
及对应 test/**。

插件线:poc/{im-agent-bridge,im-connection-gateway,im-conversation-tabs,
business-plugins-im,carbon-mcp-probe}、src/web/routes/{sessions,overlay-device}.ts、
src/net/relay/{device-grant,instance-credential}.ts。

仓库卫生:清出 40 个历史误入库 / 已改名文件(34 个交接单归档 + 6 个旧结构,
本地均有副本);dsh-server-docs/.gitignore 补 tmp/;交接单不入库(政策)。
2026-09-24 07:25:16 +08:00

66 lines
2.1 KiB
Python

#!/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}')