Spring Boot 3 的可觀測性

工程 | Marcin Grzejszczak | 2022 年 10 月 12 日 | ...

Spring 可觀測性團隊長期以來一直致力於為 Spring 應用程式新增可觀測性支援,我們很高興地通知您,此功能將在 Spring Framework 6 和 Spring Boot 3 中正式推出!

什麼是可觀測性?在我們的理解中,它是「透過檢查系統的輸出,來了解系統內部運作狀況的程度」。我們認為,指標、日誌和分散式追蹤之間的互連,讓您能夠推斷系統的狀態,以便除錯應用程式中的例外狀況和延遲。您可以在 Jonatan Ivanov 在 Enlightning 節目中的這一集中,觀看更多關於我們對可觀測性的看法。

即將發佈的 Spring Boot 3.0.0-RC1 版本將包含眾多自動組態,以使用 Micrometer 改善指標,並使用 Micrometer Tracing(前身為 Spring Cloud Sleuth)新增分散式追蹤支援。最值得注意的變更包括:它將包含對日誌關聯的內建支援,W3C 內容傳播將成為預設的傳播類型,我們將支援自動傳播中繼資料,以供追蹤基礎架構使用(稱為「遠端行李」),這有助於標記觀測。

在今年期間,我們對 Micrometer API 進行了大量變更。最重要的變更是我們引入了一個新的 API:Observation API。

其創立的想法是,我們希望使用者使用單一 API 對其程式碼進行一次檢測,並從中獲得多重好處(例如,指標、追蹤、日誌)。

這篇部落格文章詳細說明了您需要了解的關於該 API 的資訊,以及如何使用它來提供更多關於您的應用程式的洞察。

Micrometer Observation 如何運作?

為了讓任何觀測發生,您需要透過 ObservationRegistry 註冊 ObservationHandler 物件。ObservationHandler 僅對 Observation.Context 的支援實作做出反應,並且可以透過對觀測的生命週期事件做出反應來建立計時器、跨度 (span) 和日誌,例如

  • start - 觀測已開始。當呼叫 Observation#start() 方法時發生。

  • stop - 觀測已停止。當呼叫 Observation#stop() 方法時發生。

  • error - 觀測時發生錯誤。當呼叫 Observation#error(exception) 方法時發生。

  • event - 觀測時發生事件。當呼叫 Observation#event(event) 方法時發生。

  • scope started - 觀測開啟範圍 (scope)。不再使用時必須關閉範圍。處理器可以在啟動時建立執行緒區域變數,這些變數會在關閉範圍時清除。當呼叫 Observation#openScope() 方法時發生。

  • scope stopped - 觀測停止範圍。當呼叫 Observation.Scope#close() 方法時發生。

每當呼叫這些方法中的任何一個時,就會呼叫 ObservationHandler 方法(例如 onStart(T extends Observation.Context ctx)onStop(T extends Observation.Context ctx) 等)。為了在處理器方法之間傳遞狀態,您可以使用 Observation.Context

觀測狀態圖如下

        Observation           Observation
        Context               Context
Created ----------> Started ----------> Stopped

觀測 Scope 狀態圖如下

              Observation
              Context
Scope Started ----------> Scope Closed

為了能夠除錯生產問題,觀測需要額外的中繼資料,例如鍵值對(也稱為標籤)。然後,您可以使用這些標籤查詢您的指標或分散式追蹤後端,以找到所需的資料。標籤可以是高基數或低基數。

這是 Micrometer Observation API 的範例。

// Create an ObservationRegistry
ObservationRegistry registry = ObservationRegistry.create();
// Register an ObservationHandler
registry.observationConfig().observationHandler(new MyHandler());

// Create an Observation and observe your code!
Observation.createNotStarted("user.name", registry)
        .contextualName("getting-user-name")
        .lowCardinalityKeyValue("userType", "userType1") // let's assume that you can have 3 user types
        .highCardinalityKeyValue("userId", "1234") // let's assume that this is an arbitrary number
        .observe(() -> log.info("Hello")); // this is a shortcut for starting an observation, opening a scope, running user's code, closing the scope and stopping the observation

重要

高基數表示鍵值對將具有無限數量的可能值。HTTP URL 就是這樣一個鍵值的好例子(例如,/user/user1234/user/user2345 等)。低基數表示鍵值將具有有限數量的可能值。範本化 HTTP URL(例如 /user/{userId})就是這樣一個鍵值的好例子。

為了將觀測生命週期操作與觀測組態(例如名稱以及低基數和高基數標籤)分開,您可以使用 ObservationConvention,它提供了一種輕鬆覆寫預設命名慣例的方法。

建置您的第一個可觀測應用程式

開始使用的最簡單方法是從 https://start.spring.io 建立一個新專案。請務必選取 Spring Boot 3.0.0-SNAPSHOT(一旦 可用,您可以切換到 RC1)以及您最愛的建置工具。

我們將建置一個 Spring WebMvc 伺服器應用程式和一個用戶端,以使用 RestTemplate 呼叫伺服器。我們先從伺服器端開始。

WebMvc 伺服器設定

由於我們要啟動 HTTP 伺服器,我們必須選擇 org.springframework.boot:spring-boot-starter-web 相依性。

為了使用 @Observed 切面建立觀測,我們需要新增 org.springframework.boot:spring-boot-starter-aop 相依性。

為了將觀測功能新增到您的應用程式,請選擇 spring-boot-starter-actuator(以將 Micrometer 新增到類別路徑)。

現在是時候新增與可觀測性相關的功能了!

  • 指標

    • 對於使用 Prometheus 的 Micrometer 指標,我們需要新增 io.micrometer:micrometer-registry-prometheus 相依性。
  • 追蹤

    • 對於使用 Micrometer Tracing 的追蹤內容傳播,我們需要選擇一個追蹤器橋接器(追蹤器是用於處理跨度生命週期的程式庫)。我們選擇 Zipkin Brave,方法是新增 io.micrometer:micrometer-tracing-bridge-brave

      • 我們將為此示範建立的用戶端應用程式將使用另一個追蹤器程式庫,以展示追蹤器之間的互通性。
    • 對於延遲視覺化,我們需要以某種格式將已完成的跨度傳送到伺服器。在我們的案例中,我們產生一個符合 Zipkin 標準的跨度。為了實現這一點,我們需要新增 io.zipkin.reporter2:zipkin-reporter-brave 相依性。

  • 日誌

    • 由於我們的類別路徑上有 Micrometer Tracing,因此日誌會自動關聯(也就是說,它們包含唯一的追蹤識別碼)。現在我們需要傳送日誌。對於此示範,我們將它們傳送到 Grafana Loki。我們可以透過新增 com.github.loki4j:loki-logback-appender 相依性來實現這一點(查看 此連結 以取得最新發佈版本)

重要

如果您是追蹤的新手,我們需要快速定義幾個基本術語。您可以將任何操作包裝在 span 中。它具有唯一的 span id,並包含時間資訊和一些額外的中繼資料(鍵值對)。由於您可以從跨度產生子跨度,因此整個跨度樹會形成一個 trace,該 trace 共享相同的 trace id(即關聯識別碼)。

現在我們需要新增一些組態。我們設定 actuatormetrics 來發佈百分位數直方圖,並且我們重新定義日誌記錄模式以包含追蹤和跨度識別碼。我們將採樣機率設定為 1.0,以將所有追蹤傳送到延遲分析工具。

/src/main/resources/application.properties

server.port=7654
spring.application.name=server

# All traces should be sent to latency analysis tool
management.tracing.sampling.probability=1.0
management.endpoints.web.exposure.include=prometheus

# For Exemplars to work we need histogram buckets
management.metrics.distribution.percentiles-histogram.http.server.requests=true

# traceID and spanId are predefined MDC keys - we want the logs to include them
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]

由於我們正在本機執行具有 LokiTempoGrafana 堆疊,因此我們將 loki-logback-appender 組態為將日誌傳送到 Loki 的本機執行個體。

/src/main/resources/logback-spring.xml

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

    <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
        <http>
            <url>https://127.0.0.1:3100/loki/api/v1/push</url>
        </http>
        <format>
            <label>
                <pattern>app=${appName},host=${HOSTNAME},traceID=%X{traceId:-NONE},level=%level</pattern>
            </label>
            <message>
                <pattern>${FILE_LOG_PATTERN}</pattern>
            </message>
            <sortByTime>true</sortByTime>
        </format>
    </appender>

    <root level="INFO">
        <appender-ref ref="LOKI"/>
    </root>
</configuration>

WebMvc 伺服器程式碼

是時候編寫一些伺服器端程式碼了!我們希望實現應用程式的完整可觀測性,包括指標、追蹤和額外的日誌記錄。

首先,我們編寫一個控制器,將訊息記錄到主控台,並將工作委派給服務。

MyController.java

@RestController
class MyController {

    private static final Logger log = LoggerFactory.getLogger(MyController.class);
    private final MyUserService myUserService;

    MyController(MyUserService myUserService) {
        this.myUserService = myUserService;
    }

    @GetMapping("/user/{userId}")
    String userName(@PathVariable("userId") String userId) {
        log.info("Got a request");
        return myUserService.userName(userId);
    }
}

我們希望對 MyUserService#userName 方法進行一些詳細的觀測。由於新增了 AOP 支援,我們可以使用 @Observed 註解。若要執行此操作,我們可以註冊 ObservedAspect bean。

MyConfiguration.java

@Configuration(proxyBeanMethods = false)
class MyConfiguration {
    // To have the @Observed support we need to register this aspect
    @Bean
    ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
        return new ObservedAspect(observationRegistry);
    }
}

MyUserService.java

@Service
class MyUserService {

    private static final Logger log = LoggerFactory.getLogger(MyUserService.class);

    private final Random random = new Random();

    // Example of using an annotation to observe methods
    // <user.name> will be used as a metric name
    // <getting-user-name> will be used as a span  name
    // <userType=userType2> will be set as a tag for both metric & span
    @Observed(name = "user.name",
            contextualName = "getting-user-name",
            lowCardinalityKeyValues = {"userType", "userType2"})
    String userName(String userId) {
        log.info("Getting user name for user with id <{}>", userId);
        try {
            Thread.sleep(random.nextLong(200L)); // simulates latency
        }
        catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "foo";
    }
}

在類別路徑上具有指標和追蹤的情況下,使用此註解會導致建立 timerlong task timerspan。計時器將命名為 user.name,長任務計時器將命名為 user.name.active,而跨度將命名為 getting-user-name

日誌呢?我們不希望在每次進行觀測時都手動編寫日誌記錄陳述式。我們可以做的是建立一個專用的處理器,該處理器會為每個觀測記錄一些文字。

MyHandler.java

// Example of plugging in a custom handler that in this case will print a statement before and after all observations take place
@Component
class MyHandler implements ObservationHandler<Observation.Context> {

    private static final Logger log = LoggerFactory.getLogger(MyHandler.class);

    @Override
    public void onStart(Observation.Context context) {
        log.info("Before running the observation for context [{}], userType [{}]", context.getName(), getUserTypeFromContext(context));
    }

    @Override
    public void onStop(Observation.Context context) {
        log.info("After running the observation for context [{}], userType [{}]", context.getName(), getUserTypeFromContext(context));
    }

    @Override
    public boolean supportsContext(Observation.Context context) {
        return true;
    }

    private String getUserTypeFromContext(Observation.Context context) {
        return StreamSupport.stream(context.getLowCardinalityKeyValues().spliterator(), false)
                .filter(keyValue -> "userType".equals(keyValue.getKey()))
                .map(KeyValue::getValue)
                .findFirst()
                .orElse("UNKNOWN");
    }
}

就是這樣!是時候進行用戶端了。

RestTemplate 用戶端應用程式設定

和之前一樣,我們新增 spring-boot-starter-webspring-boot-starter-actuator 相依性,以執行 Web 伺服器並新增 Micrometer 支援。

是時候新增與可觀測性相關的功能了!

  • 指標

    • 對於使用 Prometheus 的 Micrometer 指標,我們需要新增 io.micrometer:micrometer-registry-prometheus 相依性。
  • 追蹤

    • 對於使用 Micrometer Tracing 的追蹤內容傳播,我們需要選擇一個追蹤器橋接器。我們選擇 OpenTelemetry,方法是新增 io.micrometer:micrometer-tracing-bridge-otel

    • 對於延遲視覺化,我們需要以某種格式將已完成的跨度傳送到伺服器。在我們的案例中,我們產生一個符合 OpenZipkin 標準的跨度。為了實現這一點,我們需要新增 io.opentelemetry:opentelemetry-exporter-zipkin 相依性。

  • 日誌

    • 和先前一樣,我們新增 com.github.loki4j:loki-logback-appender 相依性(查看 此連結 以取得最新發佈版本)以將日誌傳送到 Loki。

現在我們需要新增一些組態。我們新增幾乎與伺服器端相同的組態。

/src/main/resources/application.properties

server.port=6543
spring.application.name=client

# All traces should be sent to latency analysis tool
management.tracing.sampling.probability=1.0
management.endpoints.web.exposure.include=prometheus

# traceID and spanId are predefined MDC keys - we want the logs to include them
logging.pattern.level=%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]

Loki Appender 組態看起來完全相同。

/src/main/resources/logback-spring.xml

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

    <appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
        <http>
            <url>https://127.0.0.1:3100/loki/api/v1/push</url>
        </http>
        <format>
            <label>
                <pattern>app=${appName},host=${HOSTNAME},traceID=%X{traceId:-NONE},level=%level</pattern>
            </label>
            <message>
                <pattern>${FILE_LOG_PATTERN}</pattern>
            </message>
            <sortByTime>true</sortByTime>
        </format>
    </appender>

    <root level="INFO">
        <appender-ref ref="LOKI"/>
    </root>
</configuration>

RestTemplate 應用程式用戶端程式碼

現在是時候編寫一些用戶端程式碼了!我們使用 RestTemplate 向伺服器端傳送請求,並且我們希望實現應用程式的完整可觀測性,包括指標和追蹤。

首先,我們需要一個由 Spring Boot 自動檢測的 RestTemplate bean。請記住注入 RestTemplateBuilder 並從建構器建構 RestTemplate 執行個體。

MyConfiguration.java

@Configuration(proxyBeanMethods = false)
class MyConfiguration {
    // IMPORTANT! To instrument RestTemplate you must inject the RestTemplateBuilder
    @Bean
    RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

現在我們可以編寫一個使用 Observation API 包裝的 CommandLineRunner bean,並將請求傳送到伺服器端。API 的所有部分都在以下程式碼片段中更詳細地說明。

MyConfiguration.java

@Configuration(proxyBeanMethods = false)
class MyConfiguration {
    @Bean
    CommandLineRunner myCommandLineRunner(ObservationRegistry registry, RestTemplate restTemplate) {
        Random highCardinalityValues = new Random(); // Simulates potentially large number of values
        List<String> lowCardinalityValues = Arrays.asList("userType1", "userType2", "userType3"); // Simulates low number of values
        return args -> {
            String highCardinalityUserId = String.valueOf(highCardinalityValues.nextLong(100_000));
            // Example of using the Observability API manually
            // <my.observation> is a "technical" name that does not depend on the context. It will be used to name e.g. Metrics
             Observation.createNotStarted("my.observation", registry)
                     // Low cardinality means that the number of potential values won't be big. Low cardinality entries will end up in e.g. Metrics
                    .lowCardinalityKeyValue("userType", randomUserTypePicker(lowCardinalityValues))
                     // High cardinality means that the number of potential values can be large. High cardinality entries will end up in e.g. Spans
                    .highCardinalityKeyValue("userId", highCardinalityUserId)
                     // <command-line-runner> is a "contextual" name that gives more details within the provided context. It will be used to name e.g. Spans
                    .contextualName("command-line-runner")
                     // The following lambda will be executed with an observation scope (e.g. all the MDC entries will be populated with tracing information). Also the observation will be started, stopped and if an error occurred it will be recorded on the observation
                    .observe(() -> {
                        log.info("Will send a request to the server"); // Since we're in an observation scope - this log line will contain tracing MDC entries ...
                        String response = restTemplate.getForObject("https://127.0.0.1:7654/user/{userId}", String.class, highCardinalityUserId); // Boot's RestTemplate instrumentation creates a child span here
                        log.info("Got response [{}]", response); // ... so will this line
                    });

        };
    }
}

將它們全部一起執行

我們在 此連結 下準備了整個可觀測性基礎架構的 Docker 設定。請按照以下步驟執行基礎架構和兩個應用程式。

執行範例

若要執行範例

  1. 啟動可觀測性堆疊(為了示範目的,您可以使用提供的 Grafana、Tempo 和 Loki 堆疊),並等待它啟動。

    $ docker compose up
    
  2. 執行伺服器端應用程式(這將封鎖您目前的終端機視窗)。

    $ ./mvnw spring-boot:run -pl :server
    
  3. 執行用戶端應用程式(這將封鎖您目前的終端機視窗)

    $ ./mvnw spring-boot:run -pl :client
    

    您應該會看到類似於以下的日誌陳述式

    2022-10-04T15:04:55.345+02:00  INFO [client,bbe3aea006077640b66d40f3e62f04b9,93b7a150b7e293ef] 92556 --- [           main] com.example.client.ClientApplication     : Will send a request to the server
    2022-10-04T15:04:55.385+02:00  INFO [client,bbe3aea006077640b66d40f3e62f04b9,93b7a150b7e293ef] 92556 --- [           main] com.example.client.ClientApplication     : Got response [foo]
    
  4. 前往 Grafana,前往儀表板,然後按一下 Logs, Traces, Metrics 儀表板。在那裡,您可以選擇追蹤 ID 值(例如,bbe3aea006077640b66d40f3e62f04b9)以尋找來自兩個應用程式的所有日誌和追蹤,這些日誌和追蹤對應於該追蹤 ID。您應該會看到以下與相同追蹤識別碼相關的日誌和追蹤的關聯檢視,並且您將看到在同一時間範圍內發生的指標。這些指標與 HTTP 請求處理延遲相關。這些來自使用 Micrometer API 的自動 Spring Boot WebMvc 檢測。

    logs metrics traces

    請注意指標中的菱形形狀。這些是 Exemplars。這些是「在給定時間間隔內進行的測量的特定追蹤代表」。如果您按一下該形狀,您可以跳到追蹤 ID 檢視以查看對應的追蹤。

    exemplar

  5. 按一下追蹤 ID 以 Query it with Tempo,或前往 Tempo 並自行選擇追蹤識別碼。您將看到以下畫面。

trace view

每個長條代表一個 span。您可以看到每個操作完成需要多少時間。如果您按一下給定的跨度,您可以看到與該特定操作相關的標籤(鍵值中繼資料)和時間資訊。

span tags

這是關聯日誌檢視在 Loki 中的外觀。

correlated logs

如果您想查看 @Observed 註解方法的指標,您可以前往 Prometheus 檢視並尋找 user_name 計時器。

annotation metric

如果您想查看來自您手動建立的 Observation 的指標,請前往 Prometheus 檢視並尋找 my_observation 計時器。

my observation

使用 AOT 支援將它們全部一起執行

為了更好地了解 Spring Boot 如何支援 Native,請閱讀 這篇出色的部落格文章。我們重複使用該知識,以使用 Spring Native 執行先前建立的應用程式。

建置

若要建置應用程式,您需要在您的路徑上安裝 GraalVM。如果您使用 SDKMan,請調用以下命令

sdk install java 22.3.r17.ea-nik

另請參閱 GraalVM 快速入門

若要使用 Maven 建置應用程式,您需要啟用 native 設定檔

$ ./mvnw native:compile -Pnative

執行

先執行伺服器端應用程式

$ ./server/target/server

接下來,執行用戶端應用程式。

$ ./client/target/client

您應該會得到類似於以下的輸出

用戶端日誌

2022-10-10T12:57:17.712+02:00  INFO \[client,,\] 82009 --- \[           main\] com.example.client.ClientApplication     : Starting ClientApplication using Java 17.0.4 on marcin-precision5560 with PID 82009 (/home/marcin/repo/observability/blogs/bootRc1/client/target/client started by marcin in /home/marcin/repo/observability/blogs/bootRc1)
2022-10-10T12:57:17.712+02:00  INFO \[client,,\] 82009 --- \[           main\] com.example.client.ClientApplication     : No active profile set, falling back to 1 default profile: "default"
2022-10-10T12:57:17.723+02:00  INFO \[client,,\] 82009 --- \[           main\] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 6543 (http)
2022-10-10T12:57:17.723+02:00  INFO \[client,,\] 82009 --- \[           main\] o.apache.catalina.core.StandardService   : Starting service \[Tomcat\]
2022-10-10T12:57:17.723+02:00  INFO \[client,,\] 82009 --- \[           main\] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: \[Apache Tomcat/10.0.23\]
2022-10-10T12:57:17.727+02:00  INFO \[client,,\] 82009 --- \[           main\] o.a.c.c.C.\[Tomcat\].\[localhost\].\[/\]       : Initializing Spring embedded WebApplicationContext
2022-10-10T12:57:17.727+02:00  INFO \[client,,\] 82009 --- \[           main\] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 15 ms
2022-10-10T12:57:17.731+02:00  WARN \[client,,\] 82009 --- \[           main\] i.m.c.i.binder.jvm.JvmGcMetrics          : GC notifications will not be available because MemoryPoolMXBeans are not provided by the JVM
2022-10-10T12:57:17.781+02:00  INFO \[client,,\] 82009 --- \[           main\] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 15 endpoint(s) beneath base path '/actuator'
2022-10-10T12:57:17.783+02:00  INFO \[client,,\] 82009 --- \[           main\] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 6543 (http) with context path ''
2022-10-10T12:57:17.783+02:00  INFO \[client,,\] 82009 --- \[           main\] com.example.client.ClientApplication     : Started ClientApplication in 0.077 seconds (process running for 0.079)
2022-10-10T12:57:17.784+02:00  INFO \[client,27c1113e4276c4173daec3675f536bf4,e0f2db8b983607d8\] 82009 --- \[           main\] com.example.client.ClientApplication     : Will send a request to the server
2022-10-10T12:57:17.820+02:00  INFO \[client,27c1113e4276c4173daec3675f536bf4,e0f2db8b983607d8\] 82009 --- \[           main\] com.example.client.ClientApplication     : Got response \[foo\]
2022-10-10T12:57:18.966+02:00  INFO \[client,,\] 82009 --- \[nio-6543-exec-1\] o.a.c.c.C.\[Tomcat\].\[localhost\].\[/\]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-10-10T12:57:18.966+02:00  INFO \[client,,\] 82009 --- \[nio-6543-exec-1\] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-10-10T12:57:18.966+02:00  INFO \[client,,\] 82009 --- \[nio-6543-exec-1\] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms

伺服器端日誌

2022-10-10T12:57:07.200+02:00  INFO \[server,,\] 81760 --- \[           main\] com.example.server.ServerApplication     : Starting ServerApplication using Java 17.0.4 on marcin-precision5560 with PID 81760 (/home/marcin/repo/observability/blogs/bootRc1/server/target/server started by marcin in /home/marcin/repo/observability/blogs/bootRc1)
2022-10-10T12:57:07.201+02:00  INFO \[server,,\] 81760 --- \[           main\] com.example.server.ServerApplication     : No active profile set, falling back to 1 default profile: "default"
2022-10-10T12:57:07.213+02:00  INFO \[server,,\] 81760 --- \[           main\] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 7654 (http)
2022-10-10T12:57:07.213+02:00  INFO \[server,,\] 81760 --- \[           main\] o.apache.catalina.core.StandardService   : Starting service \[Tomcat\]
2022-10-10T12:57:07.213+02:00  INFO \[server,,\] 81760 --- \[           main\] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: \[Apache Tomcat/10.0.23\]
2022-10-10T12:57:07.217+02:00  INFO \[server,,\] 81760 --- \[           main\] o.a.c.c.C.\[Tomcat\].\[localhost\].\[/\]       : Initializing Spring embedded WebApplicationContext
2022-10-10T12:57:07.217+02:00  INFO \[server,,\] 81760 --- \[           main\] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 16 ms
2022-10-10T12:57:07.222+02:00  WARN \[server,,\] 81760 --- \[           main\] i.m.c.i.binder.jvm.JvmGcMetrics          : GC notifications will not be available because MemoryPoolMXBeans are not provided by the JVM
2022-10-10T12:57:07.278+02:00  INFO \[server,,\] 81760 --- \[           main\] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 15 endpoint(s) beneath base path '/actuator'
2022-10-10T12:57:07.280+02:00  INFO \[server,,\] 81760 --- \[           main\] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 7654 (http) with context path ''
2022-10-10T12:57:07.281+02:00  INFO \[server,,\] 81760 --- \[           main\] com.example.server.ServerApplication     : Started ServerApplication in 0.086 seconds (process running for 0.088)
2022-10-10T12:57:07.639+02:00  INFO \[server,,\] 81760 --- \[nio-7654-exec-1\] o.a.c.c.C.\[Tomcat\].\[localhost\].\[/\]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-10-10T12:57:07.639+02:00  INFO \[server,,\] 81760 --- \[nio-7654-exec-1\] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-10-10T12:57:07.640+02:00  INFO \[server,,\] 81760 --- \[nio-7654-exec-1\] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms
2022-10-10T12:57:17.785+02:00  INFO \[server,,\] 81760 --- \[nio-7654-exec-8\] com.example.server.MyHandler             : Before running the observation for context \[http.server.requests\]
2022-10-10T12:57:17.785+02:00  INFO \[server,27c1113e4276c4173daec3675f536bf4,9affba5698490e2d\] 81760 --- \[nio-7654-exec-8\] com.example.server.MyController          : Got a request
2022-10-10T12:57:17.820+02:00  INFO \[server,,\] 81760 --- \[nio-7654-exec-8\] com.example.server.MyHandler             : After running the observation for context \[http.server.requests\]

您可以檢查 Grafana 以取得指標、追蹤和日誌!

Native 支援限制

在用戶端,我們需要手動提供 reflect-config.js 組態。如需更多資訊,請參閱 此 PR

摘要

在這篇部落格文章中,我們成功地向您介紹了 Micrometer Observability API 背後的主要概念。我們也向您展示了如何使用 Observation API 和註解來建立觀測。您還可以視覺化延遲、查看關聯的日誌,並檢查來自您的 Spring Boot 應用程式的指標。

您也可以使用具有 Spring Native 的原生映像來觀測您的應用程式。

致謝

如果沒有整個 Spring 團隊、Tadaya TsuyukuboJohnny Lim 以及所有其他貢獻者和審閱者的廣泛支援,Micrometer Observability 的工作將不可能實現。

後續步驟

根據社群回饋,我們將繼續改進我們的 Observability 故事。我們打算在 今年 11 月發佈 GA 版本

對於我們來說,這是一個令人興奮的時刻。我們再次感謝所有已貢獻和報告回饋的每個人,並且我們期待進一步的回饋!查看 Spring Boot 的最新快照!查看我們專案的文件:Micrometer Context PropagationMicrometerMicrometer ObservationMicrometer TracingMicrometer Docs Generator!按一下這裡查看用於此部落格文章的程式碼。

取得 Spring 電子報

隨時掌握 Spring 電子報的最新資訊

訂閱

領先一步

VMware 提供培訓和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

查看全部