Spring boot 配置 Fluent bit 传递 Log

上篇文章透过 docker-compose 进行 Log 传递,这次则是使用 Spring boot 环境变数进行定义。范例在github 上,这个专案主要是实现简单的 CRUD,後续有加 Log 相关的配置。

首先,主要加入以下的库。

...
<dependency>
			<groupId>org.fluentd</groupId>
			<artifactId>fluent-logger</artifactId>
			<version>0.3.4</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>
		<!-- send to flunted -->
		<dependency>
			<groupId>com.sndyuk</groupId>
			<artifactId>logback-more-appenders</artifactId>
			<version>1.8.0</version>
		</dependency>

		<dependency>
			<groupId>net.logstash.logback</groupId>
			<artifactId>logstash-logback-encoder</artifactId>
			<version>6.6</version>
		</dependency>

configuration/Fluentd.java 中定义了一个关於 Fluent bit 的连线配置。

@Configuration
@ConfigurationProperties(prefix = "cch.fluentd")
@Setter
@Getter
public class Fluentd {
    @Value("${cch.fluentd.host}")
    private String host;
    @Value("${cch.fluentd.port}")
    private String port;
}

连线配置可以如在 src/main/resources/application.properties 下的配置

...
logging.config=classpath:logback-spring.xml 
cch.fluentd.host=192.168.101.129 # this
cch.fluentd.port=3003 # this

src/main/resources 下定义一个 logback-spring.xml 它是用来配置 Log,在上一篇并没有这个。定义内容如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- springProperty 可当作是环境变数宣告-->
    <springProperty scope="context" name="fluentHost" source="cch.fluentd.host"/>
    <springProperty scope="context" name="fluentPort" source="cch.fluentd.port" defaultValue="24224" />
    <springProperty scope="context" name="springAppName" source="spring.application.name" />
    <springProperty scope="context" name="env" source="spring.profiles.active" defaultValue="local"/>
    <!-- 建立一个 `ConsoleAppender` 的类,相似於 `System.out.print` 打印数据一样。该配置设置了日志输出的格式,这些表示方式根据已发送到记录器的讯息替换为生成的值。
-->
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- console 打印 -->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5level - %logger{36} - %msg trace_id=%X{trace_id} span_id=%X{span_id} trace_flags=%X{trace_flags} %n</pattern> <!-- 定义 Log 结构,可以参考 https://ithelp.ithome.com.tw/articles/10263898 -->
        </encoder>
    </appender>
    <appender name="FLUENT" class="ch.qos.logback.more.appenders.DataFluentAppender"> <!-- 定义 传递到 fluent bit 的连线 -->
        <tag>debug</tag>
        <label>normal</label>
        <remoteHost>${fluentHost}</remoteHost>
        <port>${fluentPort}</port>

        <additionalField>
            <key>env</key>
            <value>${env}</value>
        </additionalField>

        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <!-- 将日志转 Json 格式-->
            <providers class="net.logstash.logback.composite.loggingevent.LoggingEventJsonProviders">
                <pattern>
                    <pattern>
                        {
                        "timestamp": "%date{ISO8601}",
                        "level": "%level",
                        "application": "${springAppName:-}",
                        "trace": "%X{trace_id:-}",
                        "span": "%X{span_id:-}",
                        "trace_flags": "%X{trace_flags:-}",
                        "pid": "${PID:-}",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "message": "%message"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
   
    <springProfile name="dev">
        <root level="DEBUG">
			<appender-ref ref="STDOUT" />
            <appender-ref ref="FLUENT" />
		</root>
    </springProfile>
    <!-- 配置将日志写入档案 -->
    <springProfile name="file">
        <property name="logPath" value="/var/log"/>
        <appender name="fileInfoLog" filePermissions="rw-r--r--" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
                <providers class="net.logstash.logback.composite.loggingevent.LoggingEventJsonProviders">
                    <pattern>
                        <pattern>
                            {
                                "timestamp": "%date{ISO8601}",
                                "level": "%level",
                                "application": "${springAppName:-}",
                                "trace": "%X{trace_id:-}",
                                "span": "%X{span_id:-}",
                                "trace_flags": "%X{trace_flags:-}",
                                "pid": "${PID:-}",
                                "thread": "%thread",
                                "class": "%logger{40}",
                                "message": "%message"
                            }
                        </pattern>
                    </pattern>
                </providers>
            </encoder>
            <!--滚动策略-->
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <!--路径-->
                <fileNamePattern>${logPath}/info.%d{dd-MM-yyyy}_%i.log</fileNamePattern>
                <maxHistory>7</maxHistory>
                <maxFileSize>10MB</maxFileSize>
                <totalSizeCap>100MB</totalSizeCap>
            </rollingPolicy>
        </appender>

        <root level="INFO">
            <appender-ref ref="STDOUT" />
            <appender-ref ref="fileInfoLog" /> 
        </root>
    </springProfile>

    <springProfile name="prod">
        <root level="ERROR">
			<appender-ref ref="STDOUT" />
            <appender-ref ref="FLUENT" />
		</root>
    </springProfile>

    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FLUENT" />
    </root>
</configuration>

在配置上使用了 springProfile 来切分不同环境上的输出要什麽,当中 <springProfile name="file"> 的范畴定义了以档案方式储存 Log,并定义其生命周期,如下

<!--滚动策略-->
            <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
                <!--路径-->
                <fileNamePattern>${logPath}/info.%d{dd-MM-yyyy}_%i.log</fileNamePattern>
                <maxHistory>7</maxHistory>
                <maxFileSize>10MB</maxFileSize>
                <totalSizeCap>100MB</totalSizeCap>
            </rollingPolicy>

下面的配置可以说是,prod 环境,打印的 Log 是 ERROR 等级,其输出内容参照 STDOUT(<appender name="STDOUT"... ) 和 FLUENT(<appender name="FLUENT"...)

    <springProfile name="prod">
        <root level="ERROR">
			<appender-ref ref="STDOUT" />
            <appender-ref ref="FLUENT" />
		</root>
    </springProfile>

下面是预设环境的输出

    <root level="INFO">
        <appender-ref ref="STDOUT" />
        <appender-ref ref="FLUENT" />
    </root>

在此范例中我们可以透过 otel-docker-compose.yml 环境变数指定我们的环境变数

SPRING_PROFILES_ACTIVE: prod  # 指定我们要 DEV 还是 PROD,它会对应不同 Log 的打印和配置
CCH_FLUENTD_PORT: 3003 # 指定 Fluent bit port
CCH_FLUENTD_HOST: 192.168.101.129 # Fluent bit IP 位置

要运行的话须将 OTEL 开头相关的环境变数进行注解

至於在 Spring boot 中为不同开发环境设置不同的配置可以如下设置,它们都定义在 resources 目录下,命名规则通常是 application-${开发环境}.properties。如果要执行的话我们可以将 SPRING_PROFILES_ACTIVE 设置为 file 或是 dev 值,就会读取相对应的 properties 档案

.
├── application-dev.properties # 针对 dev
├── application-file.properties # 针对 file
├── application-prod.properties # 针对 prod
├── application.properties # 预设

<<:  [Day 04] 眼前的黑不是黑,你说的白是什麽白?(直方图均衡化)

>>:  从零开始的8-bit迷宫探险【Level 11】在 iPhone 里盖座迷宫,就。很。墙

[DAY 14] getRange 与 getDataRange

接下来说说我觉得非常好用的两个函数 getRange 与 getDataRange 这两个函数在取得...

Day07 NAT 类型

NAT 网路位址转换(英语:Network Address Translation,缩写:NAT)是...

Day15 - Ptt换页及新增文章列表项目

今天的内容算是当初一时没考虑到的东西。 主要是Ptt一页的文章最多列出20篇,若要搜寻到20篇以前的...

【程序】Onboarding process 转生成恶役菜鸟工程师避免 Bad End 的 30 件事 - 21

Onboarding process 第一周有哪些重点 每个月定期追踪 第三个月是最危险的 ...

Rails幼幼班--由seeds认识Rake

什麽时候知道自己已经是大叔了...从看到国民妹妹会露出姨母笑时... 或许这部分比较简单,网路上查不...