生产问题排查 — 日志分析指南¶
服务器:81.70.101.232 最后更新:2026-03-04
一、日志分层总览¶
生产环境从外到内共 4 层日志,排查时从外向内逐层定位:
① Nginx 访问/错误日志 ← 网络层:域名解析、SSL、502/504
↓
② 前端容器日志 (stdout) ← 应用网关层:SSR 渲染、API 转发
↓
③ 后端服务日志 (stdout+文件) ← 业务层:请求处理、业务逻辑、数据库
↓
④ 基础设施日志 ← 数据层:PostgreSQL、Redis
二、各层日志位置与查看方式¶
2.1 Nginx 日志(网络层)¶
| 文件 | 用途 | 格式 |
|---|---|---|
/var/log/nginx/access.log |
所有 HTTP 请求 | combined(IP/时间/请求/状态/UA) |
/var/log/nginx/error.log |
Nginx 错误(级别 notice+) | 文本 |
# 实时跟踪所有请求
tail -f /var/log/nginx/access.log
# 过滤特定域名
grep "admin.turingfocus.cn" /var/log/nginx/access.log | tail -50
# 查看 5xx 错误
grep '" 50[0-9] ' /var/log/nginx/access.log | tail -20
# 查看 Nginx 自身错误(upstream 超时、连接拒绝等)
tail -100 /var/log/nginx/error.log
常见问题:
- 502 Bad Gateway → 后端容器未启动或端口未监听
- 504 Gateway Timeout → 后端处理超时(Nginx 默认 60s)
- connect() failed (111: Connection refused) → 容器 crash 或端口绑定错误
2.2 前端容器日志(应用网关层)¶
前端使用 Next.js,日志输出到容器 stdout/stderr,无文件日志。
# UserPortal 日志
docker logs tfrs_user_portal --tail 100
docker logs tfrs_user_portal -f # 实时跟踪
docker logs tfrs_user_portal --since 30m # 最近 30 分钟
# AdminPortal 日志
docker logs tfrs_admin_portal --tail 100
docker logs tfrs_admin_portal -f
日志内容:
- Next.js SSR 渲染错误、API Route 异常
- fetch 调用后端 API 的错误(连接拒绝、超时)
- 开发模式下的 Zod schema 校验失败(console.error)
前端错误处理机制:
- 401(非 /auth/* 路径)→ 清除 token + 重定向 /login?expired=true(会话过期)
- 4xx/5xx → 映射为 AuthError / ClientParamError / ServerError
- 未捕获异常 → React Error Boundary 兜底,展示错误页面
注意: 前端容器通过 Docker DNS 名称访问后端(http://user-service:8080、http://admin-service:8081),不经过宿主机端口。如果前端报连接拒绝,检查后端容器是否在 tfrs-net 网络中:
2.3 后端服务日志(业务层)¶
后端使用 Zap 结构化日志框架。
日志双写: 同时输出到容器 stdout(docker logs)和文件(Docker 卷)。
# 方式一:docker logs(实时跟踪)
docker logs tfrs_user -f
docker logs tfrs_user --tail 200
docker logs tfrs_user --since 10m
# 方式二:文件日志(支持 grep/jq 分析,含历史轮转)
# user-service
cat /var/lib/docker/volumes/tfrs_tfrs_user_logs/_data/app.log
cat /var/lib/docker/volumes/tfrs_tfrs_user_logs/_data/error.log
# admin-service
cat /var/lib/docker/volumes/tfrs_tfrs_admin_logs/_data/app.log
cat /var/lib/docker/volumes/tfrs_tfrs_admin_logs/_data/error.log
日志格式(生产模式 JSON):
{
"time": "2026-03-04 14:22:15.123",
"level": "info",
"caller": "middleware/logger.go:100",
"msg": "HTTP请求处理完成",
"request_id": "abc-123",
"trace_id": "4bf92f3577b34da6",
"method": "GET",
"path": "/api/v1/auth/me",
"status": 200,
"latency": "45.2ms",
"client_ip": "172.22.0.3",
"user_id": 42,
"account_id": 10,
"organization_id": 5
}
关键字段说明:
| 字段 | 含义 |
|------|------|
| request_id | 请求唯一标识,贯穿整个请求链路 |
| trace_id / span_id | OpenTelemetry 分布式追踪 ID |
| user_id / account_id / organization_id | 业务上下文,定位到具体租户 |
| caller | 代码位置(文件:行号) |
| latency | 请求耗时 |
日志级别规则:
- HTTP 5xx → ERROR
- HTTP 4xx → WARN
- HTTP 2xx/3xx → INFO
- panic 恢复 → ERROR + 完整 stacktrace
常用过滤:
# 过滤错误日志
docker logs tfrs_user --since 1h 2>&1 | grep '"level":"error"'
# 按 request_id 追踪完整请求
docker logs tfrs_user 2>&1 | grep "abc-123"
# 按用户定位
docker logs tfrs_user 2>&1 | grep '"user_id":42'
# 查看慢请求(提取 latency)
docker logs tfrs_user --since 1h 2>&1 | python3 -c "
import sys, json
for line in sys.stdin:
try:
d = json.loads(line.strip())
lat = d.get('latency','')
if 'ms' in lat and float(lat.replace('ms','')) > 1000:
print(f\"{d.get('method')} {d.get('path')} {lat}\")
except: pass
"
GORM SQL 日志: 数据库查询会以彩色文本输出到 stdout(GORM 默认 logger),包含执行时间和行数。
2.4 基础设施日志(数据层)¶
# PostgreSQL
docker logs tfrs_postgres --tail 100
docker logs tfrs_postgres -f
# Redis
docker logs tfrs_redis --tail 100
# Infisical(如需排查密钥服务)
docker logs infisical-infra-infisical-1 --tail 100
三、典型问题排查流程¶
3.1 用户报告页面打不开 / 白屏¶
1. 检查 Nginx → 域名是否正确路由
grep "turingfocus.cn" /var/log/nginx/access.log | tail -10
2. 检查前端容器 → 是否存活
docker ps | grep portal
3. 检查前端日志 → SSR 是否报错
docker logs tfrs_user_portal --tail 50
4. 如果前端报 API 连接错误 → 检查后端
docker logs tfrs_user --tail 20
3.2 API 请求报 500¶
1. 从前端日志找到具体请求路径
docker logs tfrs_user_portal --since 5m 2>&1 | grep -i error
2. 在后端日志中搜索对应的 ERROR
docker logs tfrs_user --since 5m 2>&1 | grep '"level":"error"'
3. 用 request_id 追踪完整链路
docker logs tfrs_user 2>&1 | grep "<request_id>"
4. 查看 caller 字段定位代码位置
→ 例如 "caller":"service/account_service/xxx.go:123"
5. 如果涉及数据库错误,检查 PG 日志
docker logs tfrs_postgres --since 5m
3.3 用户报告登录失败 / 会话过期¶
1. 前端 401 处理:非 /auth/ 路径的 401 会自动重定向到 /login?expired=true
→ 排查后端 JWT 是否过期或密钥变更
2. 后端日志中搜索认证错误
docker logs tfrs_user --since 30m 2>&1 | grep -E '"status":401|"status":403'
3. 检查 Redis 是否正常(token 黑名单/缓存)
docker logs tfrs_redis --tail 20
docker exec tfrs_redis redis-cli ping
3.4 部署后服务不可用¶
1. 检查容器状态
docker ps -a | grep tfrs
2. 如果容器反复重启 → 查看启动日志
docker logs tfrs_user 2>&1 | head -50
3. 常见启动失败原因:
- 数据库连接失败 → 检查 PG 容器是否健康
docker exec tfrs_postgres pg_isready
- Redis 连接失败 → 检查 Redis 容器
docker exec tfrs_redis redis-cli ping
- 环境变量缺失 → 检查 .env.prod
grep -c '=' /opt/tfrs/.env.prod
4. 健康检查端点
curl -s http://127.0.0.1:8080/health
curl -s http://127.0.0.1:8081/health
3.5 第三方支付回调失败¶
⚠️ 支付回调(支付宝/微信)通过公网域名到达,需前端配合路由到后端。
1. Nginx 日志确认回调是否到达
grep "pay\|alipay\|wechat\|notify" /var/log/nginx/access.log | tail -20
2. 前端日志确认转发情况
docker logs tfrs_user_portal --since 1h 2>&1 | grep -i "pay\|notify"
3. 后端日志确认处理结果
docker logs tfrs_user --since 1h 2>&1 | grep -i "pay\|callback\|notify"
3.6 跨服务网络不通¶
1. 确认所有容器在同一网络
docker network inspect tfrs-net --format '{{range .Containers}}{{.Name}}{{"\n"}}{{end}}'
2. 从前端容器测试 DNS 解析
docker exec tfrs_user_portal nslookup user-service 2>/dev/null || \
docker exec tfrs_user_portal cat /etc/hosts
3. 从前端容器测试连通性
docker exec tfrs_user_portal wget -qO- http://user-service:8080/health 2>&1
四、日志管理¶
Docker 日志容量¶
Docker 默认使用 json-file 驱动,日志文件无限增长。建议配置 /etc/docker/daemon.json:
当前日志存储位置¶
| 来源 | 位置 | 轮转 |
|---|---|---|
| Nginx access/error | /var/log/nginx/ |
系统 logrotate |
| 前端容器 stdout | Docker json-file | 50MB × 3 份(daemon.json) |
| 后端容器 stdout | Docker json-file | 50MB × 3 份(daemon.json) |
| 后端文件日志 | Docker 卷 /var/lib/docker/volumes/tfrs_tfrs_{user,admin}_logs/_data/ |
Lumberjack(100MB/10份/30天) |
| PG/Redis 容器 | Docker json-file | 50MB × 3 份(daemon.json) |
注意事项¶
- 容器以 UID 65532(nonroot)运行,日志卷目录需确保该用户有写权限
LOG_DIR必须设为绝对路径/app/logs(匹配 Docker 卷挂载),不可使用相对路径- Docker daemon 日志限制(
daemon.json)仅对新创建的容器生效,修改后需重建容器
五、快速命令速查¶
# === 一键查看所有服务状态 ===
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
# === 所有服务最近错误 ===
for c in tfrs_user tfrs_admin tfrs_user_portal tfrs_admin_portal; do
echo "=== $c ==="
docker logs $c --since 10m 2>&1 | grep -i error | tail -5
done
# === Nginx 最近 5xx ===
grep '" 50[0-9] ' /var/log/nginx/access.log | tail -10
# === 磁盘/内存快速检查 ===
df -h / && echo "---" && free -h
# === Docker 日志占用 ===
du -sh /var/lib/docker/containers/*/