日志最佳实践
日志规范
统一格式(JSON)
{
"timestamp": "2024-01-15T10:30:00.123Z",
"level": "ERROR",
"service": "order-service", // 服务名
"instance": "order-service-abc", // 实例标识
"traceId": "abc123", // 链路追踪 ID
"spanId": "def456",
"message": "创建订单失败",
"error": {
"type": "InsufficientBalanceError",
"message": "余额不足",
"stack": "..."
},
"context": {
"userId": "u_10086",
"orderId": "o_20240115_001",
"duration_ms": 230
}
}
日志该记什么
| ✅ 应该记录 | ❌ 不该记录 |
|---|---|
| 请求入口和响应(含耗时) | 密码、Token、密钥 |
| 错误和异常(含堆栈) | 身份证、银行卡号 |
| 关键业务节点(支付、下单) | 大段 Base64、二进制 |
| 外部调用(数据库、RPC) | 循环内的日志 |
| 配置变更 | 用户聊天内容 |
日志轮转
logrotate 配置
/etc/logrotate.d/app
/var/log/app/*.log {
daily # 每天轮转
rotate 30 # 保留 30 天
compress # gzip 压缩
delaycompress # 延迟一天压缩(方便查看昨天日志)
missingok # 文件不存在不报错
notifempty # 空文件不轮转
copytruncate # 复制后截断(不需要重启应用)
maxsize 500M # 超过 500MB 也轮转
dateext # 文件名加日期后缀
}
日志脱敏
masking.py
import re
PATTERNS = {
'phone': (r'1[3-9]\d{9}', lambda m: m.group()[:3] + '****' + m.group()[-4:]),
'idcard': (r'\d{17}[\dXx]', lambda m: m.group()[:6] + '********' + m.group()[-4:]),
'email': (r'[\w.]+@[\w.]+', lambda m: m.group()[0] + '***@' + m.group().split('@')[1]),
'bankcard': (r'\d{16,19}', lambda m: m.group()[:4] + ' **** **** ' + m.group()[-4:]),
}
def mask_sensitive(text: str) -> str:
for name, (pattern, replacer) in PATTERNS.items():
text = re.sub(pattern, replacer, text)
return text
日志分级存储策略
| 时间段 | 存储位置 | 索引 | 查询速度 |
|---|---|---|---|
| 0-7 天 | ES 热节点(SSD) | 全量 | 最快 |
| 7-30 天 | ES 温节点(HDD) | 全量 | 中等 |
| 30-90 天 | ES 冷节点 / S3 | 仅标签 | 较慢 |
| 90 天+ | S3 Glacier / 归档 | 无 | 按需恢复 |
日志告警
loki-alert-rules.yaml
groups:
- name: log-alerts
rules:
# 1 分钟内某服务 ERROR 超过 50 条
- alert: HighErrorRate
expr: |
sum by(app)(count_over_time({namespace="production"} |= "ERROR" [1m])) > 50
for: 2m
labels:
severity: warning
annotations:
summary: "{{ $labels.app }} 错误日志激增"
# 出现 OOM 关键词
- alert: OOMDetected
expr: |
count_over_time({namespace="production"} |~ "OutOfMemoryError|OOM|oom-kill" [5m]) > 0
labels:
severity: critical
常见面试问题
Q1: 生产环境日志级别怎么设置?
答案:
- 业务服务:INFO 级别,关键路径可用 WARN
- 中间件:WARN 级别
- DEBUG 日志只在开发/测试环境启用
- 支持动态日志级别调整(如通过配置中心热更新),排查问题时临时开启 DEBUG
Q2: 日志量太大怎么办?
答案:
- 采集端过滤:丢弃 healthcheck、DEBUG 日志
- 采样:高频日志只保留 10%(如 access log)
- 异步写入:应用内异步队列写日志,不阻塞业务
- 分级存储:热数据 SSD、温数据 HDD、冷数据对象存储
- 日志轮转:logrotate 控制单文件大小
- 精简内容:不记录不必要的字段(如大 payload)