Spring Boot
How to instrument Spring Boot with OpenTelemetry
The OpenTelemetry Java agent with byte code instrumentation can cover most of your needs when instrumenting Spring Boot applications.
Alternatively, the OpenTelemetry Spring Boot starter can help you in the following cases:
- Spring Boot Native image applications for which the OpenTelemetry Java agent does not work
- Startup overhead of the OpenTelemetry Java agent exceeds your requirements
- OpenTelemetry Java agent might not work if your application already uses another Java monitoring agent
- You can use the Spring Boot configuration files (
application.properties
,application.yml
) to configure the OpenTelemetry Spring Boot starter which doesn’t work with the OpenTelemetry Java agent
The OpenTelemetry Java agent has more automatic instrumentation features than the OpenTelemetry starter.
You can use OpenTelemetry instrumentations libraries to complete the automatic instrumentation of the Spring Boot starter.
OpenTelemetry Spring Boot starter
Compatibility
The OpenTelemetry Spring Boot starter works with Spring Boot 2.0 and 3.0, and Spring Boot native image applications. The opentelemetry-java-examples/spring-native repository contains an example of a Spring Boot Native image application instrumented using the OpenTelemetry Spring Boot starter.
Dependency management
A Bill of Material (BOM) ensures that versions of dependencies (including transitive ones) are aligned.
Importing the opentelemetry-bom
and opentelemetry-instrumentation-bom-alpha
BOMs when using the OpenTelemetry starter is important to ensure version
alignment across all OpenTelemetry dependencies.
The following example shows how to import both BOMs using Maven:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>1.35.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-bom-alpha</artifactId>
<version>2.1.0-alpha</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
With Gradle and Spring Boot, you have two ways to import a BOM.
You can use the Gradle’s native BOM support by adding dependencies
:
import org.springframework.boot.gradle.plugin.SpringBootPlugin
plugins {
id("java")
id("org.springframework.boot") version "3.2.O"
}
dependencies {
implementation(platform(SpringBootPlugin.BOM_COORDINATES))
implementation(platform("io.opentelemetry:opentelemetry-bom:1.35.0"))
implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.1.0-alpha"))
}
The other way with Gradle is to use the io.spring.dependency-management
plugin
and to import the BOMs in dependencyManagement
:
plugins {
id("java")
id("org.springframework.boot") version "3.2.O"
id("io.spring.dependency-management") version "1.1.0"
}
dependencyManagement {
imports {
mavenBom("io.opentelemetry:opentelemetry-bom:1.35.0")
mavenBom("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:2.1.0-alpha")
}
}
Note
Be careful not to mix up the different ways of configuring things with Gradle. For example, don’t useimplementation(platform("io.opentelemetry:opentelemetry-bom:1.35.0"))
with the io.spring.dependency-management
plugin.OpenTelemetry Starter dependency
Add the dependency given below to enable the OpenTelemetry starter.
The OpenTelemetry starter uses OpenTelemetry Spring Boot autoconfiguration. For details concerning supported libraries and features of the OpenTelemetry autoconfiguration, see the configuration README.
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-spring-boot-starter</artifactId>
</dependency>
</dependencies>
dependencies {
implementation("io.opentelemetry.instrumentation:opentelemetry-spring-boot-starter")
}
Configuration
This spring starter supports configuration metadata, which means that you can see and autocomplete all available properties in your IDE.
Disable the OpenTelemetry Starter
System property:
otel.sdk.disabled
Environment variable:
OTEL_SDK_DISABLED
Description:
Set the value to true
to disable the starter, e.g. for testing purposes.
OpenTelemetry Data Exporters
This package provides autoconfiguration the following exporters:
- OTLP
- Logging
All available properties are listed in the Configuration page.
The only difference is that the OpenTelemetry Spring Boot starter uses
http/protobuf
as the default protocol for the OTLP exporter (as of 2.0.0+).
Tracer Properties
Feature | Property | Default Value |
---|---|---|
Tracer | otel.traces.sampler.probability | 1.0 |
Resource Properties
Feature | Property | Default Value |
---|---|---|
Resource | otel.springboot.resource.enabled | true |
otel.resource.attributes | empty map |
otel.resource.attributes
supports a pattern-based resource configuration in
the application.properties like this:
otel.resource.attributes.environment=dev
otel.resource.attributes.xyz=foo
It’s also possible to specify the resource attributes in application.yaml
:
otel:
resource:
attributes:
environment: dev
xyz: foo
Finally, the resource attributes can be specified as a comma-separated list, as described in the specification:
export OTEL_RESOURCE_ATTRIBUTES="key1=value1,key2=value2"
The service name is determined by the following precedence rules, in accordance with the OpenTelemetry specification:
otel.service.name
spring property orOTEL_SERVICE_NAME
environment variable (highest precedence)service.name
inotel.resource.attributes
system/spring property orOTEL_RESOURCE_ATTRIBUTES
environment variablespring.application.name
spring property- The default value is
unknown_service:java
(lowest precedence)
Automatic instrumentation
Automatic instrumentation is available for several frameworks:
Feature | Property | Default Value |
---|---|---|
Logback | otel.instrumentation.logback-appender.enabled | true |
Spring Web | otel.instrumentation.spring-web.enabled | true |
Spring Web MVC | otel.instrumentation.spring-webmvc.enabled | true |
Spring WebFlux | otel.instrumentation.spring-webflux.enabled | true |
Logback
You can enable experimental features with system properties to capture attributes :
System property | Type | Default | Description | |
---|---|---|---|---|
otel.instrumentation.logback-appender.experimental-log-attributes | Boolean | false | Enable the capture of experimental log attributes thread.name and thread.id . | |
otel.instrumentation.logback-appender.experimental.capture-code-attributes | Boolean | false | Enable the capture of source code attributes. Note that capturing source code attributes at logging sites might add a performance overhead. | |
otel.instrumentation.logback-appender.experimental.capture-marker-attribute | Boolean | false | Enable the capture of Logback markers as attributes. | |
otel.instrumentation.logback-appender.experimental.capture-key-value-pair-attributes | Boolean | false | Enable the capture of Logback key value pairs as attributes. | |
otel.instrumentation.logback-appender.experimental.capture-logger-context-attributes | Boolean | false | Enable the capture of Logback logger context properties as attributes. | |
otel.instrumentation.logback-appender.experimental.capture-mdc-attributes | String | Comma separated list of MDC attributes to capture. Use the wildcard character * to capture all attributes. |
Alternatively, you can enable these features by adding the OpenTelemetry Logback
appender in your logback.xml
or logback-spring.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<appender name="OpenTelemetry"
class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender ">
<captureExperimentalAttributes>false</captureExperimentalAttributes>
<captureCodeAttributes>true</captureCodeAttributes>
<captureMarkerAttribute>true</captureMarkerAttribute>
<captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
<captureLoggerContext>true</captureLoggerContext>
<captureMdcAttributes>*</captureMdcAttributes>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
<appender-ref ref="OpenTelemetry"/>
</root>
</configuration>
Spring Web Autoconfiguration
Provides autoconfiguration for the RestTemplate
trace interceptor defined in
opentelemetry-spring-web-3.1.
This autoconfiguration instruments all requests sent using Spring RestTemplate
beans by applying a RestTemplate
bean post processor. This feature is
supported for spring web versions 3.1+. To learn more about the OpenTelemetry
RestTemplate
interceptor, see
opentelemetry-spring-web-3.1.
Spring Web MVC Autoconfiguration
This feature autoconfigures instrumentation for Spring WebMVC controllers by
adding a
telemetry producing servlet Filter
bean to the application context. The filter decorates the request execution with
a server span, propagating the incoming tracing context if received in the HTTP
request. To learn more about the OpenTelemetry Spring WebMVC instrumentation,
see the
opentelemetry-spring-webmvc-5.3 instrumentation library.
Spring WebFlux Autoconfiguration
Provides autoconfigurations for the OpenTelemetry WebClient ExchangeFilter defined in opentelemetry-spring-webflux-5.3. This autoconfiguration instruments all outgoing HTTP requests sent using Spring’s WebClient and WebClient Builder beans by applying a bean post processor. This feature is supported for spring webflux versions 5.0+. For details, see opentelemetry-spring-webflux-5.3.
Additional Instrumentations
JDBC Instrumentation
You have two ways to enable the JDBC instrumentation with the OpenTelemetry starter.
If your application does not declare DataSource
bean, you can update your
application.properties
file to have the data source URL starting with
jdbc:otel:
and set the driver class to
io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver
.
spring.datasource.url=jdbc:otel:h2:mem:db
spring.datasource.driver-class-name=io.opentelemetry.instrumentation.jdbc.OpenTelemetryDriver
You can also wrap the DataSource
bean in an
io.opentelemetry.instrumentation.jdbc.datasource.OpenTelemetryDataSource
:
import io.opentelemetry.instrumentation.jdbc.datasource.JdbcTelemetry;
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource(OpenTelemetry openTelemetry) {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
//Data source configurations
DataSource dataSource = dataSourceBuilder.build();
return JdbcTelemetry.create(openTelemetry).wrap(dataSource);
}
}
With the datasource configuration, you need to add the following dependency:
<dependencies>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-jdbc</artifactId>
</dependency>
</dependencies>
dependencies {
implementation("io.opentelemetry.instrumentation:opentelemetry-jdbc")
}
Log4j2 Instrumentation
You have to add the OpenTelemetry appender to your log4j2.xml
file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="io.opentelemetry.instrumentation.log4j.appender.v2_17">
<Appenders>
<OpenTelemetry name="OpenTelemetryAppender"/>
</Appenders>
<Loggers>
<Root>
<AppenderRef ref="OpenTelemetryAppender" level="All"/>
</Root>
</Loggers>
</Configuration>
You can find more configuration options for the OpenTelemetry appender in the Log4j instrumentation library.
Instrumentation Annotations
This feature uses spring-aop to wrap methods annotated with @WithSpan
in a
span. The arguments to the method can be captured as attributed on the created
span by annotating the method parameters with @SpanAttribute
.
Note: this annotation can only be applied to bean methods managed by the spring application context. To learn more about aspect weaving in spring, see spring-aop.
Feature | Property | Default Value | ConditionalOnClass |
---|---|---|---|
@WithSpan | otel.instrumentation.annotations.enabled | true | WithSpan, Aspect |
Dependency
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>SPRING_VERSION</version>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-instrumentation-annotations</artifactId>
<version>2.1.0</version>
</dependency>
</dependencies>
dependencies {
implementation("org.springframework:spring-aop:SPRING_VERSION")
implementation("io.opentelemetry:opentelemetry-extension-annotations:1.35.0")
}
Usage
import org.springframework.stereotype.Component;
import io.opentelemetry.instrumentation.annotations.SpanAttribute;
import io.opentelemetry.instrumentation.annotations.WithSpan;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanKind;
/**
* Test WithSpan
*/
@Component
public class TracedClass {
@WithSpan
public void tracedMethod() {
}
@WithSpan(value="span name")
public void tracedMethodWithName() {
Span currentSpan = Span.current();
currentSpan.addEvent("ADD EVENT TO tracedMethodWithName SPAN");
currentSpan.setAttribute("isTestAttribute", true);
}
@WithSpan(kind = SpanKind.CLIENT)
public void tracedClientSpan() {
}
public void tracedMethodWithAttribute(@SpanAttribute("attributeName") String parameter) {
}
}
OpenTelemetry instrumentations libraries
You can configure other instrumentations with OpenTelemetry instrumentations libraries.
Other solutions
Instead of using the OpenTelemetry Spring starter, you can use the OpenTelemetry autoconfiguration features with an annotation or the Zipkin starter.
Spring support
Autoconfiguration is natively supported by Spring Boot applications. To enable
these features in “vanilla” use @EnableOpenTelemetry
to complete a component
scan of this package.
import io.opentelemetry.instrumentation.spring.autoconfigure.EnableOpenTelemetry;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableOpenTelemetry
public class OpenTelemetryConfig {}
Zipkin starter
OpenTelemetry Zipkin Exporter Starter is a starter package that includes the opentelemetry-api, opentelemetry-sdk, opentelemetry-extension-annotations, opentelemetry-logging-exporter, opentelemetry-spring-boot-autoconfigurations and spring framework starters required to setup distributed tracing. It also provides the opentelemetry-exporters-zipkin artifact and corresponding exporter autoconfiguration. Check out opentelemetry-spring-boot-autoconfigure for the list of supported libraries and features.
If an exporter is present in the classpath during runtime and a spring bean of the exporter is missing from the spring application context, an exporter bean is initialized and added to a simple span processor in the active tracer provider. Check out the implementation here.
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<version>1.35.0</version>
</dependency>
</dependencies>
dependencies {
implementation("io.opentelemetry:opentelemetry-exporter-zipkin:1.35.0")
}
Configurations
Property | Default Value | ConditionalOnClass |
---|---|---|
otel.exporter.zipkin.enabled | true | ZipkinSpanExporter |