1. 概述
HTTP API 請求現在已成為大多數應用程序的一部分。`Logbook 是一個可擴展的 Java 庫,用於為不同的客户端和服務器端技術啓用完整的請求和響應日誌記錄。它允許開發人員記錄應用程序接收或發送的任何 HTTP 流量。這可用於日誌分析、審計或調查流量問題。
在本文中,讓我們來了解一下將 Logbook 庫與 Spring Boot 應用程序集成的過程。
2. 依賴項
要使用 Logbook 庫與 Spring Boot 結合使用,請將以下依賴項添加到項目中:
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-spring-boot-starter</artifactId>
<version>3.9.0</version>
</dependency>我們可以在 Maven Central 找到最新版本的 Logbook 庫。
3. 配置
Logbook 與 Spring Boot 應用程序中的 logback 日誌記錄系統配合使用。我們需要向 logback-spring.xml 和 application.properties 文件添加配置。
一旦我們將 Logbook 庫添加到 pom.xml 中,Logbook 庫將與 Spring Boot 自動配置。 讓我們為 application.properties 文件添加一個日誌級別:
logging.level.org.zalando.logbook.Logbook=TRACE
日誌級別 TRACE 啓用 HTTP 請求和響應的日誌記錄。
此外,我們在 logback-spring.xml 文件中添加了 Logbook 配置:
<logger name="org.zalando.logbook" level="INFO" additivity="false">
<appender-ref ref="RollingFile"/>
</logger>一旦添加完成,我們就可以使用 HTTP 請求運行該應用程序。在每次 HTTP 請求調用之後,Logbook 庫會將請求和響應記錄到 logback-spring.xml配置中指定的日誌文件路徑上:
11:08:14.737 [http-nio-8083-exec-10] TRACE org.zalando.logbook.Logbook - Incoming Request: eac2321df47c4414
Remote: 0:0:0:0:0:0:0:1
GET http://localhost:8083/api/hello?name=James HTTP/1.1
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
accept-encoding: gzip, deflate, br, zstd
...
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36
11:08:14.741 [http-nio-8083-exec-10] TRACE org.zalando.logbook.Logbook - Outgoing Response: eac2321df47c4414
Duration: 4 ms
HTTP/1.1 200 OK
...
Date: Tue, 18 Jun 2024 05:38:14 GMT
Keep-Alive: timeout=60
Hello, James!
我們已經看到 Logbook 庫如何通過最小配置與 Spring Boot 集成。然而,這只是基本的請求和響應日誌記錄。在下一部分中,我們將深入瞭解更多配置。
4. 過濾與格式化
我們可以聲明 Logbook 庫的配置 Bean:
@Bean
public Logbook logbook() {
Logbook logbook = Logbook.builder()
.condition(Conditions.exclude(Conditions.requestTo("/api/welcome"),
Conditions.contentType("application/octet-stream"),
Conditions.header("X-Secret", "true")))
.sink(new DefaultSink(new DefaultHttpLogFormatter(), new DefaultHttpLogWriter()))
.build();
return logbook;
}在上述代碼示例中,我們聲明瞭 Logbook Bean,以便 Spring Boot 能夠將其加載用於配置。
現在,我們在構建 Logbook Bean 時指定了條件。 在 exclude() 方法中指定的請求映射將被排除在日誌記錄之外。 這種情況下的 Logbook 庫將不會記錄 API 映射到路徑 “/api/welcome” 的請求或響應。 同樣,我們使用 contentType() 方法對具有內容類型的請求進行了過濾,並使用 header() 方法對標頭進行了過濾。
同樣,應該在 include() 方法中指定應該包含的 HTTP API。 如果我們不使用 include() 方法,Logbook 將記錄所有未在 exclude() 方法中提到的請求。
為了使此過濾配置生效,應在 application.properties 文件中設置過濾器屬性。 屬性 logbook.filter.enabled 應設置為 true:
logbook.filter.enabled=true日誌簿庫記錄請求和響應,使用 sl4j 記錄器,該記錄器使用 org.zalando.logbook.Logbook 類別,默認日誌級別為 trace:
sink(new DefaultSink(
new DefaultHttpLogFormatter(),
new DefaultHttpLogWriter()
))<div>
<p>此默認配置啓用應用程序中的日誌記錄:</p>
</div>
GET http://localhost:8083/api/hello?name=John HTTP/1.1
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
....
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 47
Content-Type: text/html;charset=UTF-8
Date: Fri, 07 Jun 2024 11:12:27 GMT
Keep-Alive: timeout=60
Hello, John
可以將這些響應記錄到 System.out 或 System.err 中,這將在控制枱上打印出來:
Logbook logbook = Logbook.builder()
.sink(new DefaultSink(
new DefaultHttpLogFormatter(),
new StreamHttpLogWriter(System.out)
))
.build();我們應該避免在生產環境中使用控制枱打印,但在必要時,可以在開發環境中進行使用。
5. 接收器 (Sinks)
直接實現 接收器 (Sink) 接口,可以實現更復雜的用例,例如,將請求/響應寫入結構化的持久存儲,如數據庫。
5.1. 常見漏洞點 (Common Sinks)
Logbook 提供了一些 Sink 的實現,這些實現使用了常見的日誌格式,例如 CommonsLogFormatSink 和 ExtendedLogFormatSink。
ChunkingSink 將長消息分割成更小的塊,並分別寫入,同時將它們委託給另一個 Sink:
Logbook logbook = Logbook.builder()
.sink(new ChunkingSink(sink, 1000))
.build();5.2. Logstash Sink
Logbook 提供了一個 logstash 編碼器,位於一個附加的庫中。 讓我們來看一個 LogstashLogbackSink 的示例。 為此,我們在 <em><a href="https://mvnrepository.com/artifact/org.zalando/logbook-logstash">pom.xml</a> </em> 中添加了 <em><a href="https://mvnrepository.com/artifact/net.logstash.logback/logstash-logback-encoder">logstash-encoder</a></em> 依賴項:
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
<dependency>
<groupId>org.zalando</groupId>
<artifactId>logbook-logstash</artifactId>
<version>3.9.0</version>
</dependency><div>
<p>然後,我們更改在 <em >appender</em > 中的編碼器,位於 <em >logback-spring.xml</em > 中。日誌堆積編碼器啓用 <em >LogstashLogbackSink</em >:</p>
</div>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
...
<encoder class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>現在我們聲明 LogstashLogbackSink 並將其添加到 Logbook 對象構建器中:
HttpLogFormatter formatter = new JsonHttpLogFormatter();
LogstashLogbackSink logstashsink = new LogstashLogbackSink(formatter);
Logbook logbook = Logbook.builder()
.sink(logstashsink)
.build();我們使用了 JsonHttpLogFormatter 與 LogstashLogbackSink,這使得日誌以 JSON 格式打印。
{
"@timestamp": "2024-06-07T16:46:24.5673233+05:30",
"@version": "1",
"message": "200 OK GET http://localhost:8083/api/hello?name=john",
"logger_name": "org.zalando.logbook.Logbook",
"thread_name": "http-nio-8083-exec-6",
"level": "TRACE",
"http": {
...
"Content-Length": [
"12"
],
...
"body": "Hello, john!"
}
}JSON 日誌以單行打印;這裏為了提高可讀性,已進行格式化。
在聲明 LogstashLogbackSink 對象時,我們可以更改日誌級別:
LogstashLogbackSink logstashsink = new LogstashLogbackSink(formatter, Level.INFO);我們還可以使用 SplunkHttpLogFormatter 與 Logbook 接收器一起使用。它以鍵值對格式打印日誌:
origin=remote ... method=GET uri=http://localhost:8083/api/hello?name=John host=localhost path=/api/hello ...5.3. 複合接收器
將多個接收器組合起來,可以形成複合接收器:
CompositeSink compsink = new CompositeSink(Arrays.asList(logstashsink, new CommonsLogFormatSink(new DefaultHttpLogWriter())));
Logbook logbook = Logbook.builder()
.sink(compsink)
.build();此配置使用複合句柄中指定的所有句柄記錄請求詳情。在此,Logbook 通過組合兩個句柄記錄請求:
... "message":"GET http://localhost:8083/api/hello?name=John",... uri":"http://localhost:8083/api/hello?name=John",...
... "message":"200 OK GET http://localhost:8083/api/hello?name=John",.."headers":{"Connection":["keep-alive"],...6. 結論
在本文中,我們學習瞭如何使用最小配置將 Logbook 庫與 Spring Boot 集成。我們還學習瞭如何使用 exclude() 和 include() 方法來過濾請求路徑。此外,我們還學習瞭如何根據需要自定義日誌格式,使用 Sink 實現(如 LogstashLogbackSink)以及格式器(如 JsonHttpLogFormatter)進行定製。