<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Spring boot 3.0 可觀測(cè)性增強(qiáng)【譯】

          共 37093字,需瀏覽 75分鐘

           ·

          2022-10-19 11:29

          前言

          Spring 可觀察性團(tuán)隊(duì)一直致力于為 Spring 應(yīng)用程序添加可觀察性支持,該特性將在 Spring Framework 6 和 Spring Boot 3 中更加簡(jiǎn)單、易用! 通過(guò)可觀測(cè)性,能更好的了解系統(tǒng)內(nèi)部運(yùn)行狀態(tài)。metrics, logging 和分布式 tracing 之間的相互連通能更好的推斷系統(tǒng)的運(yùn)行狀態(tài),以便調(diào)試應(yīng)用程序中的異常、延遲和性能。 

          即將發(fā)布的 Spring Boot3.0.0-RC1 將包含大量的自動(dòng)配置,用于使用 Micrometer 改進(jìn) metrics,并通過(guò) Micrometer tracing (以前稱為 Spring Cloud Sleuth)提供新的分布式 tracing 支持。最值得注意的變化是,它將包含對(duì) log 關(guān)聯(lián)的內(nèi)置支持,W3C上下文傳遞將是默認(rèn)傳播類型,我們將支持自動(dòng)傳播元數(shù)據(jù),以供 tracing 基礎(chǔ)設(shè)施(稱為“遠(yuǎn)程包裹”)使用,幫助標(biāo)記觀察結(jié)果。 

          Micrometer API 得到了大量的改進(jìn),最重要的變化是我們引入了一個(gè)新的API:Observation API。

          它創(chuàng)建理念是,希望用戶使用單一 API 就能檢測(cè)代碼,并從中獲得多種信息(例如 metrics, tracing, logging)。

          這篇博文詳細(xì)介紹了你需要了解的API,以及如何使用它來(lái)為你的應(yīng)用程序提供更多可觀測(cè)信息。

          一、Micrometer Observation 怎么運(yùn)行?

          我們需要通過(guò) ObservationRegistry 注冊(cè) ObservationHandler 對(duì)象。ObservationHandler 僅對(duì)支持的 Observation.Context 實(shí)現(xiàn)起作用。Context`and可以通過(guò)對(duì)觀察的生命周期事件作出反應(yīng)來(lái)創(chuàng)建計(jì)時(shí)器、跨度和日志,例如: 觀測(cè)處理程序僅對(duì)受支持的觀測(cè)實(shí)現(xiàn)作出反應(yīng)。上下文,可以通過(guò)對(duì)觀察的生命周期事件作出反應(yīng)來(lái)創(chuàng)建計(jì)時(shí)器、跨度和日志,例如:

          • start - 調(diào)用 Observation#start() 方法啟動(dòng) Observation。
          • stop - 調(diào)用 Observation#stop() 方法停止 Observation。
          • error - 調(diào)用 Observation#error(exception) 方法拋出觀測(cè)。
          • event - 調(diào)用 Observation#event(event) 觀察時(shí)發(fā)生的事。
          • scope started - 調(diào)用 Observation#openScope() 方法時(shí),打開(kāi)了一個(gè) scope。不使用時(shí)必須關(guān)閉??梢栽诖藙?chuàng)建線程局部變量,這些變量在 scope 關(guān)閉時(shí)被清除。
          • scope stopped - 調(diào)用 Observation.Scope#close() 方法時(shí)停止  Observation scope。 每當(dāng)調(diào)用這些方法中的任何一個(gè)時(shí),都會(huì)調(diào)用 ObservationHandler 方法(例如 onStart(T extends Observation.Context ctx)onStop(T extends Observation.Context ctx) 等)。要在處理方法之間傳遞狀態(tài),可以使用Observation.Context。

          Observation 狀態(tài)圖如下:

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

          Observation Scope 狀態(tài)圖如下:

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

          為了調(diào)試生產(chǎn)問(wèn)題,observation 需要額外的元數(shù)據(jù),例如鍵值對(duì)(也稱為 tags)。然后,可以使用這些 tag 來(lái)查找所需的數(shù)據(jù),從而查詢 metrics 或分布式 tracing 后端。tag 可以是高基數(shù)或低基數(shù)。 

          這是 Micrometer Observation API 的一個(gè)示例。

          // 創(chuàng)建 ObservationRegistry
          ObservationRegistry registry = ObservationRegistry.create();
          // 注冊(cè) ObservationHandler
          registry.observationConfig().observationHandler(new MyHandler());

          // 創(chuàng)建 Observation!
          Observation.createNotStarted("user.name", registry)
                  .contextualName("getting-user-name")
                  .lowCardinalityKeyValue("userType""userType1") // 假設(shè)你有3種用戶類型
                  .highCardinalityKeyValue("userId""1234") // 假設(shè)這是一個(gè)任意數(shù)
                  .observe(() -> log.info("Hello")); // 這是啟動(dòng)觀察、打開(kāi)范圍、運(yùn)行用戶代碼、關(guān)閉范圍和停止觀察的快捷方式
          重要說(shuō)明高基數(shù)意味著一對(duì)可能值的數(shù)量是無(wú)限多的。HTTP URL 就是這樣一個(gè)鍵值的好例子(例如 /user/user1234,/user/user2345 等)。低基數(shù)意味著鍵值將具有有限數(shù)量的可能值。模板化的 HTTP URL(例如 /user/{userId})就是這樣一個(gè)鍵值的好例子。

          要將 observation 生命周期操作與 observation 配置(例如名稱以及低基數(shù)和高基數(shù)標(biāo)記)分離,可以使用 ObservationConvention ,它提供了一種覆蓋默認(rèn)命名約定的簡(jiǎn)單方法。

          二、構(gòu)建可觀測(cè)應(yīng)用

          開(kāi)始的最簡(jiǎn)單方法是從 https://start.spring.io。確保選擇的時(shí) Spring Boot 3.0.0-SNAPSHOT (你可以切換到 RC1 如果他已經(jīng)發(fā)布) 和你喜歡的構(gòu)建工具。 我們將構(gòu)建一個(gè) Spring WebMvc 服務(wù)端應(yīng)用程序和一個(gè) RestTemplate 調(diào)用服務(wù)器的客戶端。下面我們從服務(wù)端開(kāi)始。

          2.1 WebMvc 服務(wù)啟動(dòng)

          因?yàn)槲覀兿雴?dòng) HTTP 服務(wù), 需要選擇 org.springframework.boot:spring-boot-starter-web 依賴。 要使用 @Observed 切面創(chuàng)建  observations, 我們需要添加org.springframework.boot:spring-boot-starter-aop 依賴。 要在應(yīng)用中添加可觀測(cè)功能,請(qǐng)選擇 spring-boot-starter-actuator (并將 Micrometer 添加到 classpath).

          • Metrics
            • 對(duì)于 Micrometer metrics 可以使用 Prometheus, 只需要添加io.micrometer:micrometer-registry-prometheus 依賴.
          • Tracing
            • 對(duì)于使用 Micrometer Tracing 跟蹤 Tracing 上下文傳播 , 我們需要選擇一個(gè) tracer 橋接 (tracer 用于處理跨度生命周期的庫(kù)). 我們選擇 Zipkin Brave 然后添加 io.micrometer:micrometer-tracing-bridge-brave依賴。
            • 對(duì)于延遲可視化, 我們需要以某種格式將完成的 spans 發(fā)送到服務(wù)器。在我們的案例中我們生成了一個(gè)符合 Zipkin-compliant 標(biāo)準(zhǔn)的 span。為此,我們需要添加io.zipkin.reporter2:zipkin-reporter-brave 依賴。
          • Logs
            • 因?yàn)槲覀冊(cè)?classpath 添加了 Micrometer Tracing, 所以 logs 也是自動(dòng)關(guān)聯(lián)的 (也就是說(shuō),它們包含一個(gè)惟一的 trace 標(biāo)識(shí)符). 為了這個(gè)演示,我們將日志推送到 Grafana Loki。我們可以通過(guò)添加 com.github.loki4j:loki-logback-appender:latest.release 依賴來(lái)實(shí)現(xiàn)。 | 重要說(shuō)明 | 如果你不熟悉 tracing,我們需要快速定義兩個(gè)基本術(shù)語(yǔ)。你可以在 span 中包裝任何操作。它具有唯一的 span id,并包含計(jì)時(shí)信息和一些附加的元數(shù)據(jù)(鍵-值對(duì))。因?yàn)榭梢詮?span 生成子 span,所以整個(gè) span 樹(shù)形成一個(gè)共享相同 trace id(即關(guān)聯(lián)標(biāo)識(shí)符)的 trace。 

          現(xiàn)在我們需要添加一些配置。我們?cè)O(shè)置actuatormetrics用來(lái)生成百分位直方圖,并重新定義日志模式以包括跟蹤和范圍標(biāo)識(shí)符。我們將采樣概率設(shè)置為1.0,以將所有跟蹤發(fā)送到延遲分析工具。

          # /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:-}]

          因?yàn)槲覀冊(cè)诒镜厥褂?Loki 和 Tempo 運(yùn)行 Grafana,所以我們配置 loki-logback-appender,將日志發(fā)送到 Loki 的本地實(shí)例。

          <!-- /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>http://localhost: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>

          2.2 WebMvc 服務(wù)端代碼

          是時(shí)候編寫(xiě)一些服務(wù)器端代碼了!我們希望實(shí)現(xiàn)應(yīng)用程序的完全可觀察性,包括metrics, tracing 和附加 logging 記錄。 首先,我們編寫(xiě)一個(gè)控制器,打印 log 并調(diào)用 service。

          // 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);
              }
          }

          我們想對(duì) MyUserService#userName 方法進(jìn)行一些詳細(xì)跟蹤觀察。由于添加了AOP支持,我們可以使用@Observed注解。為此,我們可以注冊(cè) 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";
              }
          }

          有了這個(gè)注釋就會(huì)創(chuàng)建一個(gè) timer、一個(gè) long task timer 和一個(gè)span。計(jì)時(shí)器將命名為user.name,長(zhǎng)任務(wù)計(jì)時(shí)器將命名為 user.name.active,而 span 將命名為 getting-user-name。 logs 我們則可以創(chuàng)建一個(gè)專門的處理程序,為每個(gè)觀察記錄一些日志信息。

          // MyHandler.java
          @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");
              }
          }

          注冊(cè)一個(gè) bean 打開(kāi)控制器的可觀察性。

          // MyConfiguration.java
          @Configuration(proxyBeanMethods = false)
          class MyConfiguration {
              // You must set this manually until this is registered in Boot
              @Bean
              FilterRegistrationBean observationWebFilter(ObservationRegistry observationRegistry) {
                  FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new HttpRequestsObservationFilter(observationRegistry));
                  filterRegistrationBean.setDispatcherTypes(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.FORWARD,
                          DispatcherType.INCLUDE, DispatcherType.REQUEST);
                  filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
                  // We provide a list of URLs that we want to create observations for
                  filterRegistrationBean.setUrlPatterns(Collections.singletonList("/user/*"));
                  return filterRegistrationBean;
              }
          }

          2.3 RestTemplate 客戶端啟動(dòng)

          首先我們添加 spring-boot-starter-web 和 spring-boot-starter-actuator 依賴 運(yùn)行web服務(wù)器并添加 Micrometer 支持。 是時(shí)候添加可觀察性相關(guān)功能了!

          • Metrics
            • 對(duì)于 Micrometer metrics 可以使用 Prometheus, 只需要添加 io.micrometer:micrometer-registry-prometheus 依賴。
          • Tracing
            • 對(duì)于使用 Micrometer Tracing 跟蹤 Tracing 上下文傳播,我們需要選擇一個(gè) tracer 橋. 我選擇 OpenTelemetry 并添加 io.micrometer:micrometer-tracing-bridge-otel依賴。
            • 對(duì)于延遲可視化,我們需要以某種格式將完成的 spans 發(fā)送到服務(wù)器。在我們的案例中我們生成了一個(gè)符合 OpenZipkin compliant 標(biāo)準(zhǔn) span, 我們需要添加 io.opentelemetry:opentelemetry-exporter-zipkin 依賴。
          • Logs
            • 添加 com.github.loki4j:loki-logback-appender:latest.release 依賴并將日志發(fā)送到 Loki。 現(xiàn)在我們需要添加一些配置。我們添加了與服務(wù)器端幾乎相同的配置。
          # /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 配置看,起來(lái)完全相同:

          <!-- /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>http://localhost: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>

          2.4 RestTemplate 應(yīng)用代碼

          我們利用 RestTemplate 發(fā)送一個(gè)請(qǐng)求,我們希望實(shí)現(xiàn)應(yīng)用程序的全部可觀測(cè)性,包括 metrics 和 tracing。 首先,我們使用 RestTemplateBuilder 創(chuàng)建一個(gè) RestTemplate bean。

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

          現(xiàn)在,我們可以編寫(xiě)一個(gè) CommandLineRunner bean,它使用 Observation API包裝,并向服務(wù)器端發(fā)送請(qǐng)求。下面的代碼片段更詳細(xì)地描述了 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("http://localhost:7654/user/{userId}", String.classhighCardinalityUserId)// Boot's RestTemplate instrumentation creates a child span here
                                  log.info("Got response [{}]", response); // ... so will this line
                              });

                  };
              }
          }

          限制

          WebMvc Observability 的 Spring Boot AutoConfiguration 尚未完成。因此,我們需要手動(dòng)設(shè)置。有關(guān)詳細(xì)信息,請(qǐng)參閱此 issue。 為了讓 Spring Boot Exemplars AutoConfiguration 正常工作,我們需要等待此 PR 和此 PR 合并。在此之前,我們需要手動(dòng)創(chuàng)建配置。

          2.5 運(yùn)行

          我們已經(jīng)準(zhǔn)備好了這個(gè)鏈接下整個(gè)可觀測(cè)性基礎(chǔ)設(shè)施的Docker設(shè)置。按照以下步驟運(yùn)行基礎(chǔ)架構(gòu)和兩個(gè)應(yīng)用程序。

          運(yùn)行示例

          使用 docker-compose 啟動(dòng)他們

          $ docker-compose up
          1. Prometheus 默認(rèn)地址:[http://localhost:9090/](http://localhost:9090/)
          2. Grafana默認(rèn)地址:[http://localhost:3000/](http://localhost:3000/)

          運(yùn)行服務(wù)器端應(yīng)用程序。

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

          運(yùn)行客戶端應(yīng)用程序。

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

          You should see log statements similar to these: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]

          打開(kāi) Grafana 儀表盤(pán),然后單擊 Logs, Traces, Metrics 儀表盤(pán)。在這里,您可以選擇一個(gè) trace ID(例如 bbe3aea006077640b66d40f3e62f04b9),以從兩個(gè)應(yīng)用程序中查找與該 trace ID 對(duì)應(yīng)的所有 logs 和 traces 信息。應(yīng)該會(huì)看到以下與同一 trace ID 相關(guān)的日志和traces 相關(guān)視圖,你將看到在同一時(shí)間范圍內(nèi)發(fā)生的 metrics。這些指標(biāo)與 HTTP 請(qǐng)求處理延遲有關(guān)。這些來(lái)自使用 Micrometer API 的自動(dòng)收集的 Spring Boot WebMvc 信息。

          1. 注意 metrics 中的圖性,這些是Exemplars 。這些是“特定軌跡,代表在給定時(shí)間間隔內(nèi)進(jìn)行的測(cè)量”。如果單擊形狀,可以跳到 trace ID 視圖查看對(duì)應(yīng)該的 trace.
          2. 單擊 trace ID 用 Tempo 查詢 要么跳轉(zhuǎn)到自己選擇的 trace ID。您將看到以下屏幕。 每個(gè)條形代表一個(gè)span 。我們可以看到完成每個(gè)操作所需的時(shí)間。如果單擊給定的范圍,我們可以看到與該特定操作相關(guān)的 tags(鍵值元數(shù)據(jù))和計(jì)時(shí)信息。

          這就是相關(guān)日志視圖在 Loki 中的效果圖:如果想查看@Observed 注解的方法 metrics,可以轉(zhuǎn)到 Prometheus 視圖并找到user_name Timer。 如果想查看手動(dòng)創(chuàng)建的 Observation metrics,請(qǐng)轉(zhuǎn)到 Prometheus 視圖并找到 my_observation Timer。

          2.6 與 AOT 支持一起運(yùn)行

          為了更好地理解 Spring Boot 如何支持 Native,請(qǐng)閱讀這篇優(yōu)秀的博客文章。

          構(gòu)建

          要構(gòu)建應(yīng)用程序,需要配置 GraalVM 到 path。如果使用 SDKMan 調(diào)用如下:

          sdk install java 22.2.r17-nik

          查看 GraalVM 快速使用。 使用 Maven 構(gòu)建,你需要啟用 native 環(huán)境:

          $ ./mvnw -Pnative clean package

          運(yùn)行

          先運(yùn)行服務(wù)端。

          $ ./server/target/server

          然后運(yùn)行客戶端。

          $ ./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

          服務(wù)端日志:

          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 的 metrics 和 traces。閱讀 Native 支持限制 章節(jié)查看為什么不能將日志推送到 Loki。

          Native 支持限制

          日志還不會(huì)被推給 Loki。更多信息請(qǐng)查看:issue 25847。 客戶端還需要手動(dòng)配置 reflect-config.js 。更多信息,請(qǐng)參閱此 PR。

          三、總結(jié)

          在這篇博文中,我們成功地向您介紹了微米可觀察性 API 背后的主要概念。我們還向您展示了如何使用 observe API 和  annotations 自定義可觀察。您還可以可視化延遲,查看相關(guān)日志,并檢查來(lái)自 Spring Boot 應(yīng)用程序的指標(biāo)。 當(dāng)然還可以通過(guò)使用 Spring native 中的 native images 來(lái)觀察應(yīng)用程序。

          四、下一步

          基于社區(qū)的反饋,將繼續(xù)改進(jìn)的可觀察性。并且打算在今年11月GA。 更多的項(xiàng)目文檔: Micrometer Context Propagation, Micrometer, Micrometer Observation, Micrometer Tracing 和 Micrometer Docs Generator!點(diǎn)擊 這里 查看本文章的示例代碼。


          瀏覽 331
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费黄色国产视频 | 亚洲天堂黄色 | 97免费在线视频 | 成人性爱免费看 | 精品久久视频 |