關(guān)于Java應(yīng)用日志與Jaeger的trace關(guān)聯(lián)的問題
歡迎訪問我的GitHub
https://github.com/zq2599/blog_demos
內(nèi)容:所有原創(chuàng)文章分類匯總及配套源碼,涉及Java、Docker、Kubernetes、DevOPS等;
本篇概覽
- 經(jīng)過[《Jaeger開發(fā)入門(java版)》]的實戰(zhàn),相信您已經(jīng)能將自己的應(yīng)用接入Jaeger,并用來跟蹤定位問題了,本文將介紹Jaeger一個小巧而強大的輔助功能,用少量改動大幅度提升定位問題的便利性:將業(yè)務(wù)日志與Jaeger的trace關(guān)聯(lián)
- 在正式開始前,咱們先來看一個具體的問題:
一次web請求可能有多條業(yè)務(wù)日志(log4j或者logback配置的那種),這和您寫代碼執(zhí)行l(wèi)og.info的次數(shù)有關(guān),假設(shè)有10條,那么十次請求就有一百條業(yè)務(wù)日志;
通過jaeger發(fā)現(xiàn)這十次請求中有一次耗時特別長,想定位一下具體原因,現(xiàn)在問題來了:一共有100條業(yè)務(wù)日志,到底哪些是和Jaeger中耗時長的那一次請求有關(guān)?
- 您可能會說:有些業(yè)務(wù)特征如user-id,咱們可以寫入span的tag或者log中,這樣通過span查到user-id,再去日志中查找含有此user-id的日志即可,這樣確實可以,但未必每條日志都有user-id,所以并非最佳方式
- 好在Jaeger官方給出了一種簡單有效的方案:基于MDC,Jaeger的SDK在日志中注入trace相關(guān)的變量
關(guān)于MDC
- 關(guān)于sl4j的MDC不是本篇的重點,因此只把本篇用到的特性簡單說說即可,經(jīng)驗豐富的您如果對MDC已經(jīng)了解,請?zhí)^此節(jié)
- 在sl4j的配置文件中可以配置日志的格式,例如logback的配置文件如下,可見模板中新增了一段內(nèi)容[user-id=%X{user-id}]:
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <!--%logger{10}表示類名過長時會自動縮寫--> <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{10} [user-id=%X{user-id}] %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender>
再來看一段日志的代碼,先調(diào)用MDC.put方法將一個鍵值對寫入當前線程的診斷上下文map(diagnostic context map),鍵名和上面的模板中配置的%X{user-id}一模一樣:
@GetMapping("/test") public void test() { MDC.put("user-id", "user-" + System.currentTimeMillis()); log.info("this is test request"); }
現(xiàn)在把代碼運行起來,打印日志看看,如下所示,之前模板中配置的%X{user-id}已被替換成了user-1632122267618,就是代碼中MDC.put設(shè)置的值:
15:17:47 [http-nio-18081-exec-6] INFO c.b.j.c.c.HelloConsumerController [user-id=user-1632122267618] this is test request
以上就是MDC的基本功能:對日志模板中的變量進行填充,填充的內(nèi)容可以用MDC.put方法隨意設(shè)置;
此刻聰明的您應(yīng)該能猜到j(luò)aeger官方的方案是如何實現(xiàn)的了,沒錯,就是借助MDC將trace信息填充到日志模板中,這樣每行日志都有了trace信息,咱們在jaeger web頁面中感興趣的任何一次trace,都能找到對應(yīng)的日志了
關(guān)于Jaeger的官方方案
Jaeger的官方方案如下圖所示,SDK已經(jīng)把traceId、spanId、sampled寫入當前線程的診斷上下文map(diagnostic context map),只要日志模板中配置上述三個變量,就會在所有業(yè)務(wù)日志中輸出它們具體的值:
看起來似乎非常簡單,那就動手編碼試試吧
編碼實戰(zhàn)
- jaeger與MDC的關(guān)聯(lián)只是個小功能,沒必要大張旗鼓的新建項目,基于[《Jaeger開發(fā)入門(java版)》]的代碼繼續(xù)開發(fā)即可,也就是說修改兩個子工程jaeger-service-consumer和jaeger-service-provider的源碼,讓它們的業(yè)務(wù)日志打印出Jaeger的trace信息
- 首先從jaeger-service-provider工程開始,增加一個標準的logback日志配置文件logback.xml,如下所示,日志模板中已添加了traceId、spanId、sampled變量:
<?xml version="1.0" encoding="UTF-8"?> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <contextName>logback</contextName> <!--輸出到控制臺--> <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <!--%logger{10}表示類名過長時會自動縮寫--> <pattern>%d{HH:mm:ss} [%thread] %-5level %logger{10} [traceId=%X{traceId} spanId=%X{spanId} sampled=%X{sampled}] %msg%n</pattern> <charset>utf-8</charset> </encoder> </appender> <root level="info"> <appender-ref ref="console" /> </root> </configuration>
再去檢查配置類,確認JaegerTracer實例化時用了MDCScopeManager參數(shù),如下所示,咱們在上一章已經(jīng)這么做了,可以維持不變:
package com.bolingcavalry.jaeger.provider.config; import io.jaegertracing.internal.MDCScopeManager; import io.opentracing.contrib.java.spring.jaeger.starter.TracerBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class JaegerConfig { @Bean public TracerBuilderCustomizer mdcBuilderCustomizer() { // 1.8新特性,函數(shù)式接口 return builder -> builder.withScopeManager(new MDCScopeManager.Builder().build()); } }
接下來是在業(yè)務(wù)代碼中隨意加幾行打印日志的代碼,如下圖紅框所示:
接下來繼續(xù)修改jaeger-service-consumer子工程,具體步驟與剛才改造jaeger-service-provider時一模一樣,就不多占用篇幅贅述了,記得在業(yè)務(wù)代碼中隨意加幾行日志,如下圖紅框:
開發(fā)完成,開始驗證吧
驗證
- 像[《Jaeger開發(fā)入門(java版)》]那樣操作,將jaeger-service-consumer和jaeger-service-provider編譯構(gòu)建制作成docker鏡像
- 用docker-compose將所有服務(wù)啟動,然后通過瀏覽器訪問jaeger-service-consumer的服務(wù),多訪問幾次
- 打開jaeger的web頁面,可以看到多次請求的trace,咱們隨機選擇一個,鼠標點擊下圖紅框中的圓點:
此時會跳轉(zhuǎn)到該trace的詳情頁,注意頁面的url,如下圖紅框,里面的2037fe105d73f4a5就是traceid:
用2037fe105d73f4a5搜索jaeger-service-provider的日志,由于應(yīng)用部署在docker中,咱們要用docker log和grep命令組合來過濾,如下所示,咱們代碼寫的日志都打印出來了,并且紅框中就是traceid等關(guān)鍵信息
再去查看jaeger-service-consumer的日志,如下圖紅框,本次請求相關(guān)的日志也可以通過traceid搜索到:
至此,本篇實戰(zhàn)就完成了,Jaeger的web頁面上的任何一個trace,現(xiàn)在都能輕易找到與之對應(yīng)的所有業(yè)務(wù)日志,這在定位問題時簡直是如虎添翼的效果,如果您的系統(tǒng)用了ELK或者EFK來匯總所有分布式服務(wù)的日志,那就更高效了
到此這篇關(guān)于Java應(yīng)用日志如何與Jaeger的trace關(guān)聯(lián)的文章就介紹到這了,更多相關(guān)Java應(yīng)用日志與Jaeger的trace關(guān)聯(lián)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot多級緩存實現(xiàn)方案總結(jié)
所謂多級緩存,是指在整個系統(tǒng)架構(gòu)的不同系統(tǒng)層面進行數(shù)據(jù)緩存,以提升訪問速度,多級緩存就是為了解決項目服務(wù)中單一緩存使用不足的缺點,本文我們將給大家總結(jié)了SpringBoot多級緩存實現(xiàn)方案,需要的朋友可以參考下2023-08-08淺談java中異步多線程超時導(dǎo)致的服務(wù)異常
下面小編就為大家?guī)硪黄獪\談java中異步多線程超時導(dǎo)致的服務(wù)異常。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-06-06Spring Boot Admin Server管理客戶端過程詳解
這篇文章主要介紹了Spring Boot Admin Server管理客戶端過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-03-03Java數(shù)據(jù)結(jié)構(gòu)和算法之鏈表詳解
鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結(jié)構(gòu),java代碼實現(xiàn)單鏈表,插入,刪除和遍歷等功能,這篇文章主要給大家介紹了關(guān)于Java數(shù)據(jù)結(jié)構(gòu)和算法之鏈表的相關(guān)資料,需要的朋友可以參考下2024-01-01Java Web學習之Cookie和Session的深入理解
這篇文章主要給大家介紹了關(guān)于Java Web學習之Cookie和Session的相關(guān)資料,需要的朋友可以參考下2018-04-04分享Java8中通過Stream對列表進行去重的實現(xiàn)
本文主要介紹了分享Java8中通過Stream對列表進行去重的實現(xiàn),包括兩種方法,具有一定的參考價值,感興趣的可以了解一下2023-11-11spring batch 讀取多個文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫示例
本篇文章主要介紹了spring batch 讀取多個文件數(shù)據(jù)導(dǎo)入數(shù)據(jù)庫示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-03-03