系统越简单,日志越像一个附属品,哪里出问题就登录机器看一眼。

系统一旦拆成多个服务,日志就会变成排查问题的入口。订单服务打了一行日志,支付服务打了一行日志,库存服务又打了一行日志,如果这些日志散在不同机器上,排查问题就会变成“到处找文件”。

日志采集要解决的事很直接:把分散在各台机器、各个容器、各个服务里的日志,稳定地收集到统一平台,让开发和运维可以按时间、关键字、服务名、traceId 快速检索和分析。

为什么需要集中日志

单机应用里,日志一般写在本地文件:

/data/logs/order-service/info.log
/data/logs/order-service/error.log

这在小系统里没问题,常见命令也很好用:

tail -f info.log
grep "orderId=10086" info.log

但生产环境通常不是一台机器。

用户请求

网关

订单服务实例 1

订单服务实例 2

支付服务实例 1

库存服务实例 1

本地日志文件

本地日志文件

本地日志文件

本地日志文件

这时会出现几个很真实的问题:

问题 影响
日志分散 不知道请求打到哪台机器
查询低效 需要反复登录服务器
权限混乱 给开发开机器权限有风险
日志易丢 容器重启、机器下线可能导致日志不可查
难以关联 跨服务调用很难串起来

集中日志平台的价值,不只是把日志“搬到一个地方”。更重要的是,把日志变成可检索、可聚合、可追踪的系统数据。

ELK 分别负责什么

ELK 通常指 Elasticsearch、Logstash、Kibana 三个组件。很多生产环境还会加 Filebeat,所以也常被叫作 Beats + ELK 或 Elastic Stack。

组件 角色 作用
Elasticsearch 存储和检索 建索引、按条件搜索日志
Logstash 处理和转发 接收日志、解析字段、过滤转换
Kibana 查询和展示 搜索日志、配置图表、查看趋势

如果只讲经典 ELK,一条日志从应用到页面大致是这样走的:

Java 应用

日志文件

采集器

Logstash

Elasticsearch

Kibana

检索和分析

但在真实项目里,不太建议让每个 Java 应用都直接推 Logstash。更常见的方式是让 Filebeat 靠近日志文件或容器标准输出,负责轻量采集和转发。Filebeat 是轻量日志转发器,不是复杂处理引擎。

如果日志格式比较简单,也可以让 Filebeat 直接写入 Elasticsearch:

应用日志

Filebeat

Elasticsearch

Kibana

如果日志需要复杂解析、清洗、字段转换、路由分发,就把 Logstash 放在中间:

应用日志

Filebeat

Logstash

字段解析

过滤清洗

Elasticsearch

Kibana

实际项目里更常见的是 Filebeat 加 Logstash 加 Elasticsearch 加 Kibana。Filebeat 靠近业务机器,负责轻量采集;Logstash 放在日志链路中间,负责重一点的处理逻辑。这样应用只管把日志写好,采集链路单独演进,耦合更低。

Filebeat 和 Logstash 怎么选

很多人第一次搭日志平台,会把 Filebeat 和 Logstash 的职责混在一起。

Filebeat 更像一个轻量日志搬运工。它部署在业务服务器或容器节点上,监控指定日志文件,把新增日志发送出去。它本身比较轻,不适合承担太复杂的处理逻辑。

Logstash 更像一个日志加工管道。它可以接收多种输入,经过 filter 做解析、转换、补充字段,再输出到 Elasticsearch、Kafka 等地方。

不需要

需要

日志采集需求

是否需要复杂处理

Filebeat 直接写入 Elasticsearch

Filebeat 写入 Logstash

Logstash 解析和过滤

写入 Elasticsearch

可以用一个简单判断:

场景 建议
只采集普通文本日志 Filebeat 直连 Elasticsearch
需要解析 JSON 字段 Filebeat 或 Logstash 都可以
需要多条件过滤和转换 加 Logstash
需要缓冲削峰 中间可接 Kafka
日志来源很多且格式复杂 Logstash 更合适

高并发系统里,还会在采集链路中间加 Kafka。

业务应用

Filebeat

Kafka

Logstash

Elasticsearch

Kibana

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" "携带 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 -fgrepsed,几乎是日志排查三件套。

日志采集链路的关键配置

日志采集不是把组件装起来就结束了,还要关注几个关键点。

日志路径

采集器必须知道日志在哪里。

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 禁止打印或只打印摘要
请求体 敏感接口不要完整打印

日志一旦进入集中平台,访问面会变大。前面不脱敏,后面再补权限控制,成本会高很多。

一套比较稳的落地方案

中小规模系统可以这样设计:

Java 服务

Logback 输出 JSON 日志

本地日志文件

Filebeat 采集

Logstash 解析和过滤

Elasticsearch 存储索引

Kibana 查询分析

网关或拦截器

生成 traceId

更高并发、日志量更大的系统,可以把 Kafka 放进来:

业务服务集群

Filebeat

Kafka 日志主题

Logstash 消费

Elasticsearch 集群

Kibana

生命周期策略

这套方案里,每个组件的职责要清楚:

环节 重点
应用 打结构化日志,带 traceId
Filebeat 轻量采集,保证日志送出去
Kafka 削峰和缓冲
Logstash 解析、清洗、补字段
Elasticsearch 索引、存储、检索
Kibana 搜索、展示、告警辅助

常见坑

日志采集平台最常见的坑,不在于组件不会装,而在于规范没定好。

后果 建议
日志格式不统一 字段无法检索 统一 JSON 格式
没有 traceId 跨服务无法串联 网关入口生成并透传
ERROR 滥用 告警噪声很大 明确日志级别规范
打印敏感信息 安全风险 日志输出前脱敏
日志量无限增长 存储成本失控 设置保留周期
多行异常未合并 堆栈被拆散 配置多行规则
只采集不治理 平台越用越乱 定期清理索引和字段

面试或方案设计怎么讲

如果被问到“日志采集怎么做”,不要只回答“用 ELK”。

更完整的回答可以这样组织:

说明问题背景

日志分散和排查困难

说明整体架构

应用输出结构化日志

Filebeat 采集

Logstash 解析

Elasticsearch 存储

Kibana 检索

补充 traceId 和脱敏

说明高并发下引入 Kafka

可以按这段话讲:

我们会先规范应用日志格式,日志里必须包含时间、级别、服务名、traceId、业务主键和异常信息。应用通过 Logback 输出到本地文件,Filebeat 负责采集日志。如果日志需要解析和清洗,就发送到 Logstash,再写入 Elasticsearch,最后通过 Kibana 查询。日志量比较大时,中间会接 Kafka 做缓冲,避免日志高峰直接打爆后端。安全上会做敏感字段脱敏,存储上会按服务、环境、日期建索引并设置保留周期。

这比只说组件名要强很多,因为它说清楚了数据怎么流、每个组件干什么、生产上有哪些风险点。

最后

日志系统不是为了“看起来很完整”,而是为了让问题发生时能更快定位。

一套好用的日志平台,应该做到三件事:

  1. 一次请求能靠 traceId 串起来。
  2. 一个异常能靠服务名、时间、业务主键快速定位。
  3. 日志链路本身要稳定、安全、可控。

做到这三点,日志就不只是文件,而是生产系统的黑匣子。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐