領先一步
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 內容傳播將成為預設的傳播類型,我們將支援自動傳播中繼資料,以供追蹤基礎架構使用(稱為「遠端行李」),這有助於標記觀測。
在今年期間,我們對 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
- 觀測停止範圍。當呼叫 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 呼叫伺服器。我們先從伺服器端開始。
由於我們要啟動 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 的追蹤內容傳播,我們需要選擇一個追蹤器橋接器(追蹤器是用於處理跨度生命週期的程式庫)。我們選擇 Zipkin Brave,方法是新增 io.micrometer:micrometer-tracing-bridge-brave
。
對於延遲視覺化,我們需要以某種格式將已完成的跨度傳送到伺服器。在我們的案例中,我們產生一個符合 Zipkin 標準的跨度。為了實現這一點,我們需要新增 io.zipkin.reporter2:zipkin-reporter-brave
相依性。
日誌
com.github.loki4j:loki-logback-appender
相依性來實現這一點(查看 此連結 以取得最新發佈版本)重要
如果您是追蹤的新手,我們需要快速定義幾個基本術語。您可以將任何操作包裝在 span
中。它具有唯一的 span id
,並包含時間資訊和一些額外的中繼資料(鍵值對)。由於您可以從跨度產生子跨度,因此整個跨度樹會形成一個 trace
,該 trace
共享相同的 trace id
(即關聯識別碼)。
現在我們需要新增一些組態。我們設定 actuator
和 metrics
來發佈百分位數直方圖,並且我們重新定義日誌記錄模式以包含追蹤和跨度識別碼。我們將採樣機率設定為 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://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>
是時候編寫一些伺服器端程式碼了!我們希望實現應用程式的完整可觀測性,包括指標、追蹤和額外的日誌記錄。
首先,我們編寫一個控制器,將訊息記錄到主控台,並將工作委派給服務。
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
,而跨度將命名為 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 的追蹤內容傳播,我們需要選擇一個追蹤器橋接器。我們選擇 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
向伺服器端傳送請求,並且我們希望實現應用程式的完整可觀測性,包括指標和追蹤。
首先,我們需要一個由 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 設定。請按照以下步驟執行基礎架構和兩個應用程式。
若要執行範例
啟動可觀測性堆疊(為了示範目的,您可以使用提供的 Grafana、Tempo 和 Loki 堆疊),並等待它啟動。
$ docker compose up
若要存取 Prometheus,請前往 https://127.0.0.1:9090/
若要存取 Grafana,請前往 https://127.0.0.1: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
。您可以看到每個操作完成需要多少時間。如果您按一下給定的跨度,您可以看到與該特定操作相關的標籤(鍵值中繼資料)和時間資訊。
這是關聯日誌檢視在 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
設定檔
$ ./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 的原生映像來觀測您的應用程式。
如果沒有整個 Spring 團隊、Tadaya Tsuyukubo、Johnny Lim 以及所有其他貢獻者和審閱者的廣泛支援,Micrometer Observability 的工作將不可能實現。
根據社群回饋,我們將繼續改進我們的 Observability 故事。我們打算在 今年 11 月發佈 GA 版本。
對於我們來說,這是一個令人興奮的時刻。我們再次感謝所有已貢獻和報告回饋的每個人,並且我們期待進一步的回饋!查看 Spring Boot 的最新快照!查看我們專案的文件:Micrometer Context Propagation、Micrometer、Micrometer Observation、Micrometer Tracing 和 Micrometer Docs Generator!按一下這裡查看用於此部落格文章的程式碼。