一个面向家庭/小型机房/NAS 环境的 Docker 化 Syslog 日志分析 Web 程序。
项目使用 Python 3.11 + FastAPI + Bootstrap + 原生 JavaScript,读取容器内 /logs 下的 syslog-ng 落盘日志,把网络设备、Linux、NAS、SMB 审计、传输任务、存储/UPS/容器等日志翻译成中文,并按规则自动判断问题、给出排障建议。
- 路由器、交换机、防火墙、AP 等网络设备集中上报 syslog。
- syslog-ng 已经把日志落盘到宿主机目录。
- 希望在浏览器里查看最近日志、搜索关键词、过滤设备和严重级别。
- 希望把英文/原始设备日志翻译成中文。
- 希望自动识别常见问题,例如链路抖动、WAN/PPPoE/DHCP/DNS 异常、异常重启、认证失败、内核崩溃、NAS 存储告警等。
- 希望保留 NAS 审计:谁 SSH 登录、谁执行管理命令、谁改了 NAS 配置、谁访问了哪个共享文件。
- 希望直接读取 UGREEN NAS “日志中心”的 SQLite 记录,包括登录、控制面板、Samba 连接和文件传输/写入记录。
- 日志文件列表:支持
messages、messages-kv.log、remote/<设备名>/<日期>.log。 - 日志明细表:显示时间、设备、级别、中文解释、原始日志;默认合并连续近似日志,降低刷屏。
- 查询过滤:支持最近
100 / 500 / 1000行、关键词、设备名、严重级别。 - 自动分析:输出问题标题、严重级别、时间范围、涉及设备、相关原始日志、中文解释、可能原因、建议处理步骤。
- 规则库:所有识别规则集中在
rules.yaml,方便后续维护。 - 可选 AI 分析:启用后可调用 OpenAI 兼容接口,例如
deepseek-v4-flash。 - 安全读取:防止路径穿越,只允许读取容器内
/logs和可选的/nas-log-center。 - NAS 日志中心:可只读挂载
/var/lib/log_serv,在页面中作为nas-log-center/log_server_record.db和nas-log-center/transfer_log.db两个虚拟日志源查询。 - NAS 自噪声过滤:默认不显示直接引用
/volume1/docker/syslog*相关目录的自维护日志,避免分析器自己的项目目录刷屏。 - 日志保留策略:提供 syslog-ng 落盘目录的定期压缩、归档和过期清理脚本。
.
├── app/
│ ├── __init__.py
│ ├── ai_analyzer.py
│ ├── analyzer.py
│ ├── log_reader.py
│ ├── main.py
│ ├── nas_log_center.py
│ └── rules_engine.py
├── ops/
│ ├── install-router-crash-collector.sh
│ ├── router-crash-collector.sh
│ ├── syslog-retention.sh
│ ├── syslog-retention.service
│ └── syslog-retention.timer
├── static/
│ ├── app.js
│ ├── index.html
│ └── styles.css
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── rules.yaml
├── tests/
│ └── test_router_analysis.py
├── .dockerignore
├── .gitignore
└── README.md
假设 syslog-ng 日志已经在宿主机:
/volume1/docker/syslog/log
其中可能包含:
/volume1/docker/syslog/log/messages
/volume1/docker/syslog/log/messages-kv.log
/volume1/docker/syslog/log/remote/<设备名>/<日期>.log
克隆项目并启动:
git clone https://github.com/zhr2038/syslog-analyzer.git
cd syslog-analyzer
docker compose up -d --build访问:
http://<宿主机IP>:8080
例如:
http://192.168.1.15:8080
健康检查:
curl http://127.0.0.1:8080/health默认 docker-compose.yml:
services:
syslog-analyzer:
build: .
container_name: syslog-analyzer
ports:
- "8080:8080"
environment:
- TZ=Asia/Shanghai
- LOG_ROOT=/logs
- RULES_FILE=/app/rules.yaml
- ENABLE_NAS_LOG_CENTER=${ENABLE_NAS_LOG_CENTER:-true}
- NAS_LOG_CENTER_DIR=${NAS_LOG_CENTER_DIR:-/nas-log-center}
- NAS_LOG_CENTER_DEVICE=${NAS_LOG_CENTER_DEVICE:-NAS}
- ENABLE_AI=${ENABLE_AI:-false}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.deepseek.com}
- OPENAI_MODEL=${OPENAI_MODEL:-deepseek-v4-flash}
- AI_TIMEOUT_SECONDS=${AI_TIMEOUT_SECONDS:-90}
volumes:
- /volume1/docker/syslog/log:/logs:ro
- /var/lib/log_serv:/nas-log-center:ro
restart: unless-stopped如果你的日志目录不同,请修改 volume 左侧路径;容器内路径保持 /logs。
AI 默认关闭。启用后,页面会出现可用的“AI 分析当前日志”按钮。
后端只会发送用户当前筛选条件下被选中的日志,并在发送前自动脱敏:
- IP
- MAC
- 账号
- SN/序列号
- 手机号
在部署目录创建 .env:
cat > .env <<'EOF'
ENABLE_AI=true
OPENAI_API_KEY=你的 API Key
OPENAI_BASE_URL=https://api.deepseek.com
OPENAI_MODEL=deepseek-v4-flash
AI_TIMEOUT_SECONDS=90
EOF重启:
docker compose up -d --build检查状态:
curl http://127.0.0.1:8080/health注意:不要把 .env 提交到 GitHub。
AI 选择模式:
按设备重要日志:默认模式。后端先扩大扫描窗口,再按设备分组,按严重级别和问题类别选取每台设备的前 N 条重要日志,避免 NAS 高频日志挤掉路由器、AP 等设备。当前最近日志:保持旧逻辑,只分析当前筛选条件下的最近 N 行。
页面里的“每设备”表示每台设备最多发送多少条重要日志;最终发送总量仍受页面“行数”和服务端 MAX_AI_LINES=1000 限制。
规则文件是 rules.yaml。
每条规则至少包含:
- id: custom_rule
pattern: '\byour regex here\b'
severity: warning
category: custom_category
chinese_summary: 中文解释
suggestion: 处理建议字段说明:
pattern:正则表达式,忽略大小写。severity:critical、error、warning、info。category:分类,自动分析会根据分类聚合问题。chinese_summary:日志明细表展示的中文解释。suggestion:单条日志层面的处理建议。
修改规则后重启容器:
docker compose restart syslog-analyzer网络与系统:
- link down / link up
- port flapping
- reboot / restart / watchdog
- kernel panic / oops / crash
- WAN down
- PPPoE down
- DHCP failed / 地址池耗尽
- DNS failed
- NTP 异常
- VPN 异常
- 防火墙拒绝/丢弃
- Wi-Fi 终端断开
- IP/ARP 冲突
- 接口 CRC/丢包/协商错误
- 存储空间或文件系统异常
- CPU/内存压力
- 温度、风扇、电源异常
NAS 审计与运维:
- SMB 文件访问成功/失败
- 日志中心里的 Samba 连接、读取、写入、创建、删除、重命名
- SMB/Samba 服务连接异常
- NAS SSH 登录成功
- NAS Web/客户端登录成功/失败
- SSH 会话断开
- sudo/su 管理命令
- NAS 配置、共享、权限、账号、服务变更
- 传输、同步、下载、备份任务状态和失败
- 存储、磁盘、卷、RAID 状态变化和异常
- UPS/电池/供电告警
- Docker/容器状态和异常
程序会按时间窗口和分类聚合日志,识别例如:
- 短时间多次
reboot/restart/watchdog:设备疑似异常重启。 WAN down后出现PPPoE down或DHCP failed:外网链路或运营商接入异常。- 同一接口反复
link up/down:链路抖动。 - 多次
DNS failed:DNS 解析异常。 thermal/fan/power:硬件或环境告警。- 连续认证失败:密码错误或异常登录尝试。
kernel panic/oops/crash:内核、驱动或固件异常。- NAS 传输失败:同步/下载/备份任务异常。
- NAS 配置失败:权限、共享、账号或服务设置没有成功生效。
- NAS 存储告警:磁盘、卷、RAID 或文件系统需要优先检查。
每个问题会输出:
- 问题标题
- 严重级别
- 发生时间范围
- 涉及设备
- 相关原始日志
- 中文解释
- 可能原因
- 建议处理步骤
GET /health
GET /api/files
GET /api/logs?file=messages&limit=500&keyword=pppoe
GET /api/logs?file=remote/router/2026-07-09.log&limit=1000&device=router&severity=warning
GET /api/logs?file=messages&limit=500&compact=false
GET /api/analyze?file=messages&limit=2000
GET /api/summary
GET /api/ai-analyze?file=messages&limit=500&severity=warning
GET /api/ai-analyze?limit=500&ai_mode=balanced&per_device_limit=30
GET /api/rules
说明:
file必须是/logs下的相对路径。- 不允许绝对路径。
- 不允许
../../路径穿越。 /api/logs默认compact=true,会把连续近似日志合并展示;需要逐行原始日志时设置compact=false。compact_gap_seconds默认120,表示相邻两条近似日志在该时间间隔内才会合并。/api/ai-analyze默认ai_mode=balanced,按设备均衡选择重要日志;设置ai_mode=recent可使用最近 N 行。per_device_limit默认30,表示每台设备最多选取多少条重要日志。/api/ai-analyze只有在ENABLE_AI=true且配置了OPENAI_API_KEY后可用。
UGREEN NAS 的“日志中心”会把结构化记录保存在:
/var/lib/log_serv/log_server_record.db
/var/lib/log_serv/transfer_log.db
项目默认把该目录只读挂载到容器:
volumes:
- /var/lib/log_serv:/nas-log-center:ro挂载成功后,页面“日志文件”下拉会出现:
nas-log-center/log_server_record.db
nas-log-center/transfer_log.db
这两个虚拟日志源支持和普通 syslog 文件一样的查询能力:
- 按用户名搜索,例如
zhr2038、cctv。 - 按来源 IP 搜索,例如
192.168.1.141。 - 按文件路径搜索,例如
/volume2/CCTV。 - 按模块搜索,例如
login、samba、control_panel。
典型内容:
log_server_record.db:登录、控制面板、Samba 连接、系统启动/关机、存储管理等。transfer_log.db:Samba 文件读取、写入、创建、删除、重命名、传输类记录。
相关环境变量:
ENABLE_NAS_LOG_CENTER=true
NAS_LOG_CENTER_DIR=/nas-log-center
NAS_LOG_CENTER_DEVICE=HR-Cloud如果不是 UGREEN NAS,或者没有 /var/lib/log_serv,可以关闭:
ENABLE_NAS_LOG_CENTER=false推荐宿主机目录:
/volume1/docker/syslog/log
推荐落盘文件:
/volume1/docker/syslog/log/messages
/volume1/docker/syslog/log/messages-kv.log
/volume1/docker/syslog/log/remote/${HOST}/${YEAR}-${MONTH}-${DAY}.log
容器映射:
volumes:
- /volume1/docker/syslog/log:/logs:ro如果 syslog-ng 本身也是 Docker 容器,建议:
- UDP 514 映射到 syslog-ng 容器的 UDP 接收端口。
- TCP 601 映射到 syslog-ng 容器的 TCP 接收端口。
- 日志目录统一写到
/volume1/docker/syslog/log。 - 分析器只读挂载日志目录,避免误写。
仅依赖路由器普通 syslog 很难还原崩溃:内核 panic 可能在 UDP 日志发送前就已复位,而内存里的运行状态也会随重启消失。本项目为 ASUSWRT-Merlin 提供了一个轻量采集器:
- 启动后上报
BOOT_MARKER,包含 boot ID、固件版本、NVRAM 重启原因和硬件 reset reason。 - 正常关机/重启前上报
CLEAN_SHUTDOWN。下次启动如没有该标记,上报UNCLEAN_BOOT。 - 每 5 分钟上报
HEARTBEAT,记录运行时长、load、可用内存、conntrack 用量和温度。 - 启动后从
mtdoops/crashlog分区提取 panic/oops 关键调用链,通过远程 syslog 保存到 NAS。 - 对可用内存、conntrack、负载和温度设置告警阈值,只有超限才发送
RESOURCE_ALERT。 - 采集器不修改 WAN、IPv6、硬件加速或无线配置,也不会主动重启路由器。
前置条件:
- 路由器已开启 JFFS 自定义脚本。
- 路由器远程 syslog 已指向 syslog-ng 服务器的 UDP 514。
- 固件支持
/jffs/scripts/services-start、services-stop和cru,ASUSWRT-Merlin/KoolShare 通常已具备。
上传并安装:
scp ops/router-crash-collector.sh ops/install-router-crash-collector.sh admin@<路由器IP>:/tmp/
ssh admin@<路由器IP>
sh /tmp/install-router-crash-collector.sh安装器会保留现有 services-start/services-stop,只在文件尾部追加带标记的采集器调用,并生成 .syslog-analyzer.bak 备份。
检查状态:
/jffs/scripts/router-crash-collector.sh status
cru l | grep RouterCrashCollector
tail -n 100 /jffs/syslog.log | grep router-crash-collector手工发送一次资源心跳:
/jffs/scripts/router-crash-collector.sh sample重要判读原则:crashlog 可能保留的是上一个固件版本的历史崩溃。应对比 CRASHLOG_BEGIN 中的当前固件和 crashlog 原文里的 kernel build,只有新固件上再次出现同一调用链,才能判定故障仍未修复。
已内置的路由器专项规则包括:
- 非正常启动与正常关机区分。
- kernel panic、Oops、NULL pointer、Call trace。
bcmsw_rx -> bcm_tcp_v4_recv -> tcp_v6_syn_recv_sock -> inet6_sk_rx_dst_setBroadcom IPv6 崩溃路径。rc_service watchdog stop_aae/start_mastiff服务重启风暴,不再误判为整机重启。- crashlog NAND 不可纠正错误和
mtdblock3I/O error。 - OOM、conntrack 耗尽、高负载、高温、看门狗复位。
路由器管理端口建议只对 LAN/管理网开放。如 syslog 中持续出现公网 IP 连接 SSH/Web,应关闭 WAN 侧管理、改用 VPN 远程接入,并使用 SSH 密钥替代密码。
为了避免 /volume1/docker/syslog/log 不断增长,项目提供了宿主机侧保留脚本:
ops/syslog-retention.sh
默认策略:
remote/<设备>/<日期>.log:超过 2 天后压缩到/volume1/docker/syslog/archive/remote/.../*.gz。messages、messages-kv.log:超过 200 MB 时轮转,并通知syslog-ng容器重新打开日志文件。- 归档压缩包:默认保留 45 天,超过后删除。
- 分析器只读取
/volume1/docker/syslog/log,不会扫描 archive 目录。
安装到宿主机 systemd:
sudo install -m 0755 ops/syslog-retention.sh /usr/local/sbin/syslog-retention.sh
sudo install -m 0644 ops/syslog-retention.service /etc/systemd/system/syslog-retention.service
sudo install -m 0644 ops/syslog-retention.timer /etc/systemd/system/syslog-retention.timer
sudo systemctl daemon-reload
sudo systemctl enable --now syslog-retention.timer先演练不实际删除:
sudo DRY_RUN=true /usr/local/sbin/syslog-retention.sh立即执行一次:
sudo systemctl start syslog-retention.service查看定时器:
systemctl list-timers syslog-retention.timer
journalctl -u syslog-retention.service -n 100 --no-pager可调整参数:
Environment=RETENTION_DAYS=45
Environment=COMPRESS_AFTER_DAYS=2
Environment=ROTATE_ACTIVE_MAX_MB=200
Environment=SYSLOG_CONTAINER=syslog-ng如果你的 syslog-ng 容器名称不是 syslog-ng,请修改 SYSLOG_CONTAINER。
NAS 本机可以通过 rsyslog 转发一份日志到 syslog-ng。
推荐保留:
smbd_audit:谁访问了哪个共享文件。sshd/ug_login:谁登录了 NAS。sudo/su:谁执行了管理命令。conf_tool/ugos_serv/filemgr_serv:谁修改了配置、共享、权限、账号。syncbackup_serv/xunlei_serv/rsync/rclone:传输、下载、同步、备份。storage_serv/mdadm/smartd:存储、磁盘、RAID、SMART。usbhid-ups/upsd/upsmon:UPS。docker_serv/dockerd/containerd:容器。
本项目默认会在 Web/API 层隐藏直接包含以下路径的自维护噪声:
/volume1/docker/syslog
/volume1/docker/syslog-analysis
/volume1/docker/syslog-analyzer
如需调整,设置环境变量:
AUDIT_PATH_EXCLUDES=/volume1/docker/syslog,/volume1/docker/syslog-analysis,/volume1/docker/syslog-analyzer确认宿主机目录存在:
ls -lah /volume1/docker/syslog/log确认容器能看到 /logs:
docker exec -it syslog-analyzer sh -lc "ls -lah /logs && find /logs -maxdepth 3 -type f | head"查看健康检查:
curl http://127.0.0.1:8080/health查看容器日志:
docker logs --tail=200 syslog-analyzer确认 compose 的挂载是只读:
- /volume1/docker/syslog/log:/logs:ro如果 /health 显示 log_root_exists: false,说明容器内没有看到 /logs,优先检查宿主机路径和 volume 映射。
- 程序不需要登录,适合局域网内使用。
- 默认监听
0.0.0.0:8080。 - 日志目录以只读方式挂载。
- API 会阻止路径穿越。
- AI 分析默认关闭。
.env、API Key、密码、真实密钥不应提交到仓库。
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
LOG_ROOT=/path/to/syslog/log uvicorn app.main:app --host 0.0.0.0 --port 8080 --reload浏览器打开:
http://127.0.0.1:8080