Exporters
In order to visualize and analyze your telemetry, you will need to export your data to an OpenTelemetry Collector or a backend such as Jaeger, Zipkin, Prometheus or a vendor-specific one.
As part of OpenTelemetry Java you will find many exporters being available. Among them, the OpenTelemetry Protocol (OTLP) exporters provide the best experience for you as an end-user, since it is a general-purpose telemetry data delivery protocol designed in the scope of the OpenTelemetry project.
To learn more about the OTLP protocol, you can read the OTLP Specification.
Below you will find some introductions on how to set up exporters for OTLP and other common protocols in your code.
Note
If you use the Java agent for automatic instrumentation you can learn how to setup exporters following the Agent Configuration GuideOTLP
To send trace data to a OTLP endpoint (like the collector or
Jaeger) you’ll want to use opentelemetry-exporter-otlp
.
OTLP Artifacts
There are multiple OTLP options available, each catering to different use cases. For most users, the default artifact will suffice and be the most simple:
dependencies {
implementation 'io.opentelemetry:opentelemetry-exporter-otlp:1.32.0'
}
<project>
<dependencies>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
</dependency>
</dependencies>
</project>
Under the hood, there are two protocol options supported, each with different “sender” implementations.
grpc
- gRPC implementation of OTLP exporters, represented byOtlpGrpcSpanExporter
,OtlpGrpcMetricExporter
,OtlpGrpcLogRecordExporter
.http/protobuf
- HTTP with protobuf encoded payload implementation of OTLP exporters, represented byOtlpHttpSpanExporter
,OtlpHttpMetricExporter
,OtlpHttpLogRecordExporter
.
A sender is an abstraction which allows different gRPC / HTTP client implementations to fulfill the OTLP contract. Regardless of the sender implementation, the same exporter classes are used. A sender implementation is automatically used when it is detected on the classpath. The sender implementations are described in detail below:
{groupId}:{artifactId}
- Sender description.io.opentelemetry:opentelemetry-exporter-sender-okhttp
- The default sender, included automatically withopentelemetry-exporter-otlp
and bundled with the OpenTelemetry Java agent. This includes an OkHttp based implementation for both thegrpc
andhttp/protobuf
versions of the protocol, and will be suitable for most users. However, OkHttp has a transitive dependency on kotlin which is problematic in some environments.io.opentelemetry:opentelemetry-exporter-sender-jdk
- This sender includes a JDK 11+ HttpClient based implementation for thehttp/protobuf
version of the protocol. It requires zero additional dependencies, but requires Java 11+. To use, include the artifact and explicitly exclude the defaultio.opentelemetry:opentelemetry-exporter-sender-okhttp
dependency.io.opentelemetry:opentelemetry-exporter-sender-grpc-managed-channel
- This sender includes a grpc-java based implementation for thegrpc
version of the protocol. To use, include the artifact, explicitly exclude the defaultio.opentelemetry:opentelemetry-exporter-sender-okhttp
dependency, and include one of the gRPC transport implementations.
Usage
Next, configure the exporter to point at an OTLP endpoint.
If you use SDK auto-configuration all you need to do is update your environment variables:
env OTEL_EXPORTER_OTLP_ENDPOINT=http://example:4317 java -jar ./build/libs/java-simple.jar
Note, that in the case of exporting via OTLP you do not need to set
OTEL_TRACES_EXPORTER
, OTEL_METRICS_EXPORTER
and OTEL_LOGS_EXPORTER
since
otlp
is their default value
In the case of [manual configuration] you can update the example app like the following:
package otel;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.Banner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.metrics.SdkMeterProvider;
import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.SdkTracerProvider;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor;
import io.opentelemetry.sdk.logs.SdkLoggerProvider;
import io.opentelemetry.sdk.logs.export.LogRecordExporter;
import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
@SpringBootApplication
public class DiceApplication {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(DiceApplication.class);
app.setBannerMode(Banner.Mode.OFF);
app.run(args);
}
@Bean
public OpenTelemetry openTelemetry() {
Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build();
SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build())
.setResource(resource)
.build();
SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder()
.registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build()).build())
.setResource(resource)
.build();
SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder()
.addLogRecordProcessor(
BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build())
.setResource(resource)
.build();
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(sdkTracerProvider)
.setMeterProvider(sdkMeterProvider)
.setLoggerProvider(sdkLoggerProvider)
.setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance()))
.buildAndRegisterGlobal();
return openTelemetry;
}
}
To see the traces exported quickly, you can run Jaeger with OTLP enabled in a docker container:
docker run -d --name jaeger \
-e COLLECTOR_OTLP_ENABLED=true \
-p 16686:16686 \
-p 4317:4317 \
-p 4318:4318 \
jaegertracing/all-in-one:latest