使用Spring Cloud Sleuth在應(yīng)用中進行日志跟蹤

Spring Cloud Sleuth是一個在應(yīng)用中實現(xiàn)日志跟蹤的強有力的工具嗅义。使用Sleuth庫可以應(yīng)用于計劃任務(wù) 续扔、多線程服務(wù)或復(fù)雜的Web請求悬包,尤其是在一個由多個服務(wù)組成的系統(tǒng)中铭若。當(dāng)我們在這些應(yīng)用中來診斷問題時枫匾,即使有日志記錄也很難判斷出一個請求需要將哪些操作關(guān)聯(lián)在一起灰追。

如果想要診斷復(fù)雜操作堵幽,通常的解決方案是在請求中傳遞唯一的ID到每個方法來識別日志。而Sleuth可以與日志框架Logback弹澎、SLF4J輕松地集成朴下,通過添加獨特的標(biāo)識符來使用日志跟蹤和診斷問題。

1苦蒿、依賴管理

在Spring Boot Web應(yīng)用中增加Sleuth非常簡單殴胧,只需在pom.xml增加以下的依賴:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

同時添加一個應(yīng)用名稱來識別應(yīng)用程序的日志,在配置文件application.properties file增加一行

spring.application.name=Sleuth Tutorial

2、一個簡單的WEB應(yīng)用

首先創(chuàng)建一個服務(wù)

@Service
public class SleuthService {
    public void doSomeWorkSameSpan() throws InterruptedException {
        Thread.sleep(1000L);
        logger.info("Doing some work");
    }
}

然后寫一個controller去調(diào)用這個服務(wù)

@RestController
public class SleuthController {
    @Autowired
    private final SleuthService sleuthService;
    @GetMapping("/same-span")
    public String helloSleuthSameSpan() throws InterruptedException {
        logger.info("Same Span");
        sleuthService.doSomeWorkSameSpan();
        return "success";
    }
}

啟動應(yīng)用团滥,訪問 http://localhost:8080/same-span竿屹,查看日志

2018-04-16 16:35:54.151  INFO [Sleuth Tutorial,0afe3e67168fce4f,0afe3e67168fce4f,false] 5968 --- [nio-8080-exec-1] c.p.s.cloud.sleuth.SleuthController      : Same Span
2018-04-16 16:35:55.161  INFO [Sleuth Tutorial,0afe3e67168fce4f,0afe3e67168fce4f,false] 5968 --- [nio-8080-exec-1] c.p.spring.cloud.sleuth.SleuthService    : Doing some work

日志的格式為:[application name, traceId, spanId, export]

  • application name — 應(yīng)用的名稱,也就是application.properties中的spring.application.name參數(shù)配置的屬性灸姊。
  • traceId — 為一個請求分配的ID號拱燃,用來標(biāo)識一條請求鏈路。
  • spanId — 表示一個基本的工作單元力惯,一個請求可以包含多個步驟碗誉,每個步驟都擁有自己的spanId。一個請求包含一個TraceId父晶,多個SpanId
  • export — 布爾類型哮缺。表示是否要將該信息輸出到類似Zipkin這樣的聚合器進行收集和展示。

可以看到甲喝,TraceId和SpanId在兩條日志中是相同的尝苇,即使消息來源于兩個不同的類。這就可以在不同的日志通過尋找traceid來識別一個請求俺猿。

3茎匠、異步線程池

添加@Async注解實現(xiàn)異步線程調(diào)用,增加一個配置類來建立線程池

@Configuration
@EnableAsync
public class ThreadConfig extends AsyncConfigurerSupport{
    @Autowired
    private BeanFactory beanFactory;
    
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(7);
        threadPoolTaskExecutor.setMaxPoolSize(42);
        threadPoolTaskExecutor.setQueueCapacity(11);
        threadPoolTaskExecutor.setThreadNamePrefix("MyExecutor-");
        threadPoolTaskExecutor.initialize();

        return new LazyTraceExecutor(beanFactory, threadPoolTaskExecutor);
    }
}

在這里我們繼承了AsyncConfigurerSupport指定了具體的異步執(zhí)行器押袍,使用LazyTraceExecutor 確保traceId和spanId正確的傳遞,同時給類加上@EnableAsync 注解凯肋。

然后在服務(wù)里增加一個異步方法:

@Async
public void asyncMethod() throws InterruptedException {
    logger.info("Start Async Method");
    Thread.sleep(1000L);
    logger.info("End Async Method");
}

同時在controller里調(diào)用此服務(wù)

@GetMapping("/async")
public String helloSleuthAsync() throws InterruptedException {
    logger.info("Before Async Method Call");
    sleuthService.asyncMethod();
    logger.info("After Async Method Call");
    return "success";
}

訪問http://localhost:8080/async谊惭,查看日志如下:

2018-04-16 16:55:06.859  INFO [Sleuth Tutorial,4bc16602ac8262d5,4bc16602ac8262d5,false] 5968 --- [nio-8080-exec-6] c.p.s.cloud.sleuth.SleuthController      : Before Async Method Call
2018-04-16 16:55:06.872  INFO [Sleuth Tutorial,4bc16602ac8262d5,4bc16602ac8262d5,false] 5968 --- [nio-8080-exec-6] c.p.s.cloud.sleuth.SleuthController      : After Async Method Call
2018-04-16 16:55:06.905  INFO [Sleuth Tutorial,4bc16602ac8262d5,4d216310c71e9c22,false] 5968 --- [   MyExecutor-1] c.p.spring.cloud.sleuth.SleuthService    : Start Async Method
2018-04-16 16:55:07.905  INFO [Sleuth Tutorial,4bc16602ac8262d5,4d216310c71e9c22,false] 5968 --- [   MyExecutor-1] c.p.spring.cloud.sleuth.SleuthService    : End Async Method

通過例子可以看到Sleuth將traceId傳入了異步方法并創(chuàng)建了以新的spanId,代表這是同一個請求但進入了另一個處理階段侮东,由一個異步線程來執(zhí)行圈盔。

4、計劃任務(wù)

現(xiàn)在我們來看下Sleuth是怎么在@Scheduled 方法里工作的悄雅,修改ThreadConfig 類是它支持時間調(diào)度驱敲。

@Configuration
@EnableAsync
@EnableScheduling
public class ThreadConfig extends AsyncConfigurerSupport
  implements SchedulingConfigurer {
  
    //...
     
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(schedulingExecutor());
    }
 
    @Bean(destroyMethod = "shutdown")
    public Executor schedulingExecutor() {
        return Executors.newScheduledThreadPool(1);
    }
}

我們在這里實現(xiàn)了SchedulingConfigurer 接口并重寫了configureTasks 方法,同時在類上面添加了@EnableScheduling 注解宽闲。

新寫一個調(diào)度服務(wù)众眨,定義了一個每3秒執(zhí)行一次的計劃任務(wù)。

@Service
public class SchedulingService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private final SleuthService sleuthService;

    @Autowired
    public SchedulingService(SleuthService sleuthService) {
        this.sleuthService = sleuthService;
    }

    @Scheduled(fixedDelay = 30000)
    public void scheduledWork() throws InterruptedException {
        logger.info("Start some work from the scheduled task");
        sleuthService.asyncMethod();
        logger.info("End work from scheduled task");
    }
}

重啟應(yīng)用等待任務(wù)的執(zhí)行容诬,觀察日志:

2018-04-16 17:10:20.232  INFO [Sleuth Tutorial,5d891f56b6f18505,5d891f56b6f18505,false] 7936 --- [pool-1-thread-1] c.p.s.cloud.sleuth.SchedulingService     : Start some work from the scheduled task
2018-04-16 17:10:20.232  INFO [Sleuth Tutorial,5d891f56b6f18505,5d891f56b6f18505,false] 7936 --- [pool-1-thread-1] c.p.s.cloud.sleuth.SchedulingService     : End work from scheduled task
2018-04-16 17:10:20.232  INFO [Sleuth Tutorial,5d891f56b6f18505,abe8b45c36f93be8,false] 7936 --- [   MyExecutor-2] c.p.spring.cloud.sleuth.SleuthService    : Start Async Method
2018-04-16 17:10:21.232  INFO [Sleuth Tutorial,5d891f56b6f18505,abe8b45c36f93be8,false] 7936 --- [   MyExecutor-2] c.p.spring.cloud.sleuth.SleuthService    : End Async Method
2018-04-16 17:10:50.235  INFO [Sleuth Tutorial,0dd33d0764f0e6db,0dd33d0764f0e6db,false] 7936 --- [pool-1-thread-1] c.p.s.cloud.sleuth.SchedulingService     : Start some work from the scheduled task
2018-04-16 17:10:50.235  INFO [Sleuth Tutorial,0dd33d0764f0e6db,0dd33d0764f0e6db,false] 7936 --- [pool-1-thread-1] c.p.s.cloud.sleuth.SchedulingService     : End work from scheduled task
2018-04-16 17:10:50.236  INFO [Sleuth Tutorial,0dd33d0764f0e6db,5062d156f65a293e,false] 7936 --- [   MyExecutor-3] c.p.spring.cloud.sleuth.SleuthService    : Start Async Method
2018-04-16 17:10:51.236  INFO [Sleuth Tutorial,0dd33d0764f0e6db,5062d156f65a293e,false] 7936 --- [   MyExecutor-3] c.p.spring.cloud.sleuth.SleuthService    : End Async Method

在這里可以看到Sleuth為每個任務(wù)實例都創(chuàng)建一個新的traceId和spanId娩梨。

5、總結(jié)

通過本文我們看到Spring Cloud Sleuth可以應(yīng)用在各種各樣的單一Web應(yīng)用中览徒。我們可以使用這項技術(shù)輕松地為一個請求采集日志狈定,即使請求跨越多個線程。幫助我們在多線程環(huán)境下進行清晰的調(diào)試,通過識別traceId和spanId來確定每一個操作和操作中的每一步纽什,這樣可以減輕我們做日志分析的復(fù)雜性措嵌。

除了在單一應(yīng)用外,Spring Cloud Sleuth為微服務(wù)架構(gòu)中的分布式服務(wù)跟蹤問題提供了一套完整的解決方案芦缰∑蟪玻可應(yīng)用于通過RestTemplate發(fā)起的請求,通過Zuul代理傳遞的請求饺藤,通過諸如RabbitMQ包斑、Kafka(或者其他任何Spring Cloud Stream綁定器實現(xiàn)的消息中間件)轉(zhuǎn)遞的請求。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末涕俗,一起剝皮案震驚了整個濱河市罗丰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌再姑,老刑警劉巖萌抵,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異元镀,居然都是意外死亡绍填,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門栖疑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讨永,“玉大人,你說我怎么就攤上這事遇革∏淠郑” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵萝快,是天一觀的道長锻霎。 經(jīng)常有香客問我,道長揪漩,這世上最難降的妖魔是什么旋恼? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮奄容,結(jié)果婚禮上冰更,老公的妹妹穿的比我還像新娘。我一直安慰自己嫩海,他們只是感情好冬殃,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叁怪,像睡著了一般审葬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天涣觉,我揣著相機與錄音痴荐,去河邊找鬼。 笑死官册,一個胖子當(dāng)著我的面吹牛生兆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膝宁,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鸦难,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了员淫?” 一聲冷哼從身側(cè)響起合蔽,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎介返,沒想到半個月后拴事,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡圣蝎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年刃宵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片徘公。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡牲证,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出关面,到底是詐尸還是另有隱情从隆,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布缭裆,位于F島的核電站,受9級特大地震影響寿烟,放射性物質(zhì)發(fā)生泄漏澈驼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一筛武、第九天 我趴在偏房一處隱蔽的房頂上張望缝其。 院中可真熱鬧,春花似錦徘六、人聲如沸内边。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽漠其。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間和屎,已是汗流浹背拴驮。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柴信,地道東北人套啤。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像随常,于是被迫代替她去往敵國和親潜沦。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理绪氛,服務(wù)發(fā)現(xiàn)唆鸡,斷路器,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 文章主要翻譯自Spring Cloud Sleuth官方文檔 Spring-Cloud Spring Cloud為...
    莫莫小熊閱讀 652,009評論 7 32
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,806評論 6 342
  • 要加“m”說明是MB钞楼,否則就是KB了. -Xms:初始值 -Xmx:最大值 -Xmn:最小值 java -Xms8...
    dadong0505閱讀 4,829評論 0 53
  • 軟件是有生命的喇闸,你做出來的架構(gòu)決定了這個軟件它這一生是坎坷還是幸福。 本文不是講解如何使用Spring Cloud...
    Bobby0322閱讀 22,648評論 3 166