My demo of OpenTelemetry Tracing options two Spring Boot elements. One makes use of the Java agent, and I observed a special conduct once I lately upgraded it from v1.x to v2.x. Within the different one, I am utilizing Micrometer Tracing as a result of I compile to GraalVM native, and it will probably’t course of Java brokers.
I wish to evaluate these three alternative ways on this publish: Java agent v1, Java agent v2, and Micrometer Tracing.
The Base Utility and Its Infrastructure
I am going to use the identical base software: a easy Spring Boot software, coded in Kotlin. It presents a single endpoint.
- The perform past the endpoint is known as
entry()
. - It calls one other perform named
intermediate()
. - The latter makes use of a
WebClient
occasion, the alternative ofRestTemplate
, to make a name to the above endpoint. - To keep away from infinite looping, I go a customized request header: if the
entry()
perform finds it, it does not proceed additional.
It interprets into the next code:
@SpringBootApplication
class Agent1xApplication
@RestController
class MicrometerController {
personal val logger = LoggerFactory.getLogger(MicrometerController::class.java)
@GetMapping("/{message}")
enjoyable entry(@PathVariable message: String, @RequestHeader("X-done") carried out: String?) {
logger.information("entry: $message")
if (carried out == null) intermediate()
}
enjoyable intermediate() {
logger.information("intermediate")
RestClient.builder()
.baseUrl("http://localhost:8080/done")
.construct()
.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
}
}
For each setup, I am going to verify two phases: the first stage, with OpenTelemetry enabled, and a customization stage to create extra inside spans.
Micrometer Tracing
Micrometer Tracing stems from Micrometer, a “vendor-neutral application observability facade.”
Micrometer Tracing gives a easy facade for the preferred tracer libraries, letting you instrument your JVM-based software code with out vendor lock-in. It’s designed so as to add little to no overhead to your tracing assortment exercise whereas maximizing the portability of your tracing effort.
– Micrometer Tracing website
To start out with Micrometer Tracing, one wants so as to add just a few dependencies:
- Spring Boot Actuator,
org.springframework.boot:spring-boot-starter-actuator
- Micrometer Tracing itself,
io.micrometer:micrometer-tracing
- A “bridge” to the goal tracing backend API; In my case, it is OpenTelemetry, therefore
io.micrometer:micrometer-tracing-bridge-otel
- A concrete exporter to the backend,
io.opentelemetry:opentelemetry-exporter-otlp
We do not want a BOM as a result of variations are already outlined within the Spring Boot father or mother.
But, we’d like two runtime configuration parameters: the place ought to the traces be despatched, and what’s the part’s title. They’re ruled by the MANAGEMENT_OTLP_TRACING_ENDPOINT
and SPRING_APPLICATION_NAME
variables.
companies:
jaeger:
picture: jaegertracing/all-in-one:1.55
setting:
- COLLECTOR_OTLP_ENABLED=true #1
ports:
- "16686:16686"
micrometer-tracing:
construct:
dockerfile: Dockerfile-micrometer
setting:
MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2
SPRING_APPLICATION_NAME: micrometer-tracing #3
- Allow the OpenTelemetry collector for Jaeger.
- Full URL to the Jaeger OpenTelemetry gRPC endpoint.
- Set the OpenTelemetry’s service title.
This is the outcome:
With none customization, Micrometer creates spans when receiving and sending HTTP requests.
The framework must inject magic into the RestClient
for sending. We should let the previous instantiate the latter for that:
class MicrometerTracingApplication {
@Bean
enjoyable restClient(builder: RestClient.Builder) =
builder.baseUrl("http://localhost:8080/done").construct()
}
We will create handbook spans in a number of methods, one through the OpenTelemetry API itself. Nonetheless, the setup requires quite a lot of boilerplate code. Essentially the most simple method is the Micrometer’s Remark API. Its essential profit is to make use of a single API that manages each metrics and traces.
This is the up to date code:
class MicrometerController(
personal val restClient: RestClient,
personal val registry: ObservationRegistry
) {
@GetMapping("/{message}")
enjoyable entry(@PathVariable message: String, @RequestHeader("X-done") carried out: String?) {
logger.information("entry: $message")
val commentary = Remark.begin("entry", registry)
if (carried out == null) intermediate(commentary)
commentary.cease()
}
enjoyable intermediate(father or mother: Remark) {
logger.information("intermediate")
val commentary = Remark.createNotStarted("intermediate", registry)
.parentObservation(father or mother)
.begin()
restClient.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
commentary.cease()
}
}
The added commentary calls replicate upon the generated traces:
OpenTelemetry Agent v1
A substitute for Micrometer Tracing is the generic OpenTelemetry Java Agent. Its essential profit is that it impacts neither the code nor the builders; the agent is a pure runtime-scoped concern.
java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar
The agent abides by OpenTelemetry’s configuration with setting variables:
companies:
agent-1x:
construct:
dockerfile: Dockerfile-agent1
setting:
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1
OTEL_RESOURCE_ATTRIBUTES: service.title=agent-1x #2
OTEL_METRICS_EXPORTER: none #3
OTEL_LOGS_EXPORTER: none #4
ports:
- "8081:8080"
- Set the protocol, the area, and the port. The library appends
/v1/traces
. - Set the OpenTelemetry’s service title.
- Export neither the metrics nor the logs.
With no extra configuration, we get the next traces:
The agent mechanically tracks requests, each obtained and despatched, in addition to features marked with Spring-related annotations. Traces are appropriately nested inside one another, in keeping with the decision stack. To hint extra features, we have to add a dependency to our codebase, io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations
. We will now annotate beforehand untraced features with the @WithSpan
annotation.
The worth()
half governs the hint’s label, whereas the sort
interprets as a span.sort
attribute. If the worth is about to an empty string, which is the default, it outputs the perform’s title. For my functions, default values are ok.
@WithSpan
enjoyable intermediate() {
logger.information("intermediate")
RestClient.builder()
.baseUrl("http://localhost:8080/done")
.construct()
.get()
.header("X-done", "true")
.retrieve()
.toBodilessEntity()
}
It yields the anticipated new intermediate()
hint:
OpenTelemetry Agent v2
OpenTelemetry launched a brand new main model of the agent in January of this yr. I up to date my demo with it. Traces at the moment are solely created when the app receives and sends requests.
As for the earlier model, we will add traces with the @WithSpan
annotation. The one distinction is that we should additionally annotate the entry()
perform. It is not traced by default.
Dialogue
Spring turned profitable for 2 causes: it simplified complicated options, i.e., EJBs 2, and offered an abstraction layer over competing libraries. Micrometer Tracing began as an abstraction layer over Zipkin and Jaeger, and it made complete sense. This argument turns into moot with OpenTelemetry being supported by most libraries throughout programming languages and hint collectors. The Remark API continues to be a substantial good thing about Micrometer Tracing, because it makes use of a single API over Metrics and Traces.
On the Java Agent facet, OpenTelemetry configuration is analogous throughout all tech stacks and libraries – setting variables. I used to be a bit disillusioned once I upgraded from v1 to v2, as the brand new agent will not be Spring-aware: Spring-annotated features are usually not traced by default. Ultimately, it is a sensible choice. It is a lot better to be specific in regards to the spans you need than take away some you do not wish to see.
- Due to Jonatan Ivanov for his assist and his evaluate.
- The entire supply code for this publish will be discovered on GitHub.