4. 日志采集与标准化:Promtail 配置最佳实践、结构化日志(JSON/Logfmt)的采集与解析
在可观测性体系中,日志采集是数据管道的“第一公里”。如果采集端配置不当或日志格式混乱,后续的告警降噪、弹性伸缩决策将失去可靠的数据基础。本章聚焦 Promtail 的配置最佳实践,以及如何通过结构化日志(JSON / Logfmt)实现高效、可解析的日志采集。
4.1 Promtail 配置核心原则
Promtail 是 Loki 的官方日志采集 Agent,负责从文件、系统日志、容器 stdout/stderr 等源拉取日志,并附加标签后推送至 Loki。配置不当会导致日志丢失、标签爆炸或性能瓶颈。
| 原则 | 说明 | 常见反例 |
|---|---|---|
| 标签最小化 | 仅保留用于查询过滤和聚合的标签(如 service、env、pod),避免将高基数字段(如 request_id、user_id)设为标签 | 将 trace_id 作为标签,导致索引膨胀 |
| 静态标签优先 | 使用 __path__ 或文件路径提取静态标签,减少运行时动态标签 | 所有标签都通过 relabel_configs 动态生成 |
| 管道处理轻量化 | 在 Promtail 中只做必要的标签提取和格式转换,复杂解析留给 Loki 的 logql 或下游系统 | 在 Promtail 中做正则提取 20 个字段 |
| 批量与缓冲 | 合理设置 batch_size 和 batch_wait,平衡延迟与吞吐 | batch_size 设为 1MB 但网络带宽不足,导致推送超时 |
positions 文件,确保 Agent 重启后不会重复采集或遗漏日志。默认路径为 /var/log/positions.yaml。
4.2 结构化日志:JSON 与 Logfmt 的采集与解析
非结构化日志(纯文本)在查询时只能依赖全文搜索,效率低且难以提取字段。结构化日志将日志内容拆分为键值对,使 Loki 能够直接索引和过滤特定字段,是告警降噪和弹性伸缩决策的关键前提。
4.2.1 JSON 格式日志采集
JSON 是最通用的结构化日志格式,Promtail 通过 json 管道阶段自动解析。以下是一个典型的 JSON 日志行:
{"timestamp":"2025-03-21T10:00:00Z","level":"error","service":"payment","message":"timeout connecting to database","duration_ms":3200,"error_code":"DB_TIMEOUT"}
Promtail 配置示例:
scrape_configs:
- job_name: payment-service
static_configs:
- targets: [localhost]
labels:
job: payment
__path__: /var/log/payment/*.log
pipeline_stages:
- json:
expressions:
level: level
service: service
duration_ms: duration_ms
error_code: error_code
- labels:
level:
service:
- metrics:
error_count:
type: Counter
description: "Total error log lines"
prefix: promtail_custom_
match:
level: error
action: inc
解析后,Loki 中的日志行将自动携带 level、service 标签,且 duration_ms、error_code 可作为 LogQL 中的字段进行过滤和聚合。
4.2.2 Logfmt 格式日志采集
Logfmt 是 Go 社区广泛使用的键值对格式,比 JSON 更紧凑,适合高吞吐场景。示例:
ts=2025-03-21T10:00:00Z level=error service=payment msg="timeout connecting to database" duration_ms=3200 error_code=DB_TIMEOUT
Promtail 使用 regex 或 logfmt 阶段解析。推荐使用 logfmt 阶段(需 Promtail v2.9+):
pipeline_stages:
- logfmt:
mapping:
level: level
service: service
duration_ms: duration_ms
error_code: error_code
- labels:
level:
service:
logfmt 阶段会自动处理引号转义,但 regex 阶段需要手动编写正则表达式,容易出错。
4.3 日志标准化架构
以下 SVG 图展示了从日志产生到 Promtail 采集、解析、推送至 Loki 的完整标准化流程:
4.4 多行日志与容器日志采集
实际场景中,日志可能跨多行(如 Java 异常栈),或来自容器化环境。Promtail 通过 multiline 阶段和 docker_sd_configs / kubernetes_sd_configs 支持这些场景。
4.4.1 多行日志合并
Java 异常栈示例:
2025-03-21 10:00:00 ERROR [main] com.example.Service - NullPointerException
at com.example.Service.process(Service.java:45)
at com.example.Main.run(Main.java:20)
... 3 common frames omitted
Promtail 配置:
pipeline_stages:
- multiline:
firstline: '^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'
max_lines: 128
max_wait_time: 3s
该配置将匹配时间戳开头的行作为新日志的开始,后续非时间戳开头的行合并到前一条日志中。
4.4.2 Kubernetes 容器日志采集
在 K8s 环境中,Promtail 通常以 DaemonSet 部署,通过 kubernetes_sd_configs 自动发现 Pod 并采集容器 stdout/stderr。推荐配置:
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
pipeline_stages:
- cri: {} # 解析 CRI 格式(包含 stream、timestamp、log)
- json:
expressions:
level: level
service: service
- labels:
level:
service:
- drop:
source: stream
value: stderr
# 可选:丢弃 stderr 日志,或单独处理
service、env 等标签(通过 relabel_configs 从 Pod 的 label 或 annotation 中提取),避免在日志内容中重复解析。
4.5 日志标准化检查清单
以下清单帮助团队快速评估日志采集与标准化质量:
| 检查项 | 标准 | 验证方法 |
|---|---|---|
| 日志格式 | 统一使用 JSON 或 Logfmt | 随机抽取 100 条日志,检查格式一致性 |
| 必选字段 | timestamp、level、service、message | LogQL 查询 {job="xxx"} |= "timestamp" |
| 标签基数 | 每个 job 标签数 ≤ 10,高基数字段不设为标签 | Loki 的 series API 检查标签组合数 |
| 多行处理 | 异常栈、堆栈日志正确合并 | 查看 Loki 中完整异常栈是否被截断 |
| 采集延迟 | 日志产生到 Loki 可查 ≤ 30s | Promtail 的 promtail_sent_lines_total 指标 |
| 丢失率 | 日志丢失率 < 0.1% | 对比应用日志计数与 Loki 接收计数 |
4.6 常见问题与避坑
- 标签爆炸: 将
request_id、user_id等唯一标识符设为标签,导致 Loki 索引膨胀。解决方案:使用structured_metadata(Loki 2.9+)或 LogQL 的| json解析后过滤。 - 正则性能陷阱: 在 Promtail 中使用复杂正则(如
.*贪婪匹配)会导致 CPU 飙升。优先使用json或logfmt阶段。 - 时间戳覆盖: 如果日志中自带时间戳,务必使用
timestamp阶段覆盖 Promtail 的采集时间,否则查询时间范围会不准确。 - 容器日志重复: 在 K8s 中,如果同时使用
kubernetes_sd_configs和static_configs指向同一日志文件,会导致重复采集。使用drop阶段或调整发现配置去重。
logcli 命令行工具快速验证日志采集是否正常:logcli query '{job="payment"} |= "error" | json' --limit 10。如果返回空结果,检查 Promtail 的 positions.yaml 和网络连通性。
通过本章的配置最佳实践和结构化日志标准化,团队可以构建一个可靠、高效的日志采集管道,为后续的告警降噪和弹性伸缩健康检查提供高质量的数据基础。