filebeat生产环境配置

配置文件属性

生产配置

filebeat.inputs: 
- type: log
  enabled: true
  paths: 
  - /tmp/logs/*.log
  - /var/log/system.log
  - /var/log/wifi.log
  symlinks: true
  json.keys_under_root: true
  json.message_key: xxx
  json.add_error_key: true
  # 如果想卡部分日志,比如用时间作为过滤条件,加上下面两个选项,一个是时间筛选,一个是句柄是否关闭
  ignore_older: 168h
  close_inactive: 24h
  
  multiline.pattern: '^\s+|^"'
  multiline.match: after
  fields:
    type: fb-urmp-xx-test
  fields_under_root: true
output.console:
  pretty: true

参数释义

paths

待收集日志的路径列表

symlinks

使用 symlinks 属性的主要场景包括:

  1. 日志轮转:有些日志轮转工具会创建符号链接指向最新的日志文件。启用 symlinks 后,Filebeat 可以确保收集到最新的日志内容。
  2. 一致性路径:在一些系统中,符号链接可能用于统一路径,而实际文件位置可能会变化。通过设置 symlinks,Filebeat 可以稳定地读取这些符号链接指向的日志文件。

假设你有一个应用程序,它生成的日志文件在 /var/log/myapp/ 目录下,并且有一个日志轮转机制。轮转机制会将旧日志重命名并创建一个符号链接指向最新的日志文件,如下所示:

/var/log/myapp/
├── myapp.log -> myapp.log.20240628
├── myapp.log.20240626
├── myapp.log.20240627
└── myapp.log.20240628

在上面的结构中,myapp.log 是一个符号链接,指向 myapp.log.20240628,这是最新的日志文件。

不使用 symlinks

如果你在 Filebeat 配置中没有启用 symlinks

这种情况下,Filebeat 只会读取实际的日志文件,即 myapp.log.20240626myapp.log.20240627myapp.log.20240628,不会读取 myapp.log(符号链接)。如果日志轮转机制仅更新符号链接而不生成新文件,Filebeat 可能会漏掉最新的日志数据。

如果你在 Filebeat 配置中启用了 symlinks

这种情况下,Filebeat 不仅会读取实际的日志文件 myapp.log.20240626myapp.log.20240627myapp.log.20240628,还会读取 myapp.log 所指向的最新日志文件 myapp.log.20240628。这样,即使日志轮转机制只更新符号链接,Filebeat 也能获取到最新的日志内容。

json_xxx

json.keys_under_root

这个属性用于指定 JSON 键是否应该被解析为顶级字段。当设置为 true 时,意味着 JSON 对象中的所有键都将被解析为顶级字段,而不是嵌套在 message 字段下,并且没有message字段了

比如,我现在日志目录里面生成一条json日志:

{"timestamp":"2024-06-28T12:00:00Z","loglevel":"INFO444","logs":"User logged in"}

使用之后:

{
  "@timestamp": "2024-06-28T09:44:06.150Z",
  ...,
  ...,
  "timestamp": "2024-06-28T12:00:00Z",
  "loglevel": "INFO444",
  "logs": "User logged in",
  "input": {
    "type": "log"
  },
  ...,
}
json.add_error_key

当设置为 true 时,如果 JSON 解析过程中出现错误,Filebeat 会在输出中添加一个 json_error 键,并将错误信息存储在这个键下。这有助于调试和识别解析错误。

比如,我现在日志目录里面生成一条json日志:(注意看,不符合json规范)

{"timestamp":"2024-06-28T12:00:00Z","loglevel":"INFO444","logs":"User logged in

设置json.add_error_key: true

效果:

{
  "@timestamp": "2024-06-28T09:45:29.164Z",
  "@metadata": {
    "beat": "filebeat",
    "type": "_doc",
    "version": "7.16.3"
  },
  ...,
  //看这里,解析错误会多生成这个
  "error": {
    "message": "Error decoding JSON: invalid character '\\n' in string literal",
    "type": "json"
  },
  "message": "{\"timestamp\":\"2024-06-28T12:00:00Z\",\"loglevel\":\"INFO444\",\"logs\":\"User logged in"
}
json.message_key

建议搭配json.add_error_key: true来使用

使用这个属性的话,采集的日志没有message字段

这个值用来 在解析json错误的时候,将日志的源值添加到这个字段中

json.message_key 设置一个日志原值已经存在的字段,如果json解析正常的话,那么该属性继续显示日志原值的值

如果设置一个日志原值已经不存在的字段json解析正常的话,那么该属性的值为空串

如果解析失败的话,那么就会将日志的原值添加到这个字段中

比如日志原值为:

{"timestamp":"2024-06-28T12:00:00Z","loglevel":"INFO444","logs":"User logged in"}
设置json.message_key:logs的话,json解析正常的话,没有用,但是filbeat采集的日志没有message字段
设置json.message_key:test的话,json解析正常的话,fileat采集的日志多出一个test字段,但是test为空串,没有message字段

比如我设置为 json.message_key: logs,json.add_error_key: true

那么我日志里面生成一条数据

{"timestamp":"2024-06-28T12:00:00Z","loglevel":"INFO444","logs":"User logged in

filebeat采集的信息为:

{
  "@timestamp": "2024-06-28T09:57:15.426Z",
  ...,
  //看这里,logs存储的是日志的原值
  "logs": "{\"timestamp\":\"2024-06-28T12:00:00Z\",\"loglevel\":\"INFO444\",\"logs\":\"User logged in",
  "log": {
    "offset": 7704,
    "file": {
      "path": "/tmp/logs/urmp-manager.log"
    }
  },
  ...,
}

如果日志json正确解析的话,filebeat采集的日志为:

{
  "@timestamp": "2024-06-28T10:10:19.555Z",
  ...,
  "loglevel": "INFO444",
  ...,
  "logs": "User logged in",
  "timestamp": "2024-06-28T12:00:00Z",
  "input": {
    "type": "log"
  }
...
}

multiline_xx

multiline.pattern

指定用于匹配多行的正则表达式

multiline.match

multiline.pattern: ‘^\s’
multiline.match: after

指定Filebeat如何把多行合并成一个事件。可选的值是 after 或者 before

如果match=after,则以空格开头的和前面一行将合并成一条完整日志;如果 match=before,则以 空格 开头的和后面一行将合并成一条完整日志。

multiline.negate

默认为false,表示匹配pattern的行合并到上一行;true表示不匹配pattern的行合并到上一行;

假如

multiline.pattern: ‘^\s’
multiline.match: after

源日志的内容为:

{"timestamp": "2024-07-09 16:45:23.650","traceId": "[SW_CTX:[test::urmp-manager,urmp-manager-test-75564f678c-swvmg,d529c220b9a045a98e5eb9ea233ac90d.165.17205147234650001,d529c220b9a045a98e5eb9ea233ac90d.165.17205147234650000,0]]","level": "ERROR","service": "urmp-manager", "thread": "http-nio-8080-exec-4", "class": "com.hero.commons.core.handlers.MyExceptionHandler", "msg": "error", "exception":"com.hero.commons.core.exception.MyCustomException: 系统错误
	at com.hero.commons.core.handlers.MyExceptionHandler.handleException(MyExceptionHandler.java:160)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
	at org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:413)
	at org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:74)
" }

如果multiline.negate:true

那么采集的日志内容为:

{
  ...
  "error": {
    "message": "Error decoding JSON: invalid character 'a' looking for beginning of value",
    "type": "json"
  },
  "ori": "\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)",
  "fb_collect_app": "urmp-manager-test"
}
{
 ...
  "ori": "\tat org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:413)",
  "system_env": "test",
}
{
  ...
  "ori": "\tat org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:74)\n\" }",
}

注意看
源日志最后一行" }规则不符合pattern的格式,所以他合并到上一行了,其他符合的并没有合并到上一行

如果multiline.negate:false

采集的日志为

{
 ...,
  "ori": "{\"timestamp\": \"2024-07-09 17:01:48.143\",\"traceId\": \"[SW_CTX:[test::urmp-manager,urmp-manager-test-6db7b7b7bf-5rmvc,77065c0d2a864a28b9a2802143f5b690.166.17205157080370001,77065c0d2a864a28b9a2802143f5b690.166.17205157080370000,0]]\",\"level\": \"ERROR\",\"service\": \"urmp-manager\", \"thread\": \"http-nio-8080-exec-5\", \"class\": \"com.hero.commons.core.handlers.MyExceptionHandler\", \"msg\": \"error\", \"exception\":\"com.hero.commons.core.exception.MyCustomException: 系统错误\n\tat com.hero.commons.core.handlers.MyExceptionHandler.handleException(MyExceptionHandler.java:160)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\n\tat java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)\n\tat java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\n\tat java.base/java.lang.reflect.Method.invoke(Method.java:568)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:207)\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:152)\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)\n\tat org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.doResolveHandlerMethodException(ExceptionHandlerExceptionResolver.java:413)\n\tat org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionResolver.doResolveException(AbstractHandlerMethodExceptionResolver.java:74)",
 ...
}
multiline.pattern

指定一个正则表达式,多行将从内存刷新到磁盘

multiline.max_lines

可以合并成一个事件的最大行数。如果一个多行消息包含的行数超过max_lines,则超过的行被丢弃。默认是500。

fields

topic 对应的消息字段或自定义增加的字段

fields_under_root

如果值为ture,那么fields存储在输出文档的顶级位置

document_type

跟fields字段意思差不多,fields是用来替换他的,他是早期的产物

exclude_lines

exclude_lines: [‘^DBG’] #不包含匹配正则的行

include_lines

include_lines: [‘^ERR’, ‘^WARN’] #包含匹配正则的行

close_inactive

启动选项时,如果在制定时间没有被读取,将关闭文件句柄

ingore_older

#默认为0,表示禁用,可以配置2h,2m等,注意ignore_older必须大于close_inactive的值。

表示忽略超过设置值未更新的文件或者文件从来没有被harvester收集

filebeat工作原理

filebeat结构:由两个组件构成,分别是inputs(输入)和harvesters(收集器),这些组件一起工作来跟踪文件并将事件数据发送到您指定的输出,harvester负责读取单个文件的内容。harvester逐行读取每个文件,并将内容发送到输出。为每个文件启动一个harvester。harvester负责打开和关闭文件,这意味着文件描述符在harvester运行时保持打开状态。如果在收集文件时删除或重命名文件,Filebeat将继续读取该文件。这样做的副作用是,磁盘上的空间一直保留到harvester关闭。默认情况下,Filebeat保持文件打开,直到达到close_inactive

关闭harvester可以会产生的结果:

  • 文件处理程序关闭,如果harvester仍在读取文件时被删除,则释放底层资源。
  • 只有在scan_frequency结束之后,才会再次启动文件的收集。
  • 如果该文件在harvester关闭时被移动或删除,该文件的收集将不会继续

一个input负责管理harvesters和寻找所有来源读取。如果input类型是log,则input将查找驱动器上与定义的路径匹配的所有文件,并为每个文件启动一个harvester。每个input在它自己的Go进程中运行,Filebeat当前支持多种输入类型。每个输入类型可以定义多次。日志输入检查每个文件,以查看是否需要启动harvester、是否已经在运行harvester或是否可以忽略该文件

Filebeat目前支持两种prospector类型:log和stdin。

Filebeat如何保持文件的状态?

Filebeat保留每个文件的状态,并经常将状态刷新到磁盘中的注册表文件中。该状态用于记住harvester读取的最后一个偏移量,并确保发送所有日志行。如果无法访问输出(如Elasticsearch或Logstash),Filebeat将跟踪最后发送的行,并在输出再次可用时继续读取文件。当Filebeat运行时,每个输入的状态信息也保存在内存中。当Filebeat重新启动时,来自注册表文件的数据用于重建状态,Filebeat在最后一个已知位置继续每个harvester。对于每个输入,Filebeat都会保留它找到的每个文件的状态。由于文件可以重命名或移动,文件名和路径不足以标识文件。对于每个文件,Filebeat存储唯一的标识符,以检测文件是否以前被捕获。

filebeat何如保证至少一次数据消费

Filebeat保证事件将至少传递到配置的输出一次,并且不会丢失数据。是因为它将每个事件的传递状态存储在注册表文件中。在已定义的输出被阻止且未确认所有事件的情况下,Filebeat将继续尝试发送事件,直到输出确认已接收到事件为止。如果Filebeat在发送事件的过程中关闭,它不会等待输出确认所有事件后再关闭。当Filebeat重新启动时,将再次将Filebeat关闭前未确认的所有事件发送到输出。这样可以确保每个事件至少发送一次,但最终可能会有重复的事件发送到输出。通过设置shutdown_timeout选项,可以将Filebeat配置为在关机前等待特定时间

工作流程图

在这里插入图片描述

相关推荐

  1. filebeat 配置

    2024-07-17 18:48:03       34 阅读
  2. webpack生产环境下的配置

    2024-07-17 18:48:03       27 阅读
  3. Filebeat rpm方式安装及配置

    2024-07-17 18:48:03       40 阅读
  4. MySQL系统参数配置实战:生产环境优化

    2024-07-17 18:48:03       38 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-17 18:48:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-17 18:48:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-17 18:48:03       58 阅读
  4. Python语言-面向对象

    2024-07-17 18:48:03       69 阅读

热门阅读

  1. js数组去重(4种方法)

    2024-07-17 18:48:03       20 阅读
  2. Python列表基础与高级应用详解

    2024-07-17 18:48:03       25 阅读
  3. 构建可扩展的淘客返利系统架构设计与实现

    2024-07-17 18:48:03       24 阅读
  4. 神经网络类型

    2024-07-17 18:48:03       23 阅读
  5. ArduPilot开源代码之AP_DAL_GPS

    2024-07-17 18:48:03       20 阅读
  6. 江苏服务器租用:算力服务器适用于哪些场景?

    2024-07-17 18:48:03       19 阅读
  7. C语言求阶乘

    2024-07-17 18:48:03       19 阅读
  8. 力扣每日一题:2956. 找到两个数组中的公共元素

    2024-07-17 18:48:03       26 阅读
  9. 星月工作室信息组团队/XYOI

    2024-07-17 18:48:03       27 阅读
  10. EXIT_SUCCESS、EXIT_FAILURE、return的区别和用法

    2024-07-17 18:48:03       21 阅读
  11. 07 - FFmpeg 更改视频分辨率 - 保存 yuv420p

    2024-07-17 18:48:03       19 阅读