上篇文章透過 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 # 預設