Skip to content

Commit

Permalink
Add auto-configuration for OTLP span exporter
Browse files Browse the repository at this point in the history
With these changes an OTLP exporter is auto-configured
if opentelemetry-exporter-otlp is on the classpath.
By default HTTP is used but gRPC is also available.

Closes gh-34390
  • Loading branch information
jonatan-ivanov committed Mar 7, 2023
1 parent dab8b07 commit 7920a1c
Show file tree
Hide file tree
Showing 7 changed files with 437 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ dependencies {
optional("io.micrometer:micrometer-registry-wavefront")
optional("io.zipkin.reporter2:zipkin-sender-urlconnection")
optional("io.opentelemetry:opentelemetry-exporter-zipkin")
optional("io.opentelemetry:opentelemetry-exporter-otlp")
optional("io.projectreactor.netty:reactor-netty-http")
optional("io.r2dbc:r2dbc-pool")
optional("io.r2dbc:r2dbc-spi")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.actuate.autoconfigure.tracing.otlp;

import io.micrometer.tracing.otel.bridge.OtelTracer;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter;
import io.opentelemetry.sdk.trace.SdkTracerProvider;

import org.springframework.boot.actuate.autoconfigure.tracing.ConditionalOnEnabledTracing;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* {@link EnableAutoConfiguration Auto-configuration} for OTLP. Brave does not support
* OTLP, so we only configure it for OpenTelemetry. OTLP defines three transports that are
* supported: gRPC (/protobuf), HTTP/protobuf, HTTP/JSON. From these transports HTTP/JSON
* is not supported by the OTel Java SDK, and it seems there are no plans supporting it in
* the future, see: <a href=
* "https://github.com/open-telemetry/opentelemetry-java/issues/3651">opentelemetry-java#3651</a>.
* Because this class configures components from the OTel SDK, it can only support what
* the OTel SDK does: gRPC and HTTP/protobuf.
*
* @author Jonatan Ivanov
* @since 3.1.0
*/
@AutoConfiguration
@ConditionalOnEnabledTracing
@ConditionalOnClass({ OtelTracer.class, SdkTracerProvider.class, OpenTelemetry.class })
@EnableConfigurationProperties(OtlpProperties.class)
public class OtlpAutoConfiguration {

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OtlpHttpSpanExporter.class)
@ConditionalOnProperty(prefix = "management.otlp.tracing.http", name = "enabled", matchIfMissing = true)
static class HttpConfiguration {

@Bean
@ConditionalOnMissingBean
OtlpHttpSpanExporter otlpHttpSpanExporter(OtlpProperties properties) {
return OtlpHttpSpanExporter.builder()
.setEndpoint(properties.getHttp().getEndpoint())
.setTimeout(properties.getHttp().getTimeout())
.setCompression(properties.getHttp().getCompression().name().toLowerCase())
.build();
}

}

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OtlpGrpcSpanExporter.class)
@ConditionalOnProperty(prefix = "management.otlp.tracing.grpc", name = "enabled")
static class GrpcConfiguration {

@Bean
@ConditionalOnMissingBean
OtlpGrpcSpanExporter otlpGrpcSpanExporter(OtlpProperties properties) {
return OtlpGrpcSpanExporter.builder()
.setEndpoint(properties.getGrpc().getEndpoint())
.setTimeout(properties.getGrpc().getTimeout())
.setCompression(properties.getGrpc().getCompression().name().toLowerCase())
.build();
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.boot.actuate.autoconfigure.tracing.otlp;

import java.time.Duration;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
* Configuration properties for {@link OtlpAutoConfiguration}.
*
* @author Jonatan Ivanov
* @since 3.1.0
*/
@ConfigurationProperties("management.otlp.tracing")
public class OtlpProperties {

/**
* HTTP configuration.
*/
private final Http http = new Http();

/**
* gRPC configuration.
*/
private final Grpc grpc = new Grpc();

public Http getHttp() {
return this.http;
}

public Grpc getGrpc() {
return this.grpc;
}

public static class Http {

/**
* Whether auto-configuration of HTTP exporter is enabled.
*/
private boolean enabled = true;

/**
* URL to the OTel collector's HTTP API.
*/
private String endpoint = "http://localhost:4318/v1/traces";

/**
* Call timeout for the OTel Collector to process an exported batch of data. This
* timeout spans the entire call: resolving DNS, connecting, writing the request
* body, server processing, and reading the response body. If the call requires
* redirects or retries all must complete within one timeout period.
*/
private Duration timeout = Duration.ofSeconds(10);

/**
* The method used to compress the payload.
*/
private Compression compression = Compression.NONE;

public boolean isEnabled() {
return this.enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public String getEndpoint() {
return this.endpoint;
}

public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}

public Duration getTimeout() {
return this.timeout;
}

public void setTimeout(Duration timeout) {
this.timeout = timeout;
}

public Compression getCompression() {
return this.compression;
}

public void setCompression(Compression compression) {
this.compression = compression;
}

}

public static class Grpc {

/**
* Whether auto-configuration of gRPC exporter is enabled.
*/
private boolean enabled = false;

/**
* URL to the OTel collector's gRPC API.
*/
private String endpoint = "http://localhost:4317";

/**
* Call timeout for the OTel Collector to process an exported batch of data. This
* timeout spans the entire call: resolving DNS, connecting, writing the request
* body, server processing, and reading the response body. If the call requires
* redirects or retries all must complete within one timeout period.
*/
private Duration timeout = Duration.ofSeconds(10);

/**
* The method used to compress the payload.
*/
private Compression compression = Compression.NONE;

public boolean isEnabled() {
return this.enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

public String getEndpoint() {
return this.endpoint;
}

public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}

public Duration getTimeout() {
return this.timeout;
}

public void setTimeout(Duration timeout) {
this.timeout = timeout;
}

public Compression getCompression() {
return this.compression;
}

public void setCompression(Compression compression) {
this.compression = compression;
}

}

enum Compression {

/**
* Gzip compression.
*/
GZIP,

/**
* No compression.
*/
NONE

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Auto-configuration for tracing with OTLP.
*/
package org.springframework.boot.actuate.autoconfigure.tracing.otlp;
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributor
org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.OpenTelemetryAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.prometheus.PrometheusExemplarsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.wavefront.WavefrontTracingAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.zipkin.ZipkinAutoConfiguration
Expand Down
Loading

0 comments on commit 7920a1c

Please sign in to comment.