--- tags: [microservice, logging, elk, loki, structured-logging] create time: 2026-05-05 --- # 日志系统 ## 概述 Logging 回答的问题是:**具体发生了什么?**——通过原始事件记录提供上下文。 在微服务架构中,所有服务的日志必须集中收集。散落在各台机器上的日志无法支撑有效的故障排查。 ```mermaid flowchart LR APP[应用容器] -->|stdout/stderr| COLLECTOR[采集器
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 格式,便于程序解析和查询: ```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 和错误堆栈**,否则毫无价值 ## 日志采集管线 ```mermaid flowchart LR App["业务应用"] -->|stdout/stderr| K8sPod["Pod 容器日志"] K8sPod --> Collector["采集器
Filebeat / FluentBit"] Collector --> Backend["存储后端
Elasticsearch / Loki"] Backend --> UI["查询面板
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 决策树 ```mermaid flowchart TD Q{"需要全文检索吗?"} Q -- "否,按时间/Service/TraceId 查询" --> LOKI["✅ Loki
低成本、轻量"] Q -- "是,复杂的全文搜索" --> ELK["✅ ELK
功能强大"] LOKI --> Check{"日日志量 > 1TB?"} Check -- 是 --> ConsiderES["考虑混合架构
高频用 Loki,低频归档到 ES"] Check -- 否 --> Done["直接用 Loki ✅"] ELK --> Check2{"团队有经验?"} Check2 -- 是 --> UseES["直接上 ES ✅"] Check2 -- 否 --> Managed["用托管版 (阿里云 SLS)"] ``` ## 采样策略 生产环境中并非所有日志都要采集。**正常路径采 1%,异常路径全量**。 ``` 正常 HTTP 200 → 1% 采样率 → 每小时 ~360 条日志 异常 HTTP 5xx → 100% 全量采集 → 可能数千条日志 DB 慢查询 → 100% 全量采集 → 重点关注 健康检查 → 不采集 → 零成本 ``` > [!tip] 实现方式 > 采样逻辑建议写在日志库的中间件层,而非业务代码里: > ```go > 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-告警管理]] — 日志可以触发基于模式的告警