Trong bài viết trước, mình đã hướng dẫn các bạn về OpenTelemetry với Logging exporter để log các thông tin về các request tới ứng dụng. Mặc định thì chúng ta sẽ thấy chủ yếu các thông tin về tracers được log. Để hiển thị thêm các thông tin về metrics, các bạn có thể add thêm code sử dụng thư viện OpenTelemetry SDK metrics. Cụ thể như thế nào? Chúng ta hãy cùng nhau tìm hiểu trong bài viết này các bạn nhé!
Mình sẽ sử dụng lại ví dụ trong bài viết Integrate OpenTelemetry với các ứng dụng Java, và sẽ thêm OpenTelemetry SDK metrics dependency vào project của ứng dụng này như sau:
1 2 3 4 |
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-metrics</artifactId> </dependency> |
Project của chúng ta là Spring Boot và vì nó đã có managed version của OpenTelemetry SDK rồi nên các bạn không cần declare version cho OpenTelemetry SDK nữa các bạn nhé!
Bây giờ, chúng ta sẽ thêm một metric để đếm số lần request tới request “/hello” của ứng dụng ví dụ. Cứ mỗi lần request tới, số lượng request tới ứng dụng sẽ tăng lên 1.
Để làm được điều này, đầu tiên, chúng ta sẽ khởi tạo đối tượng của class Meter sử dụng class GlobalOpenTelemetry của thư viện OpenTelemetry SDK trước, như sau:
1 2 |
private Meter meter = GlobalOpenTelemetry.meterBuilder("io.opentelemetry.metrics.hello") .build(); |
Tham số của phương thức static meterBuilder() là tên của metric, giúp các bạn có thể search nhanh dựa theo tên này nên các bạn hãy đặt tên cho hợp lý để search cho nhanh nhé!
Tiếp theo, mình sẽ định nghĩa một biến để nắm giữ thông tin về số lượng request tới request “/hello” của ứng dụng. Các bạn có thể sử dụng đối tượng của class LongCounter của OpenTelemetry SDK metrics để nắm giữ thông tin này:
1 2 |
private LongCounter counter = meter.counterBuilder("helloCounter") .build(); |
Để mỗi lần một request tới url “/hello”, số lượng request sẽ tăng lên 1, các bạn có thể sử dụng phương thức add() của đối tượng LongBuilder như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package com.huongdanjava.opentelemetry; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; @RestController public class HelloController { private Meter meter = GlobalOpenTelemetry.meterBuilder("io.opentelemetry.metrics.hello") .build(); private LongCounter counter = meter.counterBuilder("helloCounter") .build(); @GetMapping("/hello") public String hello() { counter.add(1); return "Hello"; } } |
Bây giờ, chạy lại ứng dụng này sử dụng Logging Exporter của OpenTelemetry rồi request tới địa chỉ http://localhost:8080/hello 3 lần, đợi 1 xíu thời gian, các bạn sẽ thấy dòng log sau:
1 |
[otel.javaagent 2023-06-14 15:58:46:124 -0400] [PeriodicMetricReader-1] INFO io.opentelemetry.exporter.logging.LoggingMetricExporter - metric: ImmutableMetricData{resource=Resource{schemaUrl=https://opentelemetry.io/schemas/1.19.0, attributes={host.arch="x86_64", host.name="Khanhs-MacBook-Pro.local", os.description="Mac OS X 10.15.7", os.type="darwin", process.command_args=[/Applications/SpringToolSuite4.app/Contents/Eclipse/plugins/org.eclipse.justj.openjdk.hotspot.jre.full.macosx.x86_64_17.0.7.v20230425-1502/jre/bin/java, -Dcom.sun.management.jmxremote, -Dcom.sun.management.jmxremote.port=50716, -Dcom.sun.management.jmxremote.authenticate=false, -Dcom.sun.management.jmxremote.ssl=false, -Djava.rmi.server.hostname=localhost, -Dspring.jmx.enabled=true, -Dmanagement.endpoints.jmx.exposure.include=*, -Dspring.application.admin.enabled=true, -Djava.security.egd=file:/dev/./urandom, -javaagent:/Users/khanh/Downloads/opentelemetry-javaagent.jar, -XX:TieredStopAtLevel=1, -Dspring.boot.project.name=spring-boot-opentelemetry-example, -Dfile.encoding=UTF-8, -classpath, /Users/khanh/Documents/code/huongdanjava.com/spring-boot-opentelemetry-example/target/classes:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-starter-web/3.1.0/spring-boot-starter-web-3.1.0.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-starter/3.1.0/spring-boot-starter-3.1.0.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot/3.1.0/spring-boot-3.1.0.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/3.1.0/spring-boot-autoconfigure-3.1.0.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-starter-logging/3.1.0/spring-boot-starter-logging-3.1.0.jar:/Users/khanh/.m2/repository/ch/qos/logback/logback-classic/1.4.7/logback-classic-1.4.7.jar:/Users/khanh/.m2/repository/ch/qos/logback/logback-core/1.4.7/logback-core-1.4.7.jar:/Users/khanh/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.20.0/log4j-to-slf4j-2.20.0.jar:/Users/khanh/.m2/repository/org/apache/logging/log4j/log4j-api/2.20.0/log4j-api-2.20.0.jar:/Users/khanh/.m2/repository/org/slf4j/jul-to-slf4j/2.0.7/jul-to-slf4j-2.0.7.jar:/Users/khanh/.m2/repository/jakarta/annotation/jakarta.annotation-api/2.1.1/jakarta.annotation-api-2.1.1.jar:/Users/khanh/.m2/repository/org/yaml/snakeyaml/1.33/snakeyaml-1.33.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-starter-json/3.1.0/spring-boot-starter-json-3.1.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.15.0/jackson-databind-2.15.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.15.0/jackson-annotations-2.15.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.15.0/jackson-core-2.15.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.15.0/jackson-datatype-jdk8-2.15.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.15.0/jackson-datatype-jsr310-2.15.0.jar:/Users/khanh/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.15.0/jackson-module-parameter-names-2.15.0.jar:/Users/khanh/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/3.1.0/spring-boot-starter-tomcat-3.1.0.jar:/Users/khanh/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/10.1.8/tomcat-embed-core-10.1.8.jar:/Users/khanh/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/10.1.8/tomcat-embed-el-10.1.8.jar:/Users/khanh/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/10.1.8/tomcat-embed-websocket-10.1.8.jar:/Users/khanh/.m2/repository/org/springframework/spring-web/6.0.9/spring-web-6.0.9.jar:/Users/khanh/.m2/repository/org/springframework/spring-beans/6.0.9/spring-beans-6.0.9.jar:/Users/khanh/.m2/repository/io/micrometer/micrometer-observation/1.11.0/micrometer-observation-1.11.0.jar:/Users/khanh/.m2/repository/io/micrometer/micrometer-commons/1.11.0/micrometer-commons-1.11.0.jar:/Users/khanh/.m2/repository/org/springframework/spring-webmvc/6.0.9/spring-webmvc-6.0.9.jar:/Users/khanh/.m2/repository/org/springframework/spring-aop/6.0.9/spring-aop-6.0.9.jar:/Users/khanh/.m2/repository/org/springframework/spring-context/6.0.9/spring-context-6.0.9.jar:/Users/khanh/.m2/repository/org/springframework/spring-expression/6.0.9/spring-expression-6.0.9.jar:/Users/khanh/.m2/repository/io/opentelemetry/opentelemetry-sdk-metrics/1.25.0/opentelemetry-sdk-metrics-1.25.0.jar:/Users/khanh/.m2/repository/io/opentelemetry/opentelemetry-api/1.25.0/opentelemetry-api-1.25.0.jar:/Users/khanh/.m2/repository/io/opentelemetry/opentelemetry-context/1.25.0/opentelemetry-context-1.25.0.jar:/Users/khanh/.m2/repository/io/opentelemetry/opentelemetry-sdk-common/1.25.0/opentelemetry-sdk-common-1.25.0.jar:/Users/khanh/.m2/repository/io/opentelemetry/opentelemetry-semconv/1.25.0-alpha/opentelemetry-semconv-1.25.0-alpha.jar:/Users/khanh/.m2/repository/org/slf4j/slf4j-api/2.0.7/slf4j-api-2.0.7.jar:/Users/khanh/.m2/repository/org/springframework/spring-core/6.0.9/spring-core-6.0.9.jar:/Users/khanh/.m2/repository/org/springframework/spring-jcl/6.0.9/spring-jcl-6.0.9.jar, -XX:+ShowCodeDetailsInExceptionMessages, com.huongdanjava.opentelemetry.SpringBootOpentelemetryExampleApplication, --spring.output.ansi.enabled=always], process.executable.path="/Applications/SpringToolSuite4.app/Contents/Eclipse/plugins/org.eclipse.justj.openjdk.hotspot.jre.full.macosx.x86_64_17.0.7.v20230425-1502/jre/bin/java", process.pid=1935, process.runtime.description="Eclipse Adoptium OpenJDK 64-Bit Server VM 17.0.7+7", process.runtime.name="OpenJDK Runtime Environment", process.runtime.version="17.0.7+7", service.name="unknown_service:java", telemetry.auto.version="1.26.0", telemetry.sdk.language="java", telemetry.sdk.name="opentelemetry", telemetry.sdk.version="1.26.0"}}, instrumentationScopeInfo=InstrumentationScopeInfo{name=io.opentelemetry.metrics.hello, version=null, schemaUrl=null, attributes={}}, name=helloCounter, description=, unit=, type=LONG_SUM, data=ImmutableSumData{points=[ImmutableLongPointData{startEpochNanos=1686772666090170000, epochNanos=1686772726101747000, attributes={}, value=3, exemplars=[ImmutableLongExemplarData{filteredAttributes={}, epochNanos=1686772675108491000, spanContext=ImmutableSpanContext{traceId=5eb3cfd9bddb56786ec6f3efdfead80c, spanId=50207b4ea209a36e, traceFlags=01, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true}, value=1}, ImmutableLongExemplarData{filteredAttributes={}, epochNanos=1686772681305194000, spanContext=ImmutableSpanContext{traceId=20393282e4aa3a4d8a207c3186a2cb06, spanId=b23be330a56412d2, traceFlags=01, traceState=ArrayBasedTraceState{entries=[]}, remote=false, valid=true}, value=1}]}], monotonic=true, aggregationTemporality=CUMULATIVE}} |
Nếu xem xét kỹ dòng log này, các bạn sẽ thấy nó là dòng log của OpenTelemetry về metric sử dụng class LoggerMetricExporter, tên của InstrumentationScopeInfo là “io.opentelemetry.metrics.hello” như mình đã đặt ở trên, cho metric “helloCounter” thì giá trị của nó là 3.
Như vậy là chúng ta đã thành công trong việc thêm custom metric vào ứng dụng Java và sử dụng LoggingExporter để log thông tin này ra console rồi đó các bạn!