1. 程式人生 > 其它 >Spring Cloud構建微服務架構:分散式服務跟蹤(整合logstash)【Dalston版】

Spring Cloud構建微服務架構:分散式服務跟蹤(整合logstash)【Dalston版】

通過之前的《入門示例》,我們已經為兩個由SpringCloud構建的微服務專案 trace-1trace-2引入了Spring Cloud Sleuth的基礎模組 spring-cloud-starter-sleuth,實現了為各微服務的日誌資訊中新增跟蹤資訊的功能。但是,由於日誌檔案都離散的儲存在各個服務例項的檔案系統之上,僅僅通過檢視日誌檔案來分析我們的請求鏈路依然是一件相當麻煩的差事,所以我們還需要一些工具來幫助我們集中的收集、儲存和搜尋這些跟蹤資訊。引入基於日誌的分析系統是一個不錯的選擇,比如:ELK平臺,它可以輕鬆的幫助我們來收集和儲存這些跟蹤日誌,同時在需要的時候我們也可以根據Trace ID來輕鬆地搜尋出對應請求鏈路相關的明細日誌。

ELK平臺主要有由ElasticSearch、Logstash和Kiabana三個開源免費工具組成:

  • Elasticsearch是個開源分散式搜尋引擎,它的特點有:分散式,零配置,自動發現,索引自動分片,索引副本機制,restful風格介面,多資料來源,自動搜尋負載等。
  • Logstash是一個完全開源的工具,他可以對你的日誌進行收集、過濾,並將其儲存供以後使用。
  • Kibana 也是一個開源和免費的工具,它Kibana可以為 Logstash 和 ElasticSearch 提供的日誌分析友好的 Web 介面,可以幫助您彙總、分析和搜尋重要資料日誌。

Spring Cloud Sleuth在與ELK平臺整合使用時,實際上我們只要實現與負責日誌收集的Logstash完成資料對接即可,所以我們需要為Logstash準備json格式的日誌輸出。由於Spring Boot應用預設使用了logback來記錄日誌,而Logstash自身也有對logback日誌工具的支援工具,所以我們可以直接通過在logback的配置中增加對logstash的appender,就能非常方便的將日誌轉換成以json的格式儲存和輸出了。

下面我們來詳細介紹一下在快速入門示例的基礎上,如何實現面向Logstash的日誌輸出配置:

  • pom.xml依賴中引入 logstash-logback-encoder依賴,具體如下:
<dependency>
  <groupId>net.logstash.logback</groupId>
  <artifactId>logstash-logback-encoder</artifactId>
  <version>4.6</version>
</dependency>
  • 在工程 /resource
    目錄下建立 bootstrap.properties配置檔案,將 spring.application.name=trace-1配置移動到該檔案中去。由於 logback-spring.xml的載入在 application.properties之前,所以之前的配置 logback-spring.xml無法獲取到 spring.application.name屬性,因此這裡將該屬性移動到最先載入的 bootstrap.properties配置檔案中。
  • 在工程 /resource目錄下建立logback配置檔案 logback-spring.xml,具體內容如下:
<?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"/>
    <!-- 日誌在工程中的輸出位置 -->
    <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/>
    <!-- 控制檯的日誌輸出樣式 -->
    <property name="CONSOLE_LOG_PATTERN"
              value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([${springAppName:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]){yellow} %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>

    <!-- 控制檯Appender -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">           
            <level>INFO</level>
        </filter>
         <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
       </encoder>
    </appender>

    <!-- 為logstash輸出的json格式的Appender -->
    <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:-}",
                          "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"/>
        <appender-ref ref="logstash"/>
    </root>
</configuration>

對logstash支援主要通過名為 logstash的appender實現,內容並不複雜,主要是對日誌資訊的格式化處理,上面為了方便除錯檢視我們先將json日誌輸出到檔案中。

完成上面的改造之後,我們再將快速入門的示例執行起來,併發起對 trace-1的介面訪問。此時我們可以在 trace-1trace-2的工程目錄下發現有一個 build目錄,下面分別建立了以各自應用名稱命名的json檔案,該檔案就是在 logback-spring.xml中配置的名為 logstash的appender輸出的日誌檔案,其中記錄了類似下面格式的json日誌:

{"@timestamp":"2016-12-04T06:57:58.970+00:00","severity":"INFO","service":"trace-1","trace":"589ee5f7b860132f","span":"a9e891273affb7fc","exportable":"false","pid":"19756","thread":"http-nio-9101-exec-1","class":"c.d.TraceApplication$$EnhancerBySpringCGLIB$$a9604da6","rest":"===<call trace-1>==="}
{"@timestamp":"2016-12-04T06:57:59.061+00:00","severity":"INFO","service":"trace-1","trace":"589ee5f7b860132f","span":"2df8511ddf3d79a2","exportable":"false","pid":"19756","thread":"http-nio-9101-exec-1","class":"o.s.c.a.AnnotationConfigApplicationContext","rest":"Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@64951f38: startup date [Sun Dec 04 14:57:59 CST 2016]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4b8c8f15"}

我們除了可以通過上面的方式生成json檔案之外,也可以使用 LogstashTcpSocketAppender將日誌內容直接通過Tcp Socket輸出到logstash服務端,比如:

<appender name="logstash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
  <destination>127.0.0.1:9250</destination>
  ...
</appender>

完整示例:

讀者可以根據喜好選擇下面的兩個倉庫中檢視 trace-1trace-2兩個專案:

  • Github:https://github.com/dyc87112/SpringCloud-Learning/
  • Gitee:https://gitee.com/didispace/SpringCloud-Learning/