3. Filebeat实战:从安装到多文件采集与多行日志合并

好,咱们今天来聊聊Filebeat。说实话,在ELK全家桶里,Filebeat是我个人最喜欢的一个组件。为什么?因为它轻量、稳定,而且配置起来特别直观。我刚开始接触日志采集时,用过Logstash做采集端,结果那叫一个重,内存吃紧不说,配置还复杂。后来换成Filebeat,嗯,真香。

3.1 Filebeat安装配置

安装Filebeat其实很简单。我习惯用tar包方式,这样方便管理版本。你想想看,生产环境里动不动几十台机器,用rpm或deb安装虽然方便,但版本回退时反而麻烦。

# 下载并解压
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.17.0-linux-x86_64.tar.gz
tar -xzf filebeat-7.17.0-linux-x86_64.tar.gz
cd filebeat-7.17.0-linux-x86_64

核心配置文件是 filebeat.yml。我一般会先配一个最小化配置,验证通了再逐步加功能。

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log

output.elasticsearch:
  hosts: ["localhost:9200"]
小技巧: 启动前先用 ./filebeat test config 检查配置语法。我曾经因为一个缩进错误,排查了半小时才发现是yml格式问题。

3.2 多文件采集实战

实际项目中,一台服务器上往往有多个日志文件。比如Nginx的access日志、error日志,还有业务应用日志。Filebeat支持同时采集多个文件,配置起来也很直观。

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
    - /var/log/nginx/error.log
  fields:
    log_type: nginx
  fields_under_root: true

- type: log
  enabled: true
  paths:
    - /var/log/myapp/*.log
  fields:
    log_type: application
  fields_under_root: true

这里有个关键点:fields_under_root: true 表示把自定义字段放到根级别。这样在Elasticsearch里查询时,可以直接用 log_type: nginx 来过滤。我有个项目就是靠这个字段区分了20多种日志类型,排查问题时效率翻倍。

避坑指南: 多文件采集时,每个input的paths不要重叠。我曾经把同一个日志文件配到两个input里,结果ES里出现了重复数据,排查了半天才发现。

3.3 多行日志合并

Java应用的异常栈、Python的traceback,这些日志都是多行的。如果按行采集,一条异常信息会被拆成几十条记录,那分析起来就太痛苦了。

Filebeat提供了 multiline 配置来解决这个问题。说白了就是告诉Filebeat:看到什么样的行,就把它和上一行合并。

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/myapp/error.log
  multiline:
    type: pattern
    pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
    negate: true
    match: after

这个配置的意思是:如果一行不匹配日期格式(negate: true),就把它合并到上一行的后面match: after)。

为什么会这样设计?因为Java异常栈的第一行通常包含时间戳,后续行都是堆栈信息,没有时间戳。所以我们要把没有时间戳的行合并到有时间戳的行后面。

注意: 多行合并会占用内存。如果日志量特别大(比如每秒上万条),建议在应用端先把多行日志合并成一行再输出。我在一个日活千万的项目里就遇到过Filebeat OOM的问题,后来改成应用端预处理才解决。

3.4 输出到Elasticsearch

Filebeat默认支持输出到Elasticsearch。配置起来很简单,但有几个参数我建议你关注一下。

output.elasticsearch:
  hosts: ["http://es-node1:9200", "http://es-node2:9200"]
  index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"
  username: "elastic"
  password: "changeme"
  bulk_max_size: 2048
  worker: 4

这里说几个要点:

  • hosts:建议配多个节点,实现负载均衡。Filebeat会自动轮询。
  • index:索引命名规则。我习惯按天分索引,方便管理和删除旧数据。
  • bulk_max_size:批量写入大小。默认是1600,如果日志量不大可以调小,反之调大。
  • worker:并发写入的worker数。默认是1,如果ES集群性能好,可以适当调大。
个人经验: 如果ES集群压力大,可以在Filebeat和ES之间加一层Logstash或Kafka做缓冲。我有个项目日均日志量500GB,不加缓冲时ES经常写入拒绝,加了Kafka后稳如老狗。

3.5 完整配置示例

最后,给一个我在生产环境中用过的完整配置。你可以直接拿来改改就能用。

filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/nginx/access.log
    - /var/log/nginx/error.log
  fields:
    log_type: nginx
  fields_under_root: true
  multiline:
    type: pattern
    pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
    negate: true
    match: after

- type: log
  enabled: true
  paths:
    - /var/log/myapp/*.log
  fields:
    log_type: application
  fields_under_root: true
  multiline:
    type: pattern
    pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'
    negate: true
    match: after

output.elasticsearch:
  hosts: ["http://192.168.1.10:9200", "http://192.168.1.11:9200"]
  index: "filebeat-%{[agent.version]}-%{+yyyy.MM.dd}"
  username: "elastic"
  password: "your_password_here"
  bulk_max_size: 2048
  worker: 4

logging.level: info
logging.to_files: true
logging.files:
  path: /var/log/filebeat
  name: filebeat.log
  keepfiles: 7

嗯,这个配置基本覆盖了日常80%的场景。你部署后可以用 ./filebeat -e 前台运行看看日志输出,确认没问题再后台启动。

记住一点:Filebeat的配置是热加载的,修改后不需要重启进程,发个 kill -HUP 信号就行。这个特性在线上环境特别实用。