In the previous tutorial, I guided you through OpenTelemetry with the Logging exporter to log information about requests to the application. By default, we will see mainly information about tracers logged. To display more information about metrics, you can add additional code using the OpenTelemetry SDK metrics library. How is it in detail? Let’s find out together in this tutorial!
I will reuse the example in the article Integrate OpenTelemetry with Java applications, and will add the OpenTelemetry SDK metrics dependency to this application’s project as follows:
1 2 3 4 |
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-metrics</artifactId> </dependency> |
Our project is Spring Boot and since it already has a managed version of OpenTelemetry SDK, you don’t need to declare the version for OpenTelemetry SDK anymore, guys!
Now, we will add a metric to count the number of requests to the “/hello” request of the example application. For each incoming request, the number of requests to the application will increase by 1.
To do this, first, we will initialize the object of the Meter class using the GlobalOpenTelemetry class of the OpenTelemetry SDK library first, as follows:
1 2 |
private Meter meter = GlobalOpenTelemetry.meterBuilder("io.opentelemetry.metrics.hello") .build(); |
The parameter of the static meterBuilder() method is the name of the metric, so you can quickly search based on this name, so please give it a reasonable name to search quickly!
Next, I will define a variable to hold information about the number of requests to the application’s “/hello” request. You can use the object of OpenTelemetry SDK metrics’ LongCounter class to hold this information:
1 2 |
private LongCounter counter = meter.counterBuilder("helloCounter") .build(); |
To make each time, a request to the request “/hello”, the number of requests will increase by 1, you can use the add() method of the LongBuilder object as follows:
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"; } } |
Now, run this application again using OpenTelemetry’s Logging Exporter and then request to http://localhost:8080/hello 3 times, wait a little while, you will see the following logline:
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}} |
If you look closely at this logline, you will see that it is the logline of OpenTelemetry about the metric using the LoggerMetricExporter class, the name of InstrumentationScopeInfo is “io.opentelemetry.metrics.hello” as I set it above, for the metric “helloCounter” then its value is 3.
That’s it, we have successfully added a custom metric to our Java application and used the LoggingExporter to log this information to the console!