Fluent-Bit 微服务日志采集实战(开箱即用)

文章介绍了如何使用fluent-bit在每台运行Spring-Boot微服务的机器上收集日志,通过统一的日志格式,如ISO8601时间戳,然后转发到FluentBit服务器写入ES数据库。配置包括日志格式化、fluent-bit的部署与配置,以及日志过滤和多行解析规则的设定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

场景

适用于采集spring-boot微服务日志,并将日志统一保存到ES数据库中

准备工作

1. fluent-bit方案

首先确定我们的方案,fluent-bit会部署在每一台运行java微服务的机器上,监听服务生成的日志文件,采集日志后转发到专门负责写入ES的FluentBit服务器上去。
fluent-bit架构

2. 日志格式化

在采集日志之前,我们首先要确保微服务的日志采用统一格式,并且为了后面写入ES更好的识别数据,我们采用了如下的格式。

注意这里日期的输出,我们采用了ISO8601格式,保留了时区,这是为了最终写入ES能保留时区,避免出现时间偏差。

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="10 seconds">
    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
    <springProperty scope="context" name="applicationId" source="spring.application.name"
                    defaultValue="defaultApplication"/>
    <springProperty scope="context" name="log.path" source="nuzarsurf.tracer.log-path"
                    defaultValue="logs"/>
    <!-- 彩色日志 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
    <conversionRule conversionWord="wex"
                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
    <conversionRule conversionWord="wEx"
                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
    <!-- 彩色日志格式 -->
    <property name="LOG_LEVEL_PATTERN"
              value="%5p [${applicationId:-},%X{traceId:-},%X{spanId:-}]"/>
    <property name="CONSOLE_LOG_PATTERN"
              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
    <property name="LOG_PATTERN"
              value="${LOG_PATTERN:-%d{yyyy-MM-dd'T'HH:mm:ss.SSSZ} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%15.15t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!-- 控制台输出日志 -->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
    </appender>

    <!-- 时间滚动输出 level为 INFO 日志 -->
    <appender name="DEFAULT_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${applicationId}.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/${applicationId}-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>2</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
    </appender>

    <!-- 时间滚动输出 level为 ERROR 日志 -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文件的路径及文件名 -->
        <file>${log.path}/${applicationId}_error.log</file>
        <!--日志文件输出格式-->
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/${applicationId}_error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文件保留天数-->
            <maxHistory>2</maxHistory>
        </rollingPolicy>
        <!-- 此日志文件只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!-- 日志输出级别 -->
    <root level="INFO">
        <appender-ref ref="STDOUT"/>
        <appender-ref ref="DEFAULT_FILE"/>
        <appender-ref ref="ERROR_FILE"/>
    </root>
</configuration>

3. fluent-bit部署

# 安装
curl https://raw.githubusercontent.com/fluent/fluent-bit/master/install.sh | sh

# 运行
/opt/fluent-bit/bin/fluent-bit -c //etc/fluent-bit/fluent-bit.conf

4. fluent-bit配置

fluent-bit 的配置需要注意几点:

  1. 多行日志的读取
  2. 日志的regex匹配

特别注意fluent-bit最麻烦的地方其实就是日志的格式匹配了
^(?<time>[^ ]*)\s*(?<level>[^ ]*)\s\[(?<service>[^,]*),(?<traceId>[^,]*),(?<spanId>[^\]]*)\] (?<pid>[^ ]*) --- \[\s*(?<thread>[^\]]*)\] (?<logger>[^ ]*) *: (?<message>[^$]*)
以上正则表达式可以匹配
2023-07-13T10:48:25.984+0800 INFO [demo-web,traceId111,spanId222] 13212 — [ main] com.xxx.demo.DemoApplication : No active profile set, falling back to 1 default profile: “default”
自动解析日志

Rubular测试

fluent-bit我们需要把自定义的parser添加到/etc/fluent-bit/parsers.conf中去

[MULTILINE_PARSER]
    name          micro_mparser
    type          regex
    flush_timeout 1000
    #
    # rules |   state name  | regex pattern                                                                                      | next state
    # ------|---------------|---------------------------------------------------------------------------------------------------------------
    rule      "start_state"   "(?<time>[^ ]*)\s*(?<level>[^ ]*)\s\[(?<service>[^,]*),(?<traceId>[^,]*),(?<spanId>[^\]]*)\] (?<pid>[^ ]*) --- \[\s*(?<thread>[^\]]*)\] (?<logger>[^ ]*) *: (?<message>[^$]*)"            "stack"
    rule      "stack"         "^[a-zA-Z\s].*"                           "stack"

[PARSER]
    Name        micro_parser
    Format      regex
    Regex       (?<time>[^ ]*)\s*(?<level>[^ ]*)\s\[(?<service>[^,]*),(?<traceId>[^,]*),(?<spanId>[^\]]*)\] (?<pid>[^ ]*) --- \[\s*(?<thread>[^\]]*)\] (?<logger>[^ ]*) *: (?<message>[^$]*)
    Time_Key    time
    Time_Format %Y-%m-%dT%H:%M:%S.%L%z

然后配置我们需要监听的文件,这里使用到了我们的多行转换和字段提取

# 开启 multiline.parse 后,parser不生效,需要使用 filter 再次进行解析
[INPUT]
    Name              tail
    Path              /root/app/micro-test/logs/micro-test.log
    Tag               micro_test
    multiline.parser  micro_mparser
    db                micro.db
[FILTER]
    Name         parser
    Parser       micro_parser
    Match        micro_*
    Key_Name     log
    Reserve_Data On
    Preserve_Key Off

之后我们配置以下日志的输出output就行了,这里我放个简化的版本,直接输出到ES数据库

[OUTPUT]
    Name  es
    Match micro_*
    Host  xxx.xxx.xxx.xxx
    Port  9200
    Index micro.%Y.%m.%d
    tls On
    tls.verify Off
    HTTP_User elastic
    HTTP_Passwd xxxxxxxxxxxxxxxxxxxxxxxxx
    Suppress_Type_Name On
以下是使用Ansible部署Fluent Bit的步骤: 1. 安装Ansible 在部署Fluent Bit之前,需要在管理节点上安装Ansible。可以使用以下命令在Debian/Ubuntu系统上安装Ansible: ``` $ sudo apt update $ sudo apt install ansible ``` 在CentOS/RHEL系统上安装Ansible: ``` $ sudo yum install epel-release $ sudo yum install ansible ``` 2. 创建Ansible playbook 创建一个Ansible playbook来安装和配置Fluent Bit。在此过程中,您需要指定Fluent Bit的配置文件和输入源。 以下是一个示例playbook: ``` - hosts: fluentbit_servers become: yes tasks: - name: Install Fluent Bit apt: name: fluent-bit state: present - name: Configure Fluent Bit copy: src: /path/to/fluent-bit.conf dest: /etc/fluent-bit/fluent-bit.conf - name: Start Fluent Bit service: name: fluent-bit state: started ``` 在此playbook中,'fluentbit_servers'是您要在其上部署Fluent Bit的服务器的名称或IP地址。还要将'/path/to/fluent-bit.conf'替换为Fluent Bit配置文件的实际路径。 3. 运行Ansible playbook 运行上述playbook以安装和配置Fluent Bit: ``` $ ansible-playbook fluentbit.yml ``` 在运行此命令之前,请确保已将Fluent Bit配置文件复制到正确的位置,并且在服务器上已安装了Fluent Bit软件包。 4. 验证Fluent Bit 一旦Fluent Bit已安装和配置,您可以使用以下命令检查它是否正在运行: ``` $ sudo systemctl status fluent-bit ``` 此命令应显示Fluent Bit服务的状态信息。如果一切正常,您应该看到“active (running)”状态。 此外,您还可以使用以下命令检查Fluent Bit是否正在接收和处理数据: ``` $ sudo tail -f /var/log/syslog | grep fluent-bit ``` 此命令应显示Fluent Bit正在处理的日志消息。 这就是使用Ansible部署Fluent Bit的步骤。请记住,在实际环境中,您需要根据自己的需求和环境进行自定义配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值