日志采集与ELK:从本地日志到集中检索分析
系统越简单,日志越像一个附属品,哪里出问题就登录机器看一眼。
系统一旦拆成多个服务,日志就会变成排查问题的入口。订单服务打了一行日志,支付服务打了一行日志,库存服务又打了一行日志,如果这些日志散在不同机器上,排查问题就会变成“到处找文件”。
日志采集要解决的事很直接:把分散在各台机器、各个容器、各个服务里的日志,稳定地收集到统一平台,让开发和运维可以按时间、关键字、服务名、traceId 快速检索和分析。
为什么需要集中日志
单机应用里,日志一般写在本地文件:
/data/logs/order-service/info.log
/data/logs/order-service/error.log
这在小系统里没问题,常见命令也很好用:
tail -f info.log
grep "orderId=10086" info.log
但生产环境通常不是一台机器。
这时会出现几个很真实的问题:
| 问题 | 影响 |
|---|---|
| 日志分散 | 不知道请求打到哪台机器 |
| 查询低效 | 需要反复登录服务器 |
| 权限混乱 | 给开发开机器权限有风险 |
| 日志易丢 | 容器重启、机器下线可能导致日志不可查 |
| 难以关联 | 跨服务调用很难串起来 |
集中日志平台的价值,不只是把日志“搬到一个地方”。更重要的是,把日志变成可检索、可聚合、可追踪的系统数据。
ELK 分别负责什么
ELK 通常指 Elasticsearch、Logstash、Kibana 三个组件。很多生产环境还会加 Filebeat,所以也常被叫作 Beats + ELK 或 Elastic Stack。
| 组件 | 角色 | 作用 |
|---|---|---|
| Elasticsearch | 存储和检索 | 建索引、按条件搜索日志 |
| Logstash | 处理和转发 | 接收日志、解析字段、过滤转换 |
| Kibana | 查询和展示 | 搜索日志、配置图表、查看趋势 |
如果只讲经典 ELK,一条日志从应用到页面大致是这样走的:
但在真实项目里,不太建议让每个 Java 应用都直接推 Logstash。更常见的方式是让 Filebeat 靠近日志文件或容器标准输出,负责轻量采集和转发。Filebeat 是轻量日志转发器,不是复杂处理引擎。
如果日志格式比较简单,也可以让 Filebeat 直接写入 Elasticsearch:
如果日志需要复杂解析、清洗、字段转换、路由分发,就把 Logstash 放在中间:
实际项目里更常见的是 Filebeat 加 Logstash 加 Elasticsearch 加 Kibana。Filebeat 靠近业务机器,负责轻量采集;Logstash 放在日志链路中间,负责重一点的处理逻辑。这样应用只管把日志写好,采集链路单独演进,耦合更低。
Filebeat 和 Logstash 怎么选
很多人第一次搭日志平台,会把 Filebeat 和 Logstash 的职责混在一起。
Filebeat 更像一个轻量日志搬运工。它部署在业务服务器或容器节点上,监控指定日志文件,把新增日志发送出去。它本身比较轻,不适合承担太复杂的处理逻辑。
Logstash 更像一个日志加工管道。它可以接收多种输入,经过 filter 做解析、转换、补充字段,再输出到 Elasticsearch、Kafka 等地方。
可以用一个简单判断:
| 场景 | 建议 |
|---|---|
| 只采集普通文本日志 | Filebeat 直连 Elasticsearch |
| 需要解析 JSON 字段 | Filebeat 或 Logstash 都可以 |
| 需要多条件过滤和转换 | 加 Logstash |
| 需要缓冲削峰 | 中间可接 Kafka |
| 日志来源很多且格式复杂 | Logstash 更合适 |
高并发系统里,还会在采集链路中间加 Kafka。
Kafka 的作用不是必须的,但它能把“日志产生速度”和“日志处理速度”解耦。短时间日志暴涨时,先写入 Kafka,后面的 Logstash 慢慢消费,日志链路会更稳。代价是链路更长,运维成本更高,所以中小系统不必一开始就上 Kafka。
应用日志应该怎么打
日志平台好不好用,一半取决于采集链路,另一半取决于应用写日志的质量。
最怕的是这种日志:
下单失败
它对排查几乎没有帮助。失败的是哪个订单,哪个用户,哪个接口,失败原因是什么,都看不出来。
更好的日志应该带上关键上下文:
create order failed, orderId=10086, userId=9527, skuId=3001, reason=stock_not_enough
如果是 Java 项目,常见组合是 Logback 加 JSON 编码器,把日志输出成结构化 JSON。这样 Elasticsearch 能直接按字段检索,而不是只做全文搜索。
{
"timestamp": "2026-06-08T10:15:30.123+08:00",
"level": "ERROR",
"service": "order-service",
"traceId": "a1b2c3d4",
"spanId": "s1001",
"userId": 9527,
"orderId": 10086,
"message": "create order failed",
"exception": "StockNotEnoughException"
}
结构化日志的好处很明显:
| 字段 | 用途 |
|---|---|
timestamp |
按时间定位问题 |
level |
区分 INFO、WARN、ERROR |
service |
知道日志来自哪个服务 |
traceId |
串起一次请求的完整链路 |
userId |
定位用户维度的问题 |
orderId |
定位业务对象 |
exception |
快速聚合异常类型 |
日志不是写得越多越好,而是要让后来排查问题的人知道“发生了什么、发生在哪、影响谁、为什么失败”。
traceId 是日志检索的生命线
微服务排查问题时,最重要的字段之一就是 traceId。
一次请求可能经过网关、订单、库存、优惠券、支付多个服务。如果没有统一标识,每个服务的日志都像孤立的小片段。
有了 traceId,排查时只要在 Kibana 里搜索:
traceId:a1b2c3d4
就能看到这次请求经过的所有服务日志。
如果系统还接了链路追踪,traceId 还可以和调用链详情关联起来,日志负责告诉你“哪里报错”,链路追踪负责告诉你“哪里慢、调用顺序是什么”。
本地日志命令仍然要会
有了集中日志平台,不代表本地命令就没用了。
当日志采集延迟、平台不可用、临时排查机器问题时,Linux 日志命令仍然非常重要。
查看最新日志:
tail -f app.log
查看最后 200 行:
tail -n 200 app.log
查看文件开头:
head -n 50 app.log
按关键字搜索:
grep "orderId=10086" app.log
忽略大小写搜索:
grep -i "exception" app.log
查看某个时间段附近的日志:
sed -n '1000,1100p' app.log
分页查看:
more app.log
把搜索结果输出到新文件:
grep "ERROR" app.log > error.log
追加输出:
grep "timeout" app.log >> timeout.log
这些命令看起来基础,但生产排查时非常管用。尤其是 tail -f、grep、sed,几乎是日志排查三件套。
日志采集链路的关键配置
日志采集不是把组件装起来就结束了,还要关注几个关键点。
日志路径
采集器必须知道日志在哪里。
filebeat.inputs:
- type: filestream
id: order-service-log
paths:
- /data/logs/order-service/*.log
容器环境里,日志路径可能来自宿主机挂载目录,也可能来自容器标准输出。不同部署方式要提前定好日志规范,否则后面会非常乱。
多行日志
Java 异常堆栈通常是多行。
java.lang.RuntimeException: create order failed
at com.example.OrderService.create(OrderService.java:35)
at com.example.OrderController.create(OrderController.java:18)
如果不处理多行合并,异常堆栈会被拆成多条日志,检索体验很差。
索引规划
Elasticsearch 里日志一般按服务、环境、日期拆索引。常见命名类似:
log-order-service-prod-2026.06.08
这样做有几个好处:
| 设计 | 好处 |
|---|---|
| 按环境区分 | 避免测试和生产混在一起 |
| 按服务区分 | 查询范围更小 |
| 按日期区分 | 方便冷热数据管理 |
| 设置保留周期 | 控制存储成本 |
日志量大时,索引生命周期管理很重要。不是所有日志都需要永久保存,通常会按业务重要性保留 7 天、30 天、90 天或更久。
字段脱敏
日志里不要打印密码、身份证号、银行卡号、Token、密钥。
这不是“最好不要”,而是必须避免。
常见做法是:
| 类型 | 处理方式 |
|---|---|
| 手机号 | 保留前三后四 |
| 身份证号 | 只保留少量可定位片段 |
| 密码 | 禁止打印 |
| Token | 禁止打印或只打印摘要 |
| 请求体 | 敏感接口不要完整打印 |
日志一旦进入集中平台,访问面会变大。前面不脱敏,后面再补权限控制,成本会高很多。
一套比较稳的落地方案
中小规模系统可以这样设计:
更高并发、日志量更大的系统,可以把 Kafka 放进来:
这套方案里,每个组件的职责要清楚:
| 环节 | 重点 |
|---|---|
| 应用 | 打结构化日志,带 traceId |
| Filebeat | 轻量采集,保证日志送出去 |
| Kafka | 削峰和缓冲 |
| Logstash | 解析、清洗、补字段 |
| Elasticsearch | 索引、存储、检索 |
| Kibana | 搜索、展示、告警辅助 |
常见坑
日志采集平台最常见的坑,不在于组件不会装,而在于规范没定好。
| 坑 | 后果 | 建议 |
|---|---|---|
| 日志格式不统一 | 字段无法检索 | 统一 JSON 格式 |
| 没有 traceId | 跨服务无法串联 | 网关入口生成并透传 |
| ERROR 滥用 | 告警噪声很大 | 明确日志级别规范 |
| 打印敏感信息 | 安全风险 | 日志输出前脱敏 |
| 日志量无限增长 | 存储成本失控 | 设置保留周期 |
| 多行异常未合并 | 堆栈被拆散 | 配置多行规则 |
| 只采集不治理 | 平台越用越乱 | 定期清理索引和字段 |
面试或方案设计怎么讲
如果被问到“日志采集怎么做”,不要只回答“用 ELK”。
更完整的回答可以这样组织:
可以按这段话讲:
我们会先规范应用日志格式,日志里必须包含时间、级别、服务名、traceId、业务主键和异常信息。应用通过 Logback 输出到本地文件,Filebeat 负责采集日志。如果日志需要解析和清洗,就发送到 Logstash,再写入 Elasticsearch,最后通过 Kibana 查询。日志量比较大时,中间会接 Kafka 做缓冲,避免日志高峰直接打爆后端。安全上会做敏感字段脱敏,存储上会按服务、环境、日期建索引并设置保留周期。
这比只说组件名要强很多,因为它说清楚了数据怎么流、每个组件干什么、生产上有哪些风险点。
最后
日志系统不是为了“看起来很完整”,而是为了让问题发生时能更快定位。
一套好用的日志平台,应该做到三件事:
- 一次请求能靠 traceId 串起来。
- 一个异常能靠服务名、时间、业务主键快速定位。
- 日志链路本身要稳定、安全、可控。
做到这三点,日志就不只是文件,而是生产系统的黑匣子。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)