日志采集基础
日志采集是整个 pipeline 的第一步,也是坑最多的一步。我见过太多因为采集配不好,导致线上故障定位慢了半拍的案例。说白了,日志没采好,后面分析再强也没用。这一章我就把采集的四个核心环节拆开来讲,每个环节都附上我实际踩过的坑。
标准输出与标准错误流
每个应用都会产生标准输出(stdout)和标准错误(stderr)。很多人觉得这俩差不多,其实区别大了。stdout 是正常日志,stderr 用来输出异常或错误信息。你想想看,如果所有日志都往 stderr 里写,那监控系统会以为你的应用一直在报错。
我在项目中遇到过一件事:有个团队把业务日志全打到了 stderr,结果监控告警一天响了上百次。等真正出故障的时候,大家反而麻木了,没人去看告警。后来我帮他们把正常日志切到 stdout,错误日志保留在 stderr,告警才恢复正常。
kubectl logs 默认合并显示 stdout 和 stderr。但如果你用 --previous 或对接采集工具,两者可以分开处理,千万别混为一谈。
生产环境中我建议这样区分:
- stdout — 业务逻辑日志、访问日志、常规信息
- stderr — 异常堆栈、错误码、严重告警
这样做的好处是,采集时可以给 stderr 设置更高的优先级,实时告警,而 stdout 走批量分析。
文件落盘
除了标准流,很多应用还会直接把日志写到文件里。像 Java 的 Logback、Python 的 logging、Nginx 的 access log,都属于文件落盘。文件落盘的优点是持久化强,缺点是管理成本高——你要管路径、权限、磁盘空间。
我曾经因为日志文件权限没配好,Filebeat 读不了日志,排查了整整两个小时。最后发现是 /var/log/app 目录只有 root 能读,而 Filebeat 用 filebeat 用户启动,直接 Permission denied。嗯,从那以后我每次部署都会加一条检查:
# 确保采集用户有读权限
sudo -u filebeat test -r /var/log/app/*.log && echo "OK" || echo "permission issue"
文件落盘时要规划好三件事:
- 路径规范 — 统一用
/var/log/<app-name>/,别散落在各处 - 命名规则 — 包含应用名 + 日期 + 序号,比如
api-2025-04-01-001.log - 权限管控 — 采集用户至少要能读,建议用同一用户组
/ 下面,磁盘满了直接导致服务器宕机。独立挂载一个日志分区,是最基础的防护。
日志轮转
日志如果一直写不清理,磁盘迟早会爆。轮转(log rotation)就是解决这个问题的——按时间或大小切分旧日志,压缩或删除。Linux 上最常用的工具是 logrotate,我也会在 CI 流水线里配一套统一的轮转策略。
轮转的核心参数其实就这几个:
| 参数 | 作用 | 推荐值 |
|---|---|---|
daily / size |
轮转触发条件(时间或大小) | 每天 或 100MB |
rotate |
保留旧文件的数量 | 7 ~ 30 |
compress |
是否压缩旧日志 | 开启(gzip) |
copytruncate |
适用于持续写入的文件 | 建议开启 |
一个典型的 logrotate 配置长这样:
/var/log/myapp/*.log {
daily
rotate 14
compress
copytruncate
missingok
notifempty
}
我曾经因为把 rotate 设成了 90 天,又没开压缩,结果日志分区被撑爆,生产环境宕了 40 分钟。你知道吗,那一刻所有人盯着我,真是刻骨铭心。从那以后,我强制要求每个项目必须配轮转,并且压缩必须开。
size 200M + daily 双重触发。另外,轮转后记得通知采集工具重新打开文件(postrotate 里跑 kill -USR1)。
采集工具:Filebeat 与 Fluentd
日志产生了、落盘了、轮转了,下一步就是把它采集到中央存储。市面上主流的两款工具是 Filebeat 和 Fluentd。我两个都用过,简单说下各自的脾气。
先看对比表格:
| 特性 | Filebeat | Fluentd |
|---|---|---|
| 资源占用 | 极低(Go 编写) | 中等(Ruby/C) |
| 插件生态 | 较少,但够用 | 丰富(1000+) |
| 配置难度 | 简单,YAML 格式 | 较复杂,config 语法 |
| 数据可靠性 | 内置背压 & 重试 | 支持 buffer & 故障转移 |
| 适用场景 | 轻量采集,直连 ES / Logstash | 复杂路由,多目标输出 |
我个人习惯这样选:如果只是把日志送到 Elasticsearch,用 Filebeat 就够了,轻量、稳定、几乎零运维。但如果你需要做复杂的数据处理、格式转换,或者同时发往 Kafka、S3 等多个目的地,那 Fluentd 更合适。
Filebeat 的基础配置:
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/myapp/*.log
fields:
app: myapp
env: production
output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "myapp-%{+yyyy.MM.dd}"
Fluentd 的基础配置:
<source>
@type tail
path /var/log/myapp/*.log
tag myapp.log
<parse>
@type json
</parse>
</source>
<match myapp.log>
@type elasticsearch
host elasticsearch
port 9200
logstash_format true
logstash_prefix myapp
</match>
最后说一句,不管用哪个工具,一定要加「健康检查」和「采集延迟告警」。我曾经有一次 Fluentd 进程挂了三天没人发现,三天日志全丢了。嗯,从那以后我的每个采集节点都配了存活检测 + 延迟告警,超过 5 分钟没新日志就拉群。
• stdout/stderr 分开用途,千万别混用
• 文件落盘统一路径、规范命名、注意权限
• 日志轮转必须配,压缩必须开,保留期视磁盘而定
• Filebeat 轻量简单,Fluentd 灵活强大,按需选择