領先一步
VMware 提供培訓和認證,助您快速進步。
瞭解更多Spring 可觀測性團隊致力於為 Spring 應用新增可觀測性支援已有一段時間,我們很高興地通知您,此功能將在 Spring Framework 6 和 Spring Boot 3 中正式釋出!
什麼是可觀測性?在我們看來,它是 “透過檢查系統的輸出來瞭解其內部執行狀況的能力”。我們認為,將指標、日誌和分散式追蹤結合起來,您就能更好地理解系統狀態,從而除錯應用程式中的異常和延遲問題。您可以在 Jonatan Ivanov 的 Enlightning 節目中 瞭解更多關於我們對可觀測性的看法。
即將釋出的 Spring Boot 3.0.0-RC1
版本將包含許多自動配置,以改進與 Micrometer 的指標功能,並新增與 Micrometer Tracing(前身為 Spring Cloud Sleuth)的分散式追蹤支援。最顯著的變化包括內建的日誌關聯支援,W3C context propagation 將成為預設的傳播型別,並且我們將支援元資料的自動傳播,供追蹤基礎設施使用(稱為“遠端行李”),這有助於標記觀測結果。
今年以來,我們對 Micrometer API 進行了大量更改。最重要的變化是引入了一個新的 API:Observation API。
其創立理念是希望使用者只需使用一個 API 對程式碼進行一次插樁,即可從中獲得多種好處(例如,指標、追蹤、日誌記錄)。
這篇博文詳細介紹了您需要了解的關於該 API 的知識,以及如何使用它來為您的應用程式提供更多洞察力。
要進行任何觀測,您需要透過 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
- 觀測停止一個範圍(scope)。在呼叫 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 可用後 您可以切換到 RC1)以及您喜歡的構建工具。
我們將構建一個 Spring WebMvc 伺服器應用程式和一個使用 RestTemplate 呼叫伺服器的客戶端。我們從伺服器端開始。
由於我們要啟動一個 HTTP 伺服器,因此必須選擇 org.springframework.boot:spring-boot-starter-web
依賴項。
要使用 @Observed
切面建立觀測,我們需要新增 org.springframework.boot:spring-boot-starter-aop
依賴項。
要為您的應用程式新增觀測功能,請選擇 spring-boot-starter-actuator
(將 Micrometer 新增到類路徑中)。
現在是時候新增與可觀測性相關的功能了!
指標
io.micrometer:micrometer-registry-prometheus
依賴項。追蹤
對於使用 Micrometer Tracing 的 追蹤上下文傳播,我們需要選擇一個 tracer 橋接器(tracer 是一個用於處理 Span 生命週期)的庫。我們透過新增 io.micrometer:micrometer-tracing-bridge-brave
來選擇 Zipkin Brave。
對於 延遲視覺化,我們需要以某種格式將完成的 Span 傳送到伺服器。在本例中,我們生成一個 Zipkin 相容的 Span。為此,我們需要新增 io.zipkin.reporter2:zipkin-reporter-brave
依賴項。
日誌
com.github.loki4j:loki-logback-appender
依賴項即可實現此目的(請參閱 此連結 獲取最新發布版本)重要提示
如果您是追蹤新手,我們需要快速定義幾個基本術語。您可以將任何操作包裝在 span
中。它有一個唯一的 span id
,幷包含計時資訊和一些額外的元資料(鍵值對)。由於您可以從 Span 生成子 Span,因此整個 Span 樹構成一個 trace
,共享相同的 trace id
(即關聯識別符號)。
現在我們需要新增一些配置。我們將 actuator
和 metrics
設定為釋出百分位數直方圖,並重新定義日誌模式以包含追蹤和 Span 識別符號。我們將取樣機率設定為 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:-}]
由於我們在本地執行包含 Loki 和 Tempo 的 Grafana 技術棧,我們將 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://: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>
是時候編寫一些伺服器端程式碼了!我們希望實現應用程式的全面可觀測性,包括指標、追蹤和額外的日誌記錄。
首先,我們編寫一個控制器,它將訊息記錄到控制檯並將工作委託給一個服務。
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";
}
}
在類路徑中包含指標和追蹤的情況下,使用此註解會導致建立一個 timer
、一個 long task timer
和一個 span
。該定時器將命名為 user.name
,長時間任務定時器將命名為 user.name.active
,Span 將命名為 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");
}
}
就是這樣!現在輪到客戶端了。
和之前一樣,我們新增 spring-boot-starter-web
和 spring-boot-starter-actuator
依賴項以執行 Web 伺服器並新增 Micrometer 支援。
是時候新增與可觀測性相關的功能了!
指標
io.micrometer:micrometer-registry-prometheus
依賴項。追蹤
對於使用 Micrometer Tracing 的 追蹤上下文傳播,我們需要選擇一個 tracer 橋接器。我們透過新增 io.micrometer:micrometer-tracing-bridge-otel
來選擇 OpenTelemetry。
對於 延遲視覺化,我們需要以某種格式將完成的 Span 傳送到伺服器。在本例中,我們生成一個 OpenZipkin 相容的 Span。為此,我們需要新增 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://: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
向伺服器端傳送請求,並且希望實現應用程式的全面可觀測性,包括指標和追蹤。
首先,我們需要一個由 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://: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 設定。請按照以下步驟執行基礎設施和兩個應用程式。
執行示例的步驟:
啟動可觀測性技術棧(為演示目的,您可以使用提供的 Grafana、Tempo 和 Loki 技術棧),並等待其啟動完成。
$ docker compose up
要訪問 Prometheus,請前往 https://:9090/
要訪問 Grafana,請前往 https://:3000/
執行伺服器端應用程式(這將阻塞您當前的終端視窗)。
$ ./mvnw spring-boot:run -pl :server
執行客戶端應用程式(這將阻塞您當前的終端視窗)
$ ./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]
前往 Grafana,進入儀表盤,然後點選 Logs, Traces, Metrics
儀表盤。在那裡,您可以選擇一個追蹤 ID 值(例如,bbe3aea006077640b66d40f3e62f04b9
),以找到與該追蹤 ID 對應的兩個應用程式的所有日誌和追蹤。您應該會看到與同一追蹤識別符號相關的日誌和追蹤的關聯檢視,並且會看到在同一時間範圍內的指標。這些指標與 HTTP 請求處理延遲相關。它們來自於使用 Micrometer API 的 Spring Boot WebMvc 自動插樁。
請注意指標中的菱形。這些是 Exemplars
。它們是“在給定時間間隔內測量的特定追蹤代表”。如果您點選該形狀,可以跳轉到追蹤 ID 檢視以檢視相應的追蹤。
您可以點選追蹤 ID 使用 Query it with Tempo
查詢,或者前往 Tempo 自己選擇追蹤識別符號。您將看到以下螢幕。
每個條形代表一個 span
。您可以看到每個操作完成花費的時間。如果您點選某個 Span,您可以看到與該特定操作相關的標籤(鍵值元資料)和計時資訊。
這是日誌在 Loki 中的關聯檢視的樣子。
如果您想檢視 @Observed
註解方法的指標,您可以前往 Prometheus
檢視並找到 user_name
定時器。
如果您想檢視您手動建立的 Observation 的指標,請前往 Prometheus
檢視並找到 my_observation
定時器。
為了更好地瞭解 Spring Boot 如何支援 Native,請閱讀 這篇精彩的博文。我們重用這些知識來使用 Spring Native 執行之前建立的應用程式。
要構建應用程式,您的路徑中需要有 GraalVM。如果您使用 SDKMan
,請執行以下命令
sdk install java 22.3.r17.ea-nik
另請參閱 GraalVM 快速入門。
要使用 Maven 構建應用程式,您需要啟用 native
profile
$ ./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 中檢視指標、追蹤和日誌!
在客戶端,我們需要手動提供 reflect-config.js
配置。更多資訊請參閱 此 PR。
在這篇博文中,我們成功地向您介紹了 Micrometer Observability API 背後的主要概念。我們還展示瞭如何使用 Observation API 和註解建立觀測。您還可以視覺化延遲,檢視關聯日誌,並檢查來自您的 Spring Boot 應用程式的指標。
您還可以使用 Spring Native 透過 Native 映象來觀測您的應用程式。
如果沒有整個 Spring 團隊、Tadaya Tsuyukubo、Johnny Lim 以及所有其他貢獻者和評審員的大力支援,Micrometer Observability 的工作是不可能完成的。
根據社群反饋,我們將繼續改進我們的可觀測性方案。我們計劃 今年 11 月正式釋出 (GA)。
這對我們來說是一個令人興奮的時刻。我們再次感謝所有已經做出貢獻並報告反饋的人,並期待收到更多反饋!請檢視 Spring Boot 的最新快照版本!請檢視我們專案的文件:Micrometer Context Propagation、Micrometer、Micrometer Observation、Micrometer Tracing 和 Micrometer Docs Generator!點選 此處 檢視本文使用的程式碼。