Spring Cloud Sleuth 鏈路追蹤

weixin_34129145發表於2017-12-14

隨著微服務的數量增長,一個業務介面涉及到多個微服務的互動,在出錯的情況下怎麼能夠快速的定位錯誤,這是一個難題。

好在Spring Cloud已經為什麼實現了一個非常好的方案來對服務進行追蹤。

Sleuth就是做這個事情的,它在日誌中引入唯一的請求ID來標識每次請求,通過SpanId來構成整個的鏈路。

只需要引入依賴就可以整合Sleuth

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

在方法中記錄日誌我們會發現在日誌的最前面對了一部分內容,這部分內容就是Sleuth為什麼提供的鏈路資訊

2016-02-02 15:30:57.902  INFO [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
2016-02-02 15:30:58.372 ERROR [bar,6bfd228dc00d216b,6bfd228dc00d216b,false] 23030 --- [nio-8081-exec-3] ...
2016-02-02 15:31:01.936  INFO [bar,46ab0d418373cbc9,46ab0d418373cbc9,false] 23030 --- [nio-8081-exec-4] ...

可以看到內容是由[appname,traceId,spanId,exportable]組成的, 具體含義如下:

  • appname:服務的名稱,也就是spring.application.name的值,這邊要注意下,如果需要輸出正確的服務名稱,需要將spring.application.name的配置寫在bootstrap.properties中
  • traceId:整個請求的唯一ID,它標識整個整個請求的鏈路
  • spanId:基本的工作單元,發起一起遠端呼叫就是一個span
  • exportable:是否匯入資料到Zipkin中

如果僅僅是通過上面的方式,在每條日誌中都記錄請求的鏈路資訊,我們也是可以通過traceId來追蹤整個請求的資訊,但是不是特別直觀,這個時候就需要將資料匯入Zipkin中更直觀的顯示,或者匯入到ES中,用Kibana檢視,方便集中管理。

如果需要將跟蹤的資訊匯入到ES中,可以將跟蹤的資訊以JSON格式的資料輸出,然後用logstash收集輸出到ES中。

輸出JSON格式的日誌首先需要匯入一個依賴包

 <!-- 輸出JSON格式日誌 -->
 <dependency>
      <groupId>net.logstash.logback</groupId>
      <artifactId>logstash-logback-encoder</artifactId>
      <version>4.8</version>
      <scope>runtime</scope>
 </dependency>

然後建立一個logback-spring.xml檔案, 配置logstash需要收集的資料格式

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
    ​
    <springProperty scope="context" name="springAppName" source="spring.application.name"/>

    <!-- Example for logging into the build folder of your project -->
    <property name="LOG_FILE" value="logs\\${springAppName}.log"/>​

    <!-- You can override this to have a custom pattern -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

    <!-- Appender to log to console -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <!-- Minimum logging level to be presented in the console logs-->
            <level>INFO</level>
        </filter>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- Appender to log to file -->​
    <appender name="flatfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>
    ​
    <!-- Appender to log to file in a JSON format -->
    <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}.json</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                        "severity": "%level",
                        "service": "${springAppName:-}",
                        "trace": "%X{X-B3-TraceId:-}",
                        "span": "%X{X-B3-SpanId:-}",
                        "parent": "%X{X-B3-ParentSpanId:-}",
                        "exportable": "%X{X-Span-Export:-}",
                        "pid": "${PID:-}",
                        "thread": "%thread",
                        "class": "%logger{40}",
                        "rest": "%message"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>
    ​
    <root level="INFO">
        <appender-ref ref="console"/>
        <!-- uncomment this to have also JSON logs -->
        <appender-ref ref="logstash"/>
        <appender-ref ref="flatfile"/>
    </root>
</configuration>

具體程式碼可以參考我的github:

https://github.com/yinjihuan/spring-cloud

相關文章