1. 为什么我们需要关注日志记录?
日志系统就像飞机的黑匣子,记录着系统运行时的每一个关键动作。我在处理线上故障时,90%的案例都是通过日志快速定位的。最近一个典型例子:某电商系统在促销期间突然出现订单丢失,最终通过Nginx访问日志发现是负载均衡策略导致请求被错误路由。
现代系统日志已从简单的文本记录发展为包含:
- 结构化日志(JSON格式)
- 分布式追踪(TraceID串联)
- 指标监控(Prometheus格式)
- 安全审计(符合ISO27001标准)
2. 日志记录的核心要素设计
2.1 日志级别划分实践
我建议采用五级分类法(从低到高):
- DEBUG:开发调试用,如变量值打印
- INFO:关键业务流程节点,如"用户登录成功"
- WARNING:可恢复的异常,如缓存失效回源
- ERROR:需要干预的故障,如数据库连接失败
- CRITICAL:系统级故障,如磁盘写满
关键经验:线上环境默认只记录INFO及以上级别,通过动态调整功能(如Log4j2的JMX控制)临时开启DEBUG排查问题
2.2 日志内容规范
优秀日志应包含:
# 反面案例(无用日志) logger.info("Processing request") # 正面案例 logger.info( f"[订单创建] 用户:{user_id} 商品:{sku_ids} 金额:{amount}", extra={ "trace_id": request_id, "client_ip": remote_addr } )必须包含的要素:
- 业务场景标识(如[订单创建])
- 关键业务参数(用户ID等)
- 请求上下文(TraceID、IP等)
- 时间戳(建议UTC格式)
3. 主流日志方案对比选型
3.1 单机场景方案
| 工具 | 优势 | 适用场景 | 性能影响 |
|---|---|---|---|
| Log4j2 | 异步日志、动态配置 | Java应用 | 低 |
| Zap | 零内存分配、结构化日志 | Go应用 | 极低 |
| Winston | 多传输协议支持 | Node.js应用 | 中 |
3.2 分布式系统方案
ELK Stack实战配置示例:
# Filebeat配置片段 filebeat.inputs: - type: log paths: - /var/log/app/*.log fields: env: production output.elasticsearch: hosts: ["es01:9200"] indices: "app-logs-%{+yyyy.MM.dd}"关键考量点:
- 日志采集延迟(Filebeat vs Fluentd)
- 存储成本(ES冷热数据分离)
- 查询性能(合理设置分片数)
4. 问题定位的实战技巧
4.1 高频问题排查模式
超时问题:
- 检查日志中的时间戳差值
- 示例:
[API] start=2023-07-20T08:00:00.000Z end=2023-07-20T08:00:05.123Z
并发问题:
- 搜索重复的TraceID
- 检查线程ID是否冲突
数据不一致:
- 对比不同服务的日志时间线
- 使用
jq工具分析JSON日志差异
4.2 高级分析工具链
Linux基础工具组合:
# 实时监控错误日志 tail -f app.log | grep --color -E 'ERROR|CRITICAL' # 统计错误类型分布 awk '/ERROR/{print $5}' app.log | sort | uniq -c | sort -nr日志可视化分析:
- Grafana + Loki的LogQL查询:
{app="order-service"} |= "Timeout" | pattern `<ip> - <_> "<method> <uri> <_>" <status> <_> <latency>` | latency > 5s
5. 生产环境日志管理规范
5.1 日志切割策略
推荐采用时间+大小双维度滚动:
# Log4j2配置示例 <RollingFile name="FileAppender" fileName="app.log" filePattern="app-%d{yyyy-MM-dd}-%i.log"> <Policies> <TimeBasedTriggeringPolicy interval="1"/> <SizeBasedTriggeringPolicy size="500MB"/> </Policies> </RollingFile>5.2 敏感信息过滤
必须处理的敏感字段:
- 身份证/银行卡号(正则过滤)
- 密码/Token(完全屏蔽)
- IP地址(生产环境脱敏)
实现方案示例:
// Logback的替换规则 <replace> <regex>\b\d{18}\b</regex> <replacement>***ID***</replacement> </replace>6. 典型故障排查案例
最近处理的Redis连接泄漏问题:
- 现象:服务每隔几天就出现连接超时
- 排查过程:
- 发现ERROR日志中有"Connection timeout"
- 通过
netstat确认连接数持续增长 - 在代码中找到未关闭的连接池
- 解决方案:
- 添加try-with-resources块
- 增加连接数监控日志
日志关键片段:
[REDIS] Connection pool stats: active=78, idle=2, max=100这个案例让我养成了在资源操作类日志中强制记录状态指标的习惯