Skip to content

Beat介绍

本文主要介绍Beat的概念,并以Filebeat为例,说明其使用方法。

1. 什么是Beat

Beat是Elastic Stack中的轻量级数据采集器,负责从各种数据源收集数据并将其发送到Elasticsearch或Logstash进行存储和分析。 Beat家族包括多种类型的Beat,如Filebeat、Metricbeat、Packetbeat等,每种Beat针对不同的数据类型和使用场景进行了优化。

Beats Platform

什么是LIBBEAT?

libbeat 是 Elastic Beats 框架的核心库(core library),简单来说,它是所有 Beats(比如 Filebeat、Metricbeat、Packetbeat 等)产品的底层基础和公共代码部分。

libbeat提供 Beats 框架的通用功能,例如:

  • 配置解析(YAML 配置加载);
  • 输出插件系统(支持 Elasticsearch、Logstash、Kafka、Redis、文件等输出);
  • 采集器(publisher)管道和队列管理;
  • ACK 机制和重试逻辑(保证数据至少投递一次);
  • 监控指标暴露(/stats 接口);
  • 日志系统;
  • 信号处理、优雅关闭等;

所有官方 Beats(Filebeat、Metricbeat 等)都是在 libbeat 的基础上开发出来的轻量级代理(shipper),它们只实现自己特有的数据采集逻辑,其他通用的功能全部复用 libbeat。也就是说,libbaet是发送机,Filebeat、Metricbeat、Packetbeat 等只是在libbeat基础上拥有不同的车身外观。

2. Filebeat介绍

Filebeat,见名知意,主要是从文件中采集数据,发送到ES或logstash,更狭隘地说,是从日志文件中采集数据。

2.1 工作原理

当启动Filebeat后,会启动一个或多个input,用于读取在配置文件中指定的日志目录;对于定位到的每个日志文件,Filebeat会启动一个harvester。harvester会一行行读取日志文件中的内容,并将每行日志发送给libbeat(Beats的公共包),libbeat会将日志事件进行包装,并发送给在配置文件中指定的目的地。

Beats design

因此,Filebeat的两大组件为Input和Harvester。

2.2 快速开始

在开始之前,请确保ElasticSearch和Kibana已启动。下面的流程在MacOS上实现,并且ES和Kibana在Docker中运行。

ES和Kibana版本:7.17.28

首先,使用如下命令下载和解压Filebeat(注意版本一致):

bash
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-7.17.28-darwin-x86_64.tar.gz
tar xzvf filebeat-7.17.28-darwin-x86_64.tar.gz

然后,在filebeat.yml配置文件中配置输出路径ElasticSearch的地址,以及Kibana的地址:

yaml
output.elasticsearch:
  hosts: ["https://localhost:9201"]
  # username: "filebeat_internal"
  # password: "YOUR_PASSWORD"
  # ssl:
# enabled: true
# ca_trusted_fingerprint: "b9a10bbe64ee9826abeda6546fc988c8bf798b41957c33d05db736716513dc9c"

setup.kibana:
  host: "localhost:5601"

然后,在filebeat.yml配置文件中配置要读取的日志文件路径:

yaml
filebeat.inputs:
  - type: filestream
    id: my-filestream-id
    enabled: true
    paths:
      - /Users/xxx/logs/nacos/config.log

上述配置表示从/Users/xxx/logs/nacos/config.log日志文件中读取日志,并发送到ES中。

最后,启动Fileabeat:

bash
sudo ./filebeat -e

上述命令以超级用户权限,在前台(Foreground)启动 Filebeat,并将所有 Filebeat 的运行时日志信息直接输出到你的终端屏幕上。

注意,在生产环境中,Filebeat 应该以服务(Daemon)的形式在后台运行,并使用标准的日志文件来记录状态,而不是使用 -e 参数。

最后,观察ES中,会发现多了一个索引:

image-20251129105758700

接下来,配置Kibana,在Kibana中查看索引数据。

首先,在Management中选择Stack Management,然后在Kibana下选择Index Patterns,右上角选择Create index pattern

image-20251129110107058

在Name处输入filebeat- ,在Timestamp field处选择*@timestamp**:

image-20251129110228602

配置了之后,我们就可以在Kibana的Discover中查看数据了:

image-20251129110416577

2.3 重要配置介绍

本小节介绍Filebeat的配置。

2.3.1 Inputs

Filebeat Inputs用于定义Filebeat要获取的数据在哪,这是一个数组,所以每个input以-开始。

类型为filestream的input的属性如下(参考链接):

  • type:公共属性,用于指定input的类型,如果是从文件中获取数据,则类型为filestream,完整的类型列表如下:https://www.elastic.co/docs/reference/beats/filebeat/configuration-filebeat-options#filebeat-input-types。在inputs数组中,可以指定多个类型相同的input;

  • id:公共属性,input的唯一标识符,在inputs数组中,必须唯一;

  • enabled:公共属性,标识input是否启用;

  • paths:用于指定要读取的文件或路径,数组;路径满足glob模式;

    glob模式

    是一套用于匹配文件路径名的模式匹配规则,简单来说,它是一种通过使用通配符 (Wildcards) 来描述文件或目录路径集合的方法。

    通配符含义作用示例匹配结果
    *星号匹配零个或多个字符(除了路径分隔符 /)。log/*.log匹配 log/access.loglog/error.loglog/a.log
    ?问号匹配恰好一个字符。file_?.txt匹配 file_1.txtfile_A.txt,但不匹配 file_12.txt
    []方括号匹配方括号内任意一个字符或字符范围。[a-c].txt匹配 a.txtb.txtc.txt
    **双星号递归匹配零个或多个目录。data/**/log.txt匹配 data/log.txtdata/a/log.txtdata/a/b/log.txt
  • prospector.scanner.exclude_files:正则表达式数组,用于定义要忽略的文件;

  • include_lines:正则表达式数组,用于定义要获取的行需要满足的正则表达式(满足一个就可以);

  • exclude_lines:正则表达式数组,用于定义要丢弃的行需要满足的正则表达式(满足一个就可以);

    如果同时指定了include_lines和exclude_lines,那么Filebeat先执行include_lines,然后再执行exlcude_lines。

  • parsers:定义了一系列解析器,用于对日志内容进行处理,包括multilinendjsoncontainersysloginclude_message解析器;

  • processors:定义了一系列处理器,用于对事件(event)进行处理;

下面是一个input配置示例:

yaml
filebeat.inputs:
  - type: filestream
    id: my-filestream-id
    enabled: true
    paths:
      - /var/log/*.log
    prospector.scanner.exclude_files: ['\.gz$'] # 忽略.gz结尾的文件
    include_lines: ["sometext"]
    exclude_lines: ["^DBG"]
    parsers:
      - multiline:
          type: count
          count_lines: 3
    processors:
      - dissect:
          tokenizer: '"%{service.pid|integer} - %{service.name} - %{service.status}"'
          field: "message"
          target_prefix: ""

2.3.2 parsers的multiline

本小节主要介绍parsers中的multiline解析器。

在日志文件中,有可能某一个事件(event)跨越了多行,如果按照默认的配置,那么每行就会生成一个事件,最后会生成多个事件,而multiline解析器可以用来将跨越多行的事件组合成一个事件。

基本语法如下:

yaml
parsers:
  - multiline:
      type: pattern
      pattern: '^\['
      negate: true
      match: after
  • type:表示如何确定哪几行是一个事件,取值如下:
    • pattern:默认值,Filebeat识别一行是否是新事件的开始。所有符合开始行模式的行,都作为前一个事件的延续
    • count:Filebeat 将指定数量的连续行聚合成一个事件。
    • while_pattern:Filebeat找到第一行(事件的开始行)后,会持续while)将所有匹配 pattern的后续行添加到该事件中,直到遇到第一个不匹配 pattern 的行。
  • pattern:定义了一个正则表达式。Filebeat会使用这个正则表达式来检查每一行日志,来识别一行为新事件的开始行,或者识别一行为 前一个事件的延续行
  • negate:布尔值,取之为truefalse
    • negate: true:表示 不匹配 pattern 的行是当前事件的延续行
    • negate: false:表示 匹配 pattern的行是当前事件的延续行,即表示该行是新事件的开始行。
  • match:新的行应该被合并到多行事件的前面还是后面
    • match: after:匹配的行或否定的行(即延续行)将被添加到前面匹配的行后面。这适用于从事件的开始行开始匹配的场景。
    • match: before:匹配的行或否定的行(即延续行)将被添加到前面匹配的行前面。这适用于从事件的结束行开始匹配的场景。
  • count_lines:当type为count时,指定多少行聚合成一个事件;
  • max_lines:指定一个事件中最多有多少行,默认值为500;

例如,在java中,异常堆栈信息格式如下:

txt
Exception in thread "main" java.lang.IllegalStateException: A book has a null property
       at com.example.myproject.Author.getBookIds(Author.java:38)
       at com.example.myproject.Bootstrap.main(Bootstrap.java:14)
Caused by: java.lang.NullPointerException
       at com.example.myproject.Book.getId(Book.java:22)
       at com.example.myproject.Author.getBookIds(Author.java:35)
       ... 1 more

那么可以设置如下,将上面的多行异常堆栈信息聚合成一个事件:

yaml
parsers:
  - multiline:
      type: pattern
      pattern: '^[[:space:]]+(at|\.{3})[[:space:]]+\b|^Caused by:'
      negate: false
      match: after

2.3.3 processors

processors用于处理事件(event),包括移除字段、添加字段、处理字段内容、丢弃事件等,processors可以定义多个,事件按照processors定义的顺序依次进行处理,并最终进入output中指定的目的地:

txt
event -> processor 1 -> event1 -> processor 2 -> event2 -> output
如何以及在哪配置processors

processors的基本配置格式如下:

yaml
processors:
  - <processor_name>:
      when:
        <condition>
      <parameters>
  - <processor_name>:
      when:
        <condition>
      <parameters>

即processors是一个数组,其中可以定义多个processor,在每一个processor中可以定义需要满足的条件以及参数,当事件满足该processor的条件后,就会应用该processor。

可以使用如下的processors复杂配置:

yaml
processors:
  - if:
      <condition>
    then:
      - <processor_name>:
          <parameters>
      - <processor_name>:
          <parameters>
      ...
    else:
      - <processor_name>:
          <parameters>
      - <processor_name>:
          <parameters>
      ...

当事件满足if中的条件后,则使用then中定义的processor,否则使用else中定义的processor。

在Filebeat中,processors既可以定义为全局的,也可以定义为局部的(针对某个input而言)。

全局的配置是针对所有的input的事件:

yaml
filebeat.inputs:
  - type: filestream

processors:
  - <processor_name>:
      when:
        <condition>
      <parameters>

局部的配置是针对单个input的事件:

yaml
filebeat.inputs:
  - type: filestream
    processors:
      - <processor_name>:
          when:
            <condition>
          <parameters>

关于具体的processor,请查看2.4小节。

2.3.4 output

output是指明Filebeat将事件(event)发送到哪里去,本小节介绍Elasticsearch和File两种输出目的地。

Elasticsearch

将事件发送到Elasticsearch的基本配置如下:

yaml
output.elasticsearch:
	enabled: true
  hosts: ["https://myEShost-node1:9200", "https://myEShost-node2:9200"]
  protocol: http
  username: "filebeat_writer"
  password: "YOUR_PASSWORD"
  compression_level: 1
  loadbalance: true
  worker: 1
  index: customer-index
  indices:
    - index: "warning-%{[agent.version]}-%{+yyyy.MM.dd}"
      when.contains:
        message: "WARN"
    - index: "error-%{[agent.version]}-%{+yyyy.MM.dd}"
      when.contains:
        message: "ERR"
  • enabled:是否启用,默认值为true,表示启用;

  • hosts:是一个数组,表示ES的地址,由于ES可以集群部署,所以这里也可以指定多个ES节点的地址;

    ES 节点的地址可以写成URLIP:PORT,例如:http://192.15.3.2, https://es.found.io:9230192.24.3.2:9300,如果没有端口,那么使用9200作为默认端口。

    如果写成IP:PORT格式,那么协议使用protocol中指定的协议;

  • protocol:协议,可选值为http和https,默认值为http;如果在hosts中使用IP:PORT格式,那么协议就会使用protocol中指定的协议;如果使用在hosts中使用URL格式,那么就会忽略protocol中的值,使用URL中的协议;

  • usernamepassword:表示访问ES的用户名和密码;filebeat总共可以使用以下三种方式访问ES:

    • 用户名和密码:

      yaml
      output.elasticsearch:
        hosts: ["https://myEShost:9200"]
        username: "filebeat_writer"
        password: "YOUR_PASSWORD"
    • API Key:

      yaml
      output.elasticsearch:
        hosts: ["https://myEShost:9200"]
        api_key: "ZCV7VnwBgnX0T19fN8Qe:KnR6yE41RrSowb0kQ0HWoA"

      api_key的格式为:id:api_key

    • PKI证书认证:

      yaml
      output.elasticsearch:
        hosts: ["https://myEShost:9200"]
        ssl.certificate: "/etc/pki/client/cert.pem"
        ssl.key: "/etc/pki/client/cert.key"
  • compression_level:gzip压缩等级,即把数据发送给ES前使用gzip压缩的等级,可选值为0-9之间的整数。如果设置为0,表示禁用压缩,从1-9,数字越大,表示压缩率越高,即发送的数据包越小,但是消耗的CPU资源越高,默认值为1;

  • loadbalance:在hosts中可以指定多个ES地址,那么我们就可以决定是否同时向多个地址发送数据,loadbalance就是控制能否同时向多个地址发送数据,默认值为true;

    如果设置为false,那么Filebeat从hosts中随机选择一个ES地址,然后发送数据,如果该ES地址连接失败了,那么会再选择另一个ES地址,继续发送数据;

  • workerworkers:决定每个ES地址建立多少个连接,默认值为1;

  • index:决定数据发送到ES的哪个索引,如果没有指定,那么默认值为filebeat-%{[agent.version]}-%{+yyyy.MM.dd}

    当自定义索引名称时,需要同时配置setup.template.namesetup.template.pattern

    如果启用了索引生命周期管理(ILM,index lifecycle management),那么默认的索引名称为filebeat-%{[agent.version]}-%{+yyyy.MM.dd}-%,例如filebeat-[version]-2025-01-30-000001并且自定义的索引名称会被忽略;参考ILM配置:https://www.elastic.co/docs/reference/beats/filebeat/ilm。

    在自定义索引名称中,我们也可以使用事件(event)中的字段,例如%{[fields.log_type]}-%{[agent.version]}-%{+yyyy.MM.dd},其中的%{[fields.log_type]}就表示事件中的log_type字段,例如所有 log_typenormal 的事件被发送到名为 normal-[version]-2025-01-30 的索引中,而所有 log_typecritical 的事件被发送到名为 critical-[version]-2025-01-30 的索引中。

  • indices:定义了一组索引选择规则,当事件满足某个规则时,就会进入该规则指定的索引中,按照指定的规则顺序进行匹配,进入第一个满足的规则制定的索引;如果该事件不满足indices中所有的规则,那么就会进入index中指定的索引;

    有两种方式可以指定indices

    方式一:index+when

    yaml
    output.elasticsearch:
      hosts: ["http://localhost:9200"]
      indices:
        - index: "warning-%{[agent.version]}-%{+yyyy.MM.dd}"
          when.contains:
            message: "WARN"
        - index: "error-%{[agent.version]}-%{+yyyy.MM.dd}"
          when.contains:
            message: "ERR"

    首先使用某个事件来判断其是否满足when中指定的条件,如果满足,就进入indices.index中指定的索引名称,如果不满足,则继续匹配indices中的规则,如果不满足indices中的所有规则,那么该事件进入index中指定的索引;

    方式二:index+mappings+default

    yaml
    output.elasticsearch:
      hosts: ["http://localhost:9200"]
      indices:
        - index: "%{[fields.log_type]}"
          mappings:
            critical: "sev1"
            normal: "sev2"
          default: "sev3"

    首先从事件中取出log_type字段,然后判断mappings中是否有满足匹配的规则,假设log_type的值为normal,那么进入sev2索引,如果mappings中没有满足的匹配规则,就进入default中指定的索引;

    注意,上述方式限制mappings中的索引名称为字符串常量,也就是说不能使用格式化字符串,如%{[fields.log_type]}

File

File就是将事件发送到文件中,这种方式可以用来测试Filebeat是否有效。基本配置如下:

yaml
output.file:
	enabled: true
  path: "/tmp/filebeat"
  filename: filebeat
  rotate_every_kb: 10000
  number_of_files: 7
  permissions: 0600
  rotate_on_startup: true
  codec.json:
    pretty: true
    escape_html: false
  • enabled:是否启用该output,默认值为true;

  • path:用来存储输出文件的目录;

  • filename:输出文件的名称;

  • rotate_every_kb:每个文件的最大大小,以KB为单位,默认值为10240KB,也就是说每个文件最大10M,当输出文件到达该大小后,会输出到另一个文件;

  • number_of_files:表示输出文件目录下最大的文件数,默认值为7,支持的值为2-1024。当到达最大文件数时,最先创建的文件会被删除;

  • permissions:对输出文件的权限控制,默认值为0600,表示只有创建该文件的用户具有读写权限,其他用户都没有权限读写该文件;

  • rotate_on_startup:表示是否在Filebeat启动时创建新的输出文件,默认值为true;

  • codec:用于编码输出的事件,默认值为json,表示每个事件输出为一个json,并且一个json占据输出文件中的一行;

    • pretty:表示不把json输出为一行,而是输出为可读性高的格式;默认值为false;
    • escape_html:是否去除HTML表情,默认值为false;

    除了使用json格式,还可以使用字符串格式,如下:

    yaml
    output.file:
      codec.format:
        string: "%{[@timestamp]} %{[message]}"

    表示将事件中的@timestampmessage字段提取出来,拼接成一行输出;

2.4 processors

本小节介绍具体的processor。

https://www.elastic.co/docs/reference/beats/filebeat/filtering-enhancing-data

2.4.1 add_fields

add_fields处理器会在事件(event)中添加字段,语法如下:

yaml
processors:
  - add_fields:
      target: project
      fields:
        name: myproject
        id: "574734885120952459"
  • target:新添加的字段应该放在哪个字段下,默认值为fields;如果要把新添加的字段放在根层级下,设置target'',如target: ''
  • fields:要新添加的字段;

以上例子会在事件中添加如下内容:

json
{
  "project": {
    "name": "myproject",
    "id": "574734885120952459"
  }
}

2.4.2 drop_fields

drop_fields用于移除事件中的字段,语法如下:

yaml
processors:
  - drop_fields:
      when:
        condition
      fields: ["field1", "field2", ...]
      ignore_missing: false
  • when:只有满足条件时才会移除指定的字段,是可选的;
  • fields:指定要移除的字段名称,也可以使用正则表达式,需要使用/包围,例如/reg_exp/
  • ignore_missing:当事件中不存在要移除的字段时,是否抛出错误,默认值为false,表示抛出错误,设置为true,表示不抛出错误;

注意,@timestamptype字段不能被移除。

2.4.3 drop_event

drop_event用于抛弃整个事件,也就是说被抛弃的事件不会进入目的地,语法如下:

yaml
processors:
  - drop_event:
      when:
        condition
  • when:当满足条件时,事件才会被抛弃,注意,该项是必须的;

2.4.4 rename

rename用来改变字段的名称,也可以用来改变字段的层级,语法如下:

yaml
processors:
  - rename:
      fields:
        - from: "a.g"
          to: "e.d"
      ignore_missing: false
      fail_on_error: true
  • fields:是一个对象数组,其中每个对象有两个属性fromtofrom定义了要改变的字段,to定义了新的字段名称;
  • ignore_missing:当事件中不存在from中指定的字段时,是否抛出移除,默认值为false表示抛出移除;
  • fail_on_error:如果设置为true,当发生错误时,rename处理阶段停止并返回原始事件,设置为false表示继续进行rename处理,默认值为true;

当进行如下设置时,也改变字段层级:

yaml
processors:
  - rename:
      fields:
        - from: "a.g"
          to: "e"

2.4.5 dissect

dissect处理器用于将字符串用指定的格式进行分解,语法如下:

yaml
processors:
  - dissect:
      tokenizer: "%{key1} %{key2} %{key3|convert_datatype}"
      field: "message"
      target_prefix: "dissect"
      overwrite_keys: true
      trim_values: all
      trim_chars: " "
      ignore_failure: true
  • tokenizer:定义了字符串格式,其中%{key3|convert_datatype}表示占位符,该位置的字符串会被解析为key3字段,并且转换为convert_datatype指定的格式;
  • field:指定了事件中的哪个字段用来解析;
  • target_prefix:将解析后的字段放在哪个字段里,默认值为dissect,如果要把解析后的字段放在根路径下,设置target_prefix: "";注意,如果事件中已经存在同名字段,则dissect处理器不会覆盖同名字段,如果需要覆盖,设置overwrite_keys为true;
  • trim_values:定义要在哪移除字符,可选的值为noneleftrightall,默认值为none表示不移除;
  • trim_chars:指定要移除哪些字符,默认值为" ",表示移除空格,如果要移除其他字符,将要移除的字符放在一个字符串中,例如" a",表示要移除空格和字符a
  • ignore_failure:是否忽略错误,默认值为false;如果设置为true,那么当dissect遇到错误时,会恢复原事件,并继续执行后续的处理器;如果设置为false,那么会抛出错误,并阻止后续处理器的执行;

2.5 索引模板与ILM

2.5.1 默认情况

如果不调整ES输出的目标索引,那么filebeat会做如下事:

  • 创建名称为filebeat的ILM策略,如下(已省略部分字段):

    json
    {
      "filebeat": {
        "policy": {
          "phases": {
            "hot": {
              "min_age": "0ms",
              "actions": {
                "rollover": {
                  "max_age": "30d",
                  "max_size": "50gb"
                }
              }
            }
          }
        },
        "in_use_by": {
          "indices": [
            "filebeat-7.17.28-2026.01.03-000001"
          ],
          "data_streams": [],
          "composable_templates": [
            "filebeat-7.17.28"
          ]
        }
      }
    }
  • 创建名称为filebeat-<version>的索引模板,部分内容如下:

    json
    {
        "index_templates": [
            {
                "name": "filebeat-7.17.28",
                "index_template": {
                    "index_patterns": [
                        "filebeat-7.17.28-*"
                    ],
                    "template": {
                        "settings": {
                            "index": {
                                "lifecycle": {
                                    "name": "filebeat",
                                    "rollover_alias": "filebeat-7.17.28"
                                }
                            }
                        }
                    }
                }
            }
        ]
    }
  • 创建名为filebeat-<version>-<yyyy.MM.dd>-<seqNo>的索引,并使用别名filebeat-<version>

    image-20260103143902459

2.5.2 调整索引模板

如果我们自己定义索引模板,那么可以如下设置:

yaml
filebeat.inputs:
  - type: stdin
    enabled: true
    id: my-stdin-id

output.elasticsearch:
  hosts: ["http://localhost:9200"]
  index: "my-filebeat-test-01"
  username: "elastic"
  password: "your_strong_password123"

setup.kibana:
  host: "localhost:5601"

setup.ilm.enabled: false

setup.template:
  enabled: true
  name: "my-filebeat-test"
  pattern: "my-filebeat-test-*"
  settings:
    index.number_of_shards: 1
    index.number_of_replicas: 0
  fields: "my_fields.yaml"
  • 第8行,自定义索引名称
  • 第15行,禁用ILM,如果ILM启用了,会忽略自定义的索引模板;
  • 第17-24行,设置索引模板的内容

其中,setup.template.fields是自定义Mapping,内容如下:

yaml
- key: my_app
  fields:
    - name: desc
      type: text

key作为分组键,在实际生成的索引模板中,desc并不会在my_app下。

然后,启动filebeat,查看索引模板:

txt
GET /_index_template/my-filebeat*
json
{
  "index_templates": [
    {
      "name": "my-filebeat-test",
      "index_template": {
        "index_patterns": [
          "my-filebeat-test-*"
        ],
        "template": {
          "settings": {
            "index": {
              "mapping": {
                "total_fields": {
                  "limit": "10000"
                }
              },
              "refresh_interval": "5s",
              "number_of_shards": "1",
              "number_of_replicas": "0",
              "max_docvalue_fields_search": "200",
              "query": {
                "default_field": [
                  "desc",
                  "fields.*"
                ]
              }
            }
          },
          "mappings": {
            "_meta": {
              "beat": "filebeat",
              "version": "7.17.28"
            },
            "dynamic_templates": [
              {
                "strings_as_keyword": {
                  "mapping": {
                    "ignore_above": 1024,
                    "type": "keyword"
                  },
                  "match_mapping_type": "string"
                }
              }
            ],
            "properties": {
              "desc": {
                "norms": false,
                "type": "text"
              }
            },
            "date_detection": false
          }
        },
        "composed_of": [],
        "priority": 150
      }
    }
  ]
}

可以发现,生成的索引模板确实是我们自己定义的。

查看生成的索引及文档:

image-20260103151510787

会发现有很多字段,并且没有自定义的 desc 字段:

  • 很多其他的字段,这些字段是由filebeat自动生成的,当这些字段随文档进入索引时,ES会自动进行字段映射;
  • 没有自定义的desc字段,这是因为filebeat自动生成事件(文档)时,并没有包含该字段,我们可以使用processors添加;

在filebeat默认的fields.yml中,已经定义了很多字段,如果我们想添加自己的字段,不用重新定义,可以在filebeat.yml中使用如下配置:

yaml
setup.template.overwrite: true
setup.template.append_fields:
- name: test.name
  type: keyword
- name: test.hostname
  type: long
  • setup.template.overwrite:重写索引模板,默认值为false
  • setup.template.append_fields:声明自定义字段及其数据类型;

我们可以使用如下命令,查看要生成的索引模板:

bash
./filebeat export template

2.5.3 ILM与Data Stream

如果是较老的Filebeat版本,参考一下配置:

yaml
setup.ilm.rollover_alias: "xxx"

在较新的Filebeat版本中,如果开启了ILM,那么会优先使用ILM+Data Stream模式。

以下案例在Filebeat-9.1.9中演示,在MacOS中下载使用Filebeat-9.1.9:

txt
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-9.1.9-darwin-x86_64.tar.gz
tar xzvf filebeat-9.1.9-darwin-x86_64.tar.gz

filebeat.yml配置文件内容如下:

yaml
filebeat.inputs:
  - type: stdin
    enabled: true
    id: my-stdin-id

output.elasticsearch:
  hosts: ["http://localhost:9200"]
  index: "my-filebeat-index-template"
  username: "elastic"
  password: "your_strong_password123"

setup.kibana:
  host: "localhost:5601"

setup.ilm:
  enabled: true
  policy_name: "my-filebeat-test-ilm-policy"
  policy_file: "ilm-policy.json"

setup.template:
  enabled: true
  name: "my-filebeat-index-template"
  pattern: "my-filebeat-*"
  settings:
    index.number_of_shards: 1
    index.number_of_replicas: 0
  fields: "my_fields.yaml"
  append_fields:
    - name: test.name
      type: keyword
    - name: test.hostname
      type: long

ILM策略定义ilm-policy.json内容如下:

Details
json
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "set_priority": {
            "priority": 100
          }, 
          "rollover": {
            "max_docs": 2
          }
        }
      },
      "warm":{
        "min_age": "5m", 
        "actions": {
          "readonly": {},
          "allocate": {
            "number_of_replicas": 0
          },
          "shrink": {
            "number_of_shards": 1
          }
        } 
      }
    }
  }
}

以上配置文件的效果如下:

  • 由于开启了ILM,所以filebeat会使用在setup.ilm.policy_file中的具体策略规则,创建以setup.ilm.policy_name为名的ILM策略

    image-20260103170438721

  • 虽然在官方文档中,说开启了ILM,会忽略setup.template.namesetup.template.pattern

    WARNING

    If index lifecycle management is enabled (which is typically the default), setup.template.name and setup.template.pattern are ignored.

    但是,实际测试下来,如果不设置这两个属性会报错,并且设置了会创建索引模板,并且开启了Data Stream模式:

    image-20260103170650129

  • 创建与索引模板同名的Data Stream:

    image-20260103170813091

  • 一定要设置output.elasticsearch.index的值,并且该值需要与setup.template.name的值相同,这样写入文档时才会写入到Data Stream中。

    如果不设置,那么output.elasticsearc.index的默认值为filebeat-<version>,会导致事件(文档)写入到名称为filebeat-<version>的索引中,而不是Data Stream中:

    image-20260103171129373

2.6 小结

Filebeat,或者说beats,内部使用了很多ILM和Data Stream的知识。

最开始我没学习ILM和Data Stream,想先了解Fileabeat的使用,但是发现看不懂,最后还是去补了ILM和Data Stream的知识后,再来学习Fileabeat的。

其实Filebeat,做的事就是想从Filebeat端,去创建ILM、Data Stream等内容,并且再加上Filebeat获取事件、解析事件等功能。其实学完下来,发现Filebeat不简单,或者说有点难以理解,很多地方设计不太合理(或者说和文档有出入)。

我认为最好的方法还是在ES端做好索引模板、ILM、Data Stream的创建与管理工作,在Filebeat端,只需要确定数据从哪输入,怎么处理,输出到哪的工作,推荐如下配置:

yaml
setup.ilm.enabled: false           # 关闭 Filebeat 自动管理 ILM
setup.template.enabled: false      # 关闭 Filebeat 自动加载/管理索引模板(最关键!)

output.elasticsearch:
  hosts: ["https://es.example.com:9200"]
  index: "logs-nginx-prod"           # ← 直接写自己创建的数据流完整名称

3. 实战案例

本小节介绍如何使用Filebeat,读取Spring Boot程序的日志到Elasticsearch中。

3.1 创建Spring Boot程序

完整项目地址:https://github.com/Lee-0o0/spring-boot-demo

主要查看日志配置logback.xml

xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>

    <!-- 将日志写入文件,并归档 -->
    <appender name="ROLLINGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/springboot-demo.log</file>
        <!-- 注意选取的是 SizeAndTimeBasedRollingPolicy -->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!-- 按天归档 -->
            <fileNamePattern>logs/archive/springboot-demo-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <!-- 单文件最大大小 -->
            <maxFileSize>1MB</maxFileSize>
            <!-- 保留历史天数(因为是按天归档的) -->
            <maxHistory>60</maxHistory>
            <!-- 日志总文件大小 -->
            <totalSizeCap>20GB</totalSizeCap>
        </rollingPolicy>

        <!-- 日志内容格式 -->
        <encoder>
            <pattern>[%thread] %-5level %logger -%msg %n</pattern>
        </encoder>
    </appender>

    <!-- 控制台输出日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%-4relative [%thread] %-5level %logger{35} -%kvp- %msg %n</pattern>
        </encoder>
    </appender>

    <!-- 定义根日志记录器日志级别 -->
    <root level="INFO">
        <!-- ref的值需要与appender的name一致 -->
        <appender-ref ref="ROLLINGFILE" />
        <appender-ref ref="STDOUT" />
    </root>

</configuration>

3.2 配置Filebeat

在filebea.yml中配置如下:

yaml
filebeat.inputs:
  - type: filestream
    id: my-filestream-id
    enabled: true
    paths:
      - /Users/lhb/projects/demo/java_demo/spring-boot-demo/logs/*.log
    prospector.scanner.exclude_files: ['\.gz$']
    parsers:
      - multiline:
          type: pattern
          pattern: '^\[|^[0-9]{4}'
          negate: true
          match: after

processors:
  - dissect:
      tokenizer: "[%{thread}] %{level->} %{logger} -%{message}"
      field: "message"
      target_prefix: "app"
  - drop_fields:
      fields: ["host", "input", "agent", "ecs", "log", "message"]
      ignore_missing: true
  - rename:
      fields:
        - from: "app.message"
          to: "message"
        - from: "app.level"
          to: "level"
        - from: "app.logger"
          to: "logger"
        - from: "app.thread"
          to: "thread"
      ignore_missing: true
      fail_on_error: false
  - drop_fields:
      fields: ["app"]
      ignore_missing: true

# output.console:
#   pretty: true

output.elasticsearch:
  hosts: ["http://localhost:9200"]
  index: "app-logs-000001"
  username: "elastic"
  password: "your_strong_password123"

setup.kibana:
  host: "localhost:5601"

setup.ilm:
  enabled: true
  policy_name: "app-logs-ilm-policy"
  policy_file: "ilm-policy.json"

setup.template:
  enabled: true
  name: "app-logs"
  pattern: "app-logs-*"
  settings:
    index.number_of_shards: 1
    index.number_of_replicas: 0
  fields: "my_fields.yaml"

注意以下两点:

  • parsers中配置多行解析器,以处理出现异常的情况;

  • dissect中解析日志时,使用->表示多余的空格,如%{level->}

my_fields.yml如下:

yaml
- key: my_app
  fields:
    - name: message
      type: text
    - name: level
      type: keyword
    - name: logger
      type: keyword
    - name: thread
      type: keyword

3.3 效果演示

image-20260110110148335