5.1 KiB
5.1 KiB
tags, create time
| tags | create time | |||||
|---|---|---|---|---|---|---|
|
2026-05-05 |
日志系统
概述
Logging 回答的问题是:具体发生了什么?——通过原始事件记录提供上下文。
在微服务架构中,所有服务的日志必须集中收集。散落在各台机器上的日志无法支撑有效的故障排查。
flowchart LR
APP[应用容器] -->|stdout/stderr| COLLECTOR[采集器<br/>FLUENTD / Filebeat]
COLLECTOR --> PARSE["解析 & 过滤"]
PARSE --> ES[(Elasticsearch)]
PARSE --> LOKI[(Loki)]
ES --> GRAF["Grafana / Kibana"]
LOKI --> GRAF
style COLLECTOR fill:#fff3e0
style PARSE fill:#e3f2fd
结构化日志
不要写纯文本日志。推荐 JSON 格式,便于程序解析和查询:
{
"timestamp": "2026-05-05T10:30:00Z",
"level": "ERROR",
"service": "order-service",
"trace_id": "abc-123-def",
"span_id": "span-456",
"msg": "failed to connect payment service",
"caller": "payment/client.go:42",
"cost_ms": 30000,
"user_id": "user-42"
}
最小字段集合(必选)
| 字段 | 格式 | 说明 |
|---|---|---|
timestamp |
ISO 8601 (2026-05-05T10:30:00Z) |
UTC 时区,不可省略 |
level |
TRACE / DEBUG / INFO / WARN / ERROR / FATAL | 大小写统一 |
service |
字符串 | 微服务名称 |
trace_id |
字符串 | 链路追踪 ID,与 Tracing 串联 |
msg |
字符串 | 人类可读的消息描述 |
日志级别使用规范
| 级别 | 使用场景 | 示例 |
|---|---|---|
| TRACE | 调试级详细输出(仅开发环境) | 方法入参/出参、循环体内部状态 |
| DEBUG | 诊断信息 | 缓存命中率、连接池状态 |
| INFO | 关键业务事件 | 下单成功、支付回调、用户注册 |
| WARN | 异常但不致命 | 重试了一次、走降级、配置热更新 |
| ERROR | 影响单个请求的失败 | DB 超时、下游调用失败、空指针 |
| FATAL | 进程无法继续运行 | 配置文件缺失、依赖服务完全不可用 |
[!warning] 最佳实践
- 不要记录敏感信息:密码、Token、身份证号等绝不能出现在日志中
- INFO 级记录关键业务事件——这些是排查业务问题的主线
- WARN 级记录异常但不致命——如重试、降级
- ERROR 级必须有 trace_id 和错误堆栈,否则毫无价值
日志采集管线
flowchart LR
App["业务应用"] -->|stdout/stderr| K8sPod["Pod 容器日志"]
K8sPod --> Collector["采集器<br/>Filebeat / FluentBit"]
Collector --> Backend["存储后端<br/>Elasticsearch / Loki"]
Backend --> UI["查询面板<br/>Grafana / Kibana"]
Collector -->|"过滤掉 health check"| Drop["丢弃无用日志"]
style Drop fill:#ffebee,stroke:#ef5350
采集器选型
| 组件 | 语言 | 资源消耗 | 特点 |
|---|---|---|---|
| Filebeat (ELK) | Go | 低 | 轻量,适合 K8s DaemonSet |
| Fluentd | Ruby | 中 | 插件生态丰富,处理灵活 |
| FluentBit | C | 极低 | 边缘场景首选,K8s 官方推荐 |
日志方案对比
| 方案 | 存储 | 查询能力 | 成本 | 适用场景 |
|---|---|---|---|---|
| ELK (Elasticsearch) | ES 集群 | 全文检索强大 | 高 | 日志量大、需要复杂分析 |
| Loki + Grafana | 对象存储 (S3) | Label 索引 + LogQL | 低 | 已在用 Grafana 的团队 |
| 云 SLS / CloudWatch | 云托管 | 开箱即用 | 中~高 | 全云原生环境 |
Loki vs ELK 决策树
flowchart TD
Q{"需要全文检索吗?"}
Q -- "否,按时间/Service/TraceId 查询" --> LOKI["✅ Loki<br/>低成本、轻量"]
Q -- "是,复杂的全文搜索" --> ELK["✅ ELK<br/>功能强大"]
LOKI --> Check{"日日志量 > 1TB?"}
Check -- 是 --> ConsiderES["考虑混合架构<br/>高频用 Loki,低频归档到 ES"]
Check -- 否 --> Done["直接用 Loki ✅"]
ELK --> Check2{"团队有经验?"}
Check2 -- 是 --> UseES["直接上 ES ✅"]
Check2 -- 否 --> Managed["用托管版 (阿里云 SLS)"]
采样策略
生产环境中并非所有日志都要采集。正常路径采 1%,异常路径全量。
正常 HTTP 200 → 1% 采样率 → 每小时 ~360 条日志
异常 HTTP 5xx → 100% 全量采集 → 可能数千条日志
DB 慢查询 → 100% 全量采集 → 重点关注
健康检查 → 不采集 → 零成本
[!tip] 实现方式 采样逻辑建议写在日志库的中间件层,而非业务代码里:
func SampleLogger(next logger.Logger, rate float64) logger.Logger { return &sampledLogger{ next: next, shouldSample: func() bool { return rand.Float64() < rate }, } }
关联笔记
- 04-可观测性/01-Metrics监控 — Metrics + Logging = 完整的问题定位能力
- 04-可观测性/03-链路追踪 — trace_id 是日志与追踪的桥梁
- 04-可观测性/04-告警管理 — 日志可以触发基于模式的告警