Removed OTel (#1802)

This commit is contained in:
Marcin Grzejszczak
2020-12-10 22:19:57 +01:00
committed by GitHub
parent 89433dc4d7
commit 4c3d12e639
188 changed files with 57 additions and 10838 deletions

View File

@@ -49,23 +49,6 @@ Example of Sleuth with Brave tracer:
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- Sleuth with OpenTelemetry tracer implementation -->
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
-->
</dependencies>
----

View File

@@ -68,10 +68,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>

View File

@@ -99,7 +99,6 @@ public class SampleTests {
protected String[] runArgs() {
List<String> strings = new ArrayList<>();
strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
"--spring.autoconfigure.exclude=org.springframework.cloud.sleuth.otel.autoconfig.TraceOtelAutoConfiguration",
"--spring.application.name=defaultTraceContextForStream" + instrumentation.name()));
strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));
return strings.toArray(new String[0]);

View File

@@ -16,24 +16,9 @@
package org.springframework.cloud.sleuth.benchmarks.jmh;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
public enum TracerImplementation {
otel(BraveAutoConfiguration.class.getCanonicalName()), brave(OtelAutoConfiguration.class.getCanonicalName());
private String key = "spring.autoconfigure.exclude";
private String value;
TracerImplementation(String value) {
this.value = value;
}
public String property() {
return "--" + this.key + "=" + this.value;
}
brave;
@Override
public String toString() {

View File

@@ -38,7 +38,6 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
@@ -106,7 +105,7 @@ public class BridgeTests {
public void setup() {
SpringApplication application = new SpringApplication(TestConfiguration.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.withSleuth = application.run("--spring.jmx.enabled=false", this.tracerImplementation.property(),
this.withSleuth = application.run("--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.tracer = this.withSleuth.getBean(Tracer.class);
this.parent = this.tracer.nextSpan().name("name").start();
@@ -119,7 +118,7 @@ public class BridgeTests {
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@ImportAutoConfiguration(BraveAutoConfiguration.class)
static class TestConfiguration {
}

View File

@@ -72,7 +72,7 @@ public class AnnotationBenchmarksTests {
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
this.tracerImplementation.property(),
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.sleuth = this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class);
}

View File

@@ -76,7 +76,7 @@ public class AsyncBenchmarksTests {
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
this.tracerImplementation.property(),
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.withoutSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
"--spring.jmx.enabled=false", "--spring.application.name=withoutSleuth",

View File

@@ -139,7 +139,7 @@ public class HttpFilterBenchmarksTests {
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
this.tracerImplementation.property(),
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.tracingFilter = this.withSleuth.getBean(TracingFilter.class);
this.mockMvcForTracedController = MockMvcBuilders

View File

@@ -88,7 +88,7 @@ public class RestTemplateBenchmarkTests {
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
this.tracerImplementation.property(),
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.mockMvc = MockMvcBuilders.standaloneSetup(this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class))
.build();

View File

@@ -107,7 +107,7 @@ public class MicroBenchmarkStreamTests {
protected String[] runArgs() {
List<String> strings = new ArrayList<>();
strings.addAll(Arrays.asList("--spring.jmx.enabled=false", this.tracerImplementation.property(),
strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
"--spring.application.name=defaultTraceContextForStream" + instrumentation.name() + "_"
+ tracerImplementation.name()));
strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));

View File

@@ -38,10 +38,6 @@
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>

View File

@@ -42,23 +42,6 @@ Example of Sleuth with Brave tracer:
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- Sleuth with OpenTelemetry tracer implementation -->
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
-->
</dependencies>
----

View File

@@ -20,8 +20,6 @@
:autoconfig_path: {project-root}/spring-cloud-sleuth-autoconfigure
:api_path: {project-root}/spring-cloud-sleuth-api
:brave_path: {project-root}/spring-cloud-sleuth-brave
:otel_path: {project-root}/spring-cloud-sleuth-otel
:tests_path: {core_path}/tests
:common_tests_path: {tests_path}/common
:brave_tests_path: {tests_path}/brave
:otel_tests_path: {tests_path}/otel

View File

@@ -32,19 +32,6 @@
|spring.sleuth.messaging.rabbit.enabled | `true` | Enable tracing of RabbitMQ.
|spring.sleuth.mongodb.enabled | `true` | Enable tracing for MongoDb.
|spring.sleuth.opentracing.enabled | `true` | Enables OpenTracing support.
|spring.sleuth.otel.config.instrumentation-name | `org.springframework.cloud.spring-cloud-sleuth` | Instrumentation name to be used to find a Tracer.
|spring.sleuth.otel.config.instrumentation-version | | Instrumentation version to be used to find a Tracer.
|spring.sleuth.otel.config.max-attr-length | `0` | Returns the global default max length of string attribute value in characters.
|spring.sleuth.otel.config.max-attrs | `0` | Returns the global default max number of attributes per {@link Span}.
|spring.sleuth.otel.config.max-event-attrs | `0` | Returns the global default max number of attributes per event.
|spring.sleuth.otel.config.max-events | `0` | Returns the global default max number of events per {@link Span}.
|spring.sleuth.otel.config.max-link-attrs | `0` | Returns the global default max number of attributes per link.
|spring.sleuth.otel.config.max-links | `0` | Returns the global default max number of link entries per {@link Span}.
|spring.sleuth.otel.exporter.sleuth-span-filter.enabled | `true` | Enables Sleuth span filter.
|spring.sleuth.otel.log.exporter.enabled | `false` | Enable log exporter for OTel.
|spring.sleuth.otel.log.slf4j.enabled | `false` | Enable slf4j support for OTel.
|spring.sleuth.otel.propagation.composite-text-map-propagator.enabled | `true` | Enable a composite text map propagator that can combine multiple propagation types into a single text map propagator.
|spring.sleuth.otel.propagation.sleuth-baggage.enabled | `true` | Enable propagating baggage in a Sleuth compatible way (baggage key & value pair means e.g. a key & value HTTP pair).
|spring.sleuth.propagation.type | | Tracing context propagation types.
|spring.sleuth.quartz.enabled | `true` | Enable tracing for Quartz.
|spring.sleuth.reactor.decorate-on-each | `true` | When true decorates on each operator, will be less performing, but logging will always contain the tracing entries in each operator. When false decorates on last operator, will be more performing, but logging might not always contain the tracing entries. @deprecated use explicit value via {@link SleuthReactorProperties#instrumentationType}

View File

@@ -65,8 +65,7 @@ Need more details about {project-full-name}'s core features?
<<project-features.adoc#features-baggage, Baggage>>
* *Tracer Features:*
<<project-features.adoc#features-brave, OpenZipkin Brave>> |
<<project-features.adoc#features-otel, OpenTelemetry>>
<<project-features.adoc#features-brave, OpenZipkin Brave>>
* *Reporting Features:*
<<project-features.adoc#features-zipkin, Zipkin>> |

View File

@@ -15,11 +15,10 @@ Spring Cloud Sleuth provides API for distributed tracing solution for https://cl
It integrates out of the box with two tracer implementations:
* https://github.com/openzipkin/brave[OpenZipkin Brave]
* https://opentelemetry.io[OpenTelemetry SDK]
Spring Cloud Sleuth is able to trace your requests and messages so that you can correlate that communication to corresponding log entries.
You can also export the tracing information to an external system to visualize latency.
Spring Cloud Sleuth supports https://zipkin.io[OpenZipkin] compatible systems directly and various other ones via the OpenTelemetry integration.
Spring Cloud Sleuth supports https://zipkin.io[OpenZipkin] compatible systems directly.
[[getting-started-terminology]]
=== Terminology
@@ -193,36 +192,6 @@ To add the necessary dependencies, edit your `pom.xml` and add the `spring-boot-
</dependencies>
----
To use Sleuth with OpenTelemetry do the following.
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<dependencies>
<!-- Boot's Web support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<!-- Exclude Brave -->
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Add OpenTelemetry tracer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
</dependencies>
----
[[getting-started-first-application-code]]
=== Writing the Code

View File

@@ -55,60 +55,6 @@ dependencies {
----
====
[[how-to-set-up-sleuth-with-otel]]
== How to Set Up Sleuth with OpenTelemetry?
Add the Sleuth starter, exlcude Brave and add OpenTelemetry dependency to the classpath.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-sleuth") {
exclude group: 'org.springframework.cloud', module: 'spring-cloud-sleuth-brave'
}
}
----
====
[[how-to-set-up-sleuth-with-brave-zipkin-http]]
== How to Set Up Sleuth with Brave & Zipkin via HTTP?
@@ -156,65 +102,6 @@ dependencies {
----
====
[[how-to-set-up-sleuth-with-otel-zipkin-http]]
== How to Set Up Sleuth with OpenTelemetry & Zipkin via HTTP?
Add the Sleuth starter, exclude Brave, add OTel and Zipkin to the classpath.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-sleuth") {
exclude group: 'org.springframework.cloud', module: 'spring-cloud-sleuth-brave'
}
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
}
----
====
[[how-to-set-up-sleuth-with-brave-zipkin-messaging]]
== How to Set Up Sleuth with Brave & Zipkin via Messaging?
@@ -382,197 +269,6 @@ Also, you need to set the property `spring.zipkin.sender.type` property accordin
spring.zipkin.sender.type: activemq
----
[[how-to-set-up-sleuth-with-otel-zipkin-messaging]]
== How to Set Up Sleuth with OpenTelemetry & Zipkin via Messaging?
If you want to use RabbitMQ, Kafka or ActiveMQ instead of HTTP, add the `spring-rabbit`, `spring-kafka` or `org.apache.activemq:activemq-client` dependency.
The default destination name is `Zipkin`.
If using Kafka, you must add the Kafka dependency.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-sleuth") {
exclude group: 'org.springframework.cloud', module: 'spring-cloud-sleuth-brave'
}
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.kafka:spring-kafka"
}
----
====
Also, you need to set the property `spring.zipkin.sender.type` property accordingly:
[source,yaml]
----
spring.zipkin.sender.type: kafka
----
If you want Sleuth over RabbitMQ, add the `spring-cloud-sleuth-otel` (exclude `spring-cloud-sleuth-brave`), `spring-cloud-sleuth-zipkin` and `spring-rabbit` dependencies.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.amqp:spring-rabbit"
}
----
====
If you want Sleuth over RabbitMQ, add the `spring-cloud-sleuth-otel` (exclude `spring-cloud-sleuth-brave`), `spring-cloud-sleuth-zipkin` and `activemq-client` dependencies.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation("org.springframework.cloud:spring-cloud-starter-sleuth") {
exclude group: 'org.springframework.cloud', module: 'spring-cloud-sleuth-brave'
}
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.apache.activemq:activemq-client"
}
----
====
Also, you need to set the property `spring.zipkin.sender.type` property accordingly:
[source,yaml]
----
spring.zipkin.sender.type: activemq
----
[[how-to-see-spans-in-an-external-system]]
== How to See Spans in an External System?
@@ -601,42 +297,6 @@ If the boolean value in the section `[backend,0b6aaf642574edd3,0b6aaf642574edd3,
Up till Sleuth 3.0.0 the dependency `spring-cloud-starter-zipkin` included the `spring-cloud-starter-sleuth` dependency and the `spring-cloud-sleuth-zipkin` dependency.
With 3.0.0 `spring-cloud-starter-zipkin` was removed, so you need to change it to `spring-cloud-sleuth-zipkin`.
If you're working with OpenTelemetry you need to provide the dependency with your exporter.
For example if you want to use the OpenTelemetry Zipkin Exporter just add a dependency.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencies {
implementation "io.opentelemetry:opentelemetry-exporter-zipkin"
}
----
====
Then add the `SpanExporter` bean.
====
[source,java,indent=0]
----
@Bean SpanExporter zipkinExporter() {
return ZipkinSpanExporter.builder()
.setEndpoint("http://localhost/api/v2/spans")
.setServiceName("my-service")
.build();
}
----
====
[[connection-misconfiguration]]
=== Connection Misconfiguration
@@ -781,30 +441,21 @@ To use the provided defaults you can set the `spring.sleuth.propagation.type` pr
The value can be a list in which case you will propagate more tracing headers.
For Brave we support `AWS`, `B3`, `W3C` propagation types.
For OpenTelemetry we support `AWS`, `B3`, `JAEGER`, `W3C`, `OT_TRACER` and `W3C` propagation types.
If you want to provide a custom propagation mechanism set the `spring.sleuth.propagation.type` property to `CUSTOM` and implement your own bean (`Propagation.Factory` for Brave and `TextMapPropagator` for OpenTelemetry).
If you want to provide a custom propagation mechanism set the `spring.sleuth.propagation.type` property to `CUSTOM` and implement your own bean (`Propagation.Factory` for Brave).
Below you can find the examples:
====
[source,java,indent=0,subs="verbatim,attributes",role="primary"]
.Brave
[source,java,indent=0,subs="verbatim,attributes"]
----
@Component
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/BravePropagationTests.java[tags=custom_propagator,indent=0]
----
[source,java,indent=0,subs="verbatim,attributes",role="secondary"]
.OpenTelemetry
----
@Component
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/otel/OtelPropagationConfigurationTests.java[tags=custom_propagator,indent=0]
----
====
[[how-to-implement-own-tracer]]
== How to Implement My Own Tracer?
Spring Cloud Sleuth API contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave and OpenTelemetry implementations.
You can check how both tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge` and `org.springframework.cloud.sleuth.otel.bridge` modules respectively.
The project comes with OpenZipkin Brave implementation.
You can check how both tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge` module.

View File

@@ -13,7 +13,7 @@ In this section, we describe how to customize asynchronous communication with Sp
[[sleuth-async-annotation-integration]]
=== `@Async` Annotated methods
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
In Spring Cloud Sleuth, we instrument async-related components so that the tracing information is passed between threads.
You can disable this behavior by setting the value of `spring.sleuth.async.enabled` to `false`.
@@ -27,7 +27,7 @@ If you annotate your method with `@Async`, we automatically create a new Span wi
[[sleuth-async-scheduled-integration]]
=== `@Scheduled` Annotated Methods
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
In Spring Cloud Sleuth, we instrument scheduled method execution so that the tracing information is passed between threads.
You can disable this behavior by setting the value of `spring.sleuth.scheduled.enabled` to `false`.
@@ -42,7 +42,7 @@ If you want to skip span creation for some `@Scheduled` annotated classes, you c
[[sleuth-async-executor-service-integration]]
=== Executor, ExecutorService, and ScheduledExecutorService
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We provide `LazyTraceExecutor`, `TraceableExecutorService`, and `TraceableScheduledExecutorService`.
Those implementations create spans each time a new task is submitted, invoked, or scheduled.
@@ -85,7 +85,7 @@ Features from this section can be disabled by setting the `spring.sleuth.web.cli
[[sleuth-http-client-rest-template-integration]]
=== Synchronous Rest Template
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We inject a `RestTemplate` interceptor to ensure that all the tracing information is passed to the requests.
Each time a call is made, a new Span is created.
@@ -98,7 +98,7 @@ If you create a `RestTemplate` instance with a `new` keyword, the instrumentatio
[[sleuth-http-client-async-rest-template-integration]]
=== Asynchronous Rest Template
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
IMPORTANT: Starting with Sleuth `2.0.0`, we no longer register a bean of `AsyncRestTemplate` type.
It is up to you to create such a bean.
@@ -123,7 +123,7 @@ include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/inst
[[sleuth-http-client-webclient-integration]]
==== `WebClient`
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We inject a `ExchangeFilterFunction` implementation that creates a span and, through on-success and on-error callbacks, takes care of closing client-side spans.
@@ -135,7 +135,7 @@ If you create a `WebClient` instance with a `new` keyword, the instrumentation d
[[sleuth-http-client-traverson-integration]]
==== Traverson
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
If you use the https://docs.spring.io/spring-hateoas/docs/current/reference/html/#client.traverson[Traverson] library, you can inject a `RestTemplate` as a bean into your Traverson object.
Since `RestTemplate` is already intercepted, you get full support for tracing in your client.
@@ -162,7 +162,7 @@ To block these features, set `spring.sleuth.web.client.enabled` to `false`.
[[sleuth-http-client-netty-integration]]
==== Netty `HttpClient`
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We instrument the Netty's `HttpClient`.
@@ -174,7 +174,7 @@ If you create a `HttpClient` instance with a `new` keyword, the instrumentation
[[sleuth-http-client-userinfo-integration]]
==== `UserInfoRestTemplateCustomizer`
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We instrument the Spring Security's `UserInfoRestTemplateCustomizer`.
@@ -188,7 +188,7 @@ Features from this section can be disabled by setting the `spring.sleuth.web.ena
[[sleuth-http-server-http-filter-integration]]
=== HTTP Filter
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Through the `TracingFilter`, all sampled incoming requests result in creation of a Span.
You can configure which URIs you would like to skip by setting the `spring.sleuth.web.skipPattern` property.
@@ -208,7 +208,7 @@ To disable the filter that logs uncaught exceptions you can disable the
[[sleuth-http-server-handler-interceptor-integration]]
=== HandlerInterceptor
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Since we want the span names to be precise, we use a `TraceHandlerInterceptor` that either wraps an existing `HandlerInterceptor` or is added directly to the list of existing `HandlerInterceptors`.
The `TraceHandlerInterceptor` adds a special request attribute to the given `HttpServletRequest`.
@@ -219,14 +219,14 @@ In that case, please file an issue in Spring Cloud Sleuth.
[[sleuth-http-server-async-integration]]
=== Async Servlet support
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
If your controller returns a `Callable` or a `WebAsyncTask`, Spring Cloud Sleuth continues the existing span instead of creating a new one.
[[sleuth-http-server-webflux-integration]]
=== WebFlux support
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Through `TraceWebFilter`, all sampled incoming requests result in creation of a Span.
That Span's name is `http:` + the path to which the request was sent.
@@ -255,7 +255,7 @@ Features from this section can be disabled by setting the `spring.sleuth.messagi
[[sleuth-messaging-spring-integration-integration]]
=== Spring Integration
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Spring Cloud Sleuth integrates with https://projects.spring.io/spring-integration/[Spring Integration].
It creates spans for publish and subscribe events.
@@ -289,7 +289,7 @@ include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/inst
[[sleuth-messaging-spring-cloud-function-integration]]
=== Spring Cloud Function and Spring Cloud Stream
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Spring Cloud Sleuth can instrument Spring Cloud Function.
The way to achieve it is to provide a `Function` or `Consumer` or `Supplier` that takes in a `Message` as a parameter e.g. `Function<Message<String>, Message<Integer>>`.
@@ -352,7 +352,7 @@ IMPORTANT: We don't support baggage propagation for JMS
[[sleuth-openfeign-integration]]
== OpenFeign
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
By default, Spring Cloud Sleuth provides integration with Feign through `TraceFeignClientAutoConfiguration`.
You can disable it entirely by setting `spring.sleuth.feign.enabled` to `false`.
@@ -366,7 +366,7 @@ However, all the default instrumentation is still there.
[[sleuth-opentracing-integration]]
== OpenTracing
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
Spring Cloud Sleuth is compatible with https://opentracing.io/[OpenTracing].
If you have OpenTracing on the classpath, we automatically register the OpenTracing `Tracer` bean.
@@ -375,7 +375,7 @@ If you wish to disable this, set `spring.sleuth.opentracing.enabled` to `false`
[[sleuth-quartz-integration]]
== Quartz
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We instrument quartz jobs by adding Job/Trigger listeners to the Quartz Scheduler.
@@ -384,7 +384,7 @@ To turn off this feature, set the `spring.sleuth.quartz.enabled` property to `fa
[[sleuth-reactor-integration]]
== Reactor
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We have three modes of instrumenting reactor based applications that can be set via `spring.sleuth.reactor.instrumentation-type` property:
@@ -417,7 +417,7 @@ To disable Redis support, set the `spring.sleuth.redis.enabled` property to `fal
[[sleuth-runnablecallable-integration]]
== Runnable and Callable
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
If you wrap your logic in `Runnable` or `Callable`, you can wrap those classes in their Sleuth representative, as shown in the following example for `Runnable`:
@@ -545,7 +545,7 @@ https://github.com/yidongnan/grpc-spring-boot-starter[Grpc Spring Boot Starter]
[[sleuth-rxjava-integration]]
== RxJava
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
We registering a custom https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaschedulershook[`RxJavaSchedulersHook`] that wraps all `Action0` instances in their Sleuth representative, which is called `TraceAction`.
The hook either starts or continues a span, depending on whether tracing was already going on before the Action was scheduled.
@@ -559,7 +559,7 @@ IMPORTANT: The suggested approach to reactive programming and Sleuth is to use t
[[sleuth-circuitbreaker-integration]]
== Spring Cloud CircuitBreaker
This feature is available for both Brave and OpenTelemetry tracer implementation.
This feature is available for all tracer implementations.
If you have Spring Cloud CircuitBreaker on the classpath, we will wrap the passed command `Supplier` and the fallback `Function` in its trace representations.
In order to disable this instrumentation set `spring.sleuth.circuitbreaker.enabled` to `false`.

View File

@@ -21,7 +21,6 @@ To use the provided defaults you can set the `spring.sleuth.propagation.type` pr
The value can be a list in which case you will propagate more tracing headers.
For Brave we support `AWS`, `B3`, `W3C` propagation types.
For OpenTelemetry we support `AWS`, `B3`, `JAEGER`, `OT_TRACER` and `W3C` via the `io.opentelemetry:opentelemetry-extension-trace-propagators` dependency that you have to manually add to your classpath.
You can read more about how to provide custom context propagation in this "<<howto.adoc#how-to-change-context-propagation,how to section>>".
@@ -249,30 +248,6 @@ You can integrate with Brave and https://opentracing.io/[OpenTracing] via the
`io.opentracing.brave:brave-opentracing` bridge.
Just add it to the classpath and the OpenTracing `Tracer` will be set up automatically.
[[features-otel]]
== OpenTelemetry Tracer Integration
Spring Cloud Sleuth integrates with the OpenTelemetry (OTel in short) SDK tracer via the bridge that is available in the `spring-cloud-sleuth-otel` module.
In this section you can read about specific OTel integrations.
You can choose to use either Sleuth's API or the OpenTelemetry API directly in your code (e.g. either Sleuth's `Tracer` or OpenTelemetry's `Tracer`).
If you want to use this tracer implementation's API directly please read https://github.com/open-telemetry/opentelemetry-java[their documentation to learn more about it].
[[features-otel-logging]]
=== OpenTelemetry Logging Integration
We're providing an Slf4j integration via a `SpanProcessor` that injects to and removes entries (trace / span ids, baggage, tags etc.) from MDC. You can disable that via the `spring.sleuth.otel.log.slf4j.enabled=false` property.
If it's there on the classpath, we integrate with the `LoggingSpanExporter`.
You can disable that integration via the `spring.sleuth.otel.log.exporter.enabled=false` property.
[[features-otel-opentracing]]
=== OpenTelemetry Opentracing
You can integrate with OpenTelemetry and https://opentracing.io/[OpenTracing] via the
`io.opentelemetry:opentelemetry-opentracing-shim` bridge.
Just add it to the classpath and the OpenTracing `Tracer` will be set up automatically.
[[features-zipkin]]
== Sending Spans to Zipkin

View File

@@ -14,8 +14,8 @@ If you are starting out with {project-full-name}, you should probably read the
== Span Lifecycle with Spring Cloud Sleuth's API
Spring Cloud Sleuth Core in its `api` module contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave and OpenTelemetry implementations.
You can check how both tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge` and `org.springframework.cloud.sleuth.otel.bridge` modules respectively.
The project comes with OpenZipkin Brave implementation.
You can check how the tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge`.
The most commonly used interfaces are:

48
pom.xml
View File

@@ -49,7 +49,6 @@
<module>spring-cloud-sleuth-api</module>
<module>spring-cloud-sleuth-instrumentation</module>
<module>spring-cloud-sleuth-brave</module>
<module>spring-cloud-sleuth-otel</module>
<module>spring-cloud-sleuth-autoconfigure</module>
<module>tests</module>
<module>spring-cloud-sleuth-zipkin</module>
@@ -73,9 +72,6 @@
<spring-cloud-openfeign.version>3.0.0-SNAPSHOT</spring-cloud-openfeign.version>
<brave.version>5.13.2</brave.version>
<opentracing.version>0.32.0</opentracing.version>
<opentelemetry.version>0.11.0</opentelemetry.version>
<!-- From maven local -->
<opentelemetry-instrumentation.version>0.11.0</opentelemetry-instrumentation.version>
<spring-security-boot-autoconfigure.version>2.3.4.RELEASE</spring-security-boot-autoconfigure.version>
<disable.nohttp.checks>false</disable.nohttp.checks>
<okhttp.version>4.9.0</okhttp.version>
@@ -232,13 +228,6 @@
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
@@ -261,12 +250,6 @@
<artifactId>mockwebserver</artifactId>
<version>${mockwebserver.version}</version>
</dependency>
<!-- OpenTelemetry -->
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-api</artifactId>
<version>${opentelemetry-instrumentation.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
@@ -297,35 +280,6 @@
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>bintray-open-telemetry-maven</id>
<name>bintray</name>
<url>https://dl.bintray.com/open-telemetry/maven</url>
</repository>
<repository>
<snapshots>
<enabled>true</enabled>
</snapshots>
<id>bintray-open-telemetry-maven-snapshot</id>
<name>bintray</name>
<url>https://oss.jfrog.org/oss-snapshot-local/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<snapshots>
<enabled>false</enabled>
</snapshots>
<id>bintray-open-telemetry-maven</id>
<name>bintray-plugins</name>
<url>https://dl.bintray.com/open-telemetry/maven</url>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>spring</id>
@@ -341,7 +295,7 @@
<enabled>false</enabled>
</releases>
</repository>
<!-- BRAVE & OTEL -->
<!-- BRAVE -->
<repository>
<id>jfrog-snapshots</id>
<name>JFrog Snapshots</name>

View File

@@ -303,99 +303,12 @@
<optional>true</optional>
</dependency>
<!-- Otel -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-common</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-tracing</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-api</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-opentracing-shim</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>

View File

@@ -53,12 +53,7 @@ public class SleuthTracerProperties {
/**
* Picks the OpenZipkin Brave tracer implementation.
*/
BRAVE,
/**
* Picks the OpenTelemetry tracer implementation.
*/
OTEL
BRAVE
}

View File

@@ -22,7 +22,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.context.annotation.Configuration;
/**
@@ -36,7 +35,7 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(Tracer.class)
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthAsyncProperties.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceAsyncAutoConfiguration {
}

View File

@@ -26,7 +26,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceAsyncCustomizer;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
@@ -45,7 +44,7 @@ import org.springframework.scheduling.annotation.AsyncConfigurer;
@AutoConfigureBefore(TraceAsyncDefaultAutoConfiguration.class)
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
@AutoConfigureAfter(name = "org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration",
value = { BraveAutoConfiguration.class, OtelAutoConfiguration.class })
value = BraveAutoConfiguration.class)
public class TraceAsyncCustomAutoConfiguration implements BeanPostProcessor {
@Autowired

View File

@@ -36,7 +36,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.sleuth.SpanNamer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.async.LazyTraceExecutor;
import org.springframework.cloud.sleuth.instrument.async.TraceAsyncAspect;
import org.springframework.context.annotation.Bean;
@@ -61,7 +60,7 @@ import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
@EnableConfigurationProperties(SleuthAsyncProperties.class)
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceAsyncDefaultAutoConfiguration {
@Bean

View File

@@ -24,7 +24,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.circuitbreaker.TraceCircuitBreakerFactoryAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -41,7 +40,7 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnBean(Tracer.class)
@ConditionalOnProperty(value = "spring.sleuth.circuitbreaker.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthCircuitBreakerProperties.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceCircuitBreakerAutoConfiguration {
@Bean

View File

@@ -24,7 +24,6 @@ import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEven
import org.springframework.cloud.function.context.catalog.FunctionAroundWrapper;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.messaging.TraceFunctionAroundWrapper;
import org.springframework.cloud.sleuth.propagation.Propagator;
import org.springframework.context.annotation.Bean;
@@ -44,7 +43,7 @@ import org.springframework.messaging.support.MessageHeaderAccessor;
@ConditionalOnProperty(value = "spring.sleuth.function.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@ConditionalOnClass({ FunctionAroundWrapper.class, RefreshScopeRefreshedEvent.class })
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceFunctionAutoConfiguration {
@Bean

View File

@@ -29,7 +29,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.messaging.DefaultMessageSpanCustomizer;
import org.springframework.cloud.sleuth.instrument.messaging.MessageSpanCustomizer;
import org.springframework.cloud.sleuth.instrument.messaging.TracingChannelInterceptor;
@@ -58,8 +57,7 @@ import org.springframework.util.StringUtils;
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(GlobalChannelInterceptor.class)
@ConditionalOnBean(Tracer.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class,
TraceSpringMessagingAutoConfiguration.class })
@AutoConfigureAfter({ BraveAutoConfiguration.class, TraceSpringMessagingAutoConfiguration.class })
@ConditionalOnProperty(value = "spring.sleuth.messaging.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthIntegrationMessagingProperties.class)
@Conditional(TracingChannelInterceptorCondition.class)

View File

@@ -24,7 +24,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.messaging.DefaultMessageSpanCustomizer;
import org.springframework.cloud.sleuth.instrument.messaging.MessageSpanCustomizer;
import org.springframework.cloud.sleuth.instrument.messaging.TracingChannelInterceptor;
@@ -51,7 +50,7 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
@ConditionalOnClass(DelegatingWebSocketMessageBrokerConfiguration.class)
@ConditionalOnBean(Tracer.class)
@ConditionalOnProperty(value = "spring.sleuth.integration.websockets.enabled", matchIfMissing = true)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
class TraceWebSocketAutoConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired

View File

@@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.quartz.TracingJobListener;
import org.springframework.cloud.sleuth.propagation.Propagator;
import org.springframework.context.annotation.Bean;
@@ -43,7 +42,7 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean({ Tracer.class, Scheduler.class })
@ConditionalOnProperty(value = "spring.sleuth.quartz.enabled", matchIfMissing = true)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class, QuartzAutoConfiguration.class })
@AutoConfigureAfter({ BraveAutoConfiguration.class, QuartzAutoConfiguration.class })
public class TraceQuartzAutoConfiguration implements InitializingBean {
private final Scheduler scheduler;

View File

@@ -41,7 +41,6 @@ import org.springframework.cloud.context.scope.refresh.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
@@ -63,7 +62,7 @@ import static org.springframework.cloud.sleuth.autoconfig.instrument.reactor.Tra
@ConditionalOnProperty(value = "spring.sleuth.reactor.enabled", matchIfMissing = true)
@ConditionalOnClass(Mono.class)
@AutoConfigureAfter(name = "org.springframework.cloud.sleuth.autoconfig.instrument.web.TraceWebAutoConfiguration",
value = { BraveAutoConfiguration.class, OtelAutoConfiguration.class })
value = BraveAutoConfiguration.class)
@EnableConfigurationProperties(SleuthReactorProperties.class)
public class TraceReactorAutoConfiguration {

View File

@@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.rxjava.SleuthRxJavaSchedulersHook;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -44,7 +43,7 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnClass(RxJavaSchedulersHook.class)
@ConditionalOnProperty(value = "spring.sleuth.rxjava.schedulers.hook.enabled", matchIfMissing = true)
@EnableConfigurationProperties(SleuthRxJavaSchedulersProperties.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
class TraceRxJavaAutoConfiguration {
@Bean

View File

@@ -25,7 +25,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -43,7 +42,7 @@ import org.springframework.context.annotation.Configuration;
@ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@EnableConfigurationProperties(SleuthSchedulingProperties.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceSchedulingAutoConfiguration {
@Bean

View File

@@ -21,7 +21,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -37,7 +36,7 @@ import org.springframework.context.annotation.Import;
@ConditionalOnSleuthWeb
@Import({ SkipPatternConfiguration.class, TraceWebFluxConfiguration.class, TraceWebServletConfiguration.class })
@EnableConfigurationProperties(SleuthWebProperties.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceWebAutoConfiguration {
}

View File

@@ -30,7 +30,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.instrument.web.mvc.TracingAsyncClientHttpRequestInterceptor;
import org.springframework.context.annotation.Bean;
@@ -52,7 +51,7 @@ import org.springframework.web.client.AsyncRestTemplate;
@ConditionalOnProperty(value = "spring.sleuth.web.async.client.enabled", matchIfMissing = true)
@ConditionalOnClass(AsyncRestTemplate.class)
@ConditionalOnBean(Tracer.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceWebAsyncClientAutoConfiguration {
@Configuration(proxyBeanMethods = false)

View File

@@ -34,7 +34,6 @@ import org.springframework.cloud.gateway.filter.headers.HttpHeadersFilter;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.instrument.web.client.HttpClientBeanPostProcessor;
import org.springframework.cloud.sleuth.instrument.web.client.LazyTraceClientHttpRequestInterceptor;
@@ -67,7 +66,7 @@ import org.springframework.web.reactive.function.client.WebClient;
@ConditionalnOnSleuthWebClient
@ConditionalOnBean(Tracer.class)
@AutoConfigureBefore(HttpClientConfiguration.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
class TraceWebClientAutoConfiguration {
@Configuration(proxyBeanMethods = false)

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Conditional;
/**
* Conditional on OTel tracer.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(AnyTracerModePropertySetCondition.class)
public @interface ConditionalOnOtelEnabled {
}
final class AnyTracerModePropertySetCondition extends AnyNestedCondition {
private AnyTracerModePropertySetCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnProperty(value = "spring.sleuth.tracer.mode", havingValue = "AUTO", matchIfMissing = true)
static class OnAutoTracerMode {
}
@ConditionalOnProperty(value = "spring.sleuth.tracer.mode", havingValue = "OTEL")
static class OnConcreteTracerMode {
}
}

View File

@@ -1,146 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.TracerSdkProvider;
import io.opentelemetry.sdk.trace.config.TraceConfig;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.spi.TracerProviderFactorySdk;
import io.opentelemetry.spi.metrics.MeterProviderFactory;
import io.opentelemetry.spi.trace.TracerProviderFactory;
import org.springframework.beans.factory.ObjectProvider;
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.cloud.sleuth.autoconfig.SleuthAnnotationConfiguration;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthSpanFilterProperties;
import org.springframework.cloud.sleuth.autoconfig.SleuthTracerProperties;
import org.springframework.cloud.sleuth.autoconfig.TraceConfiguration;
import org.springframework.cloud.sleuth.internal.SleuthContextListener;
import org.springframework.cloud.sleuth.otel.bridge.OtelOpenTelemetry;
import org.springframework.cloud.sleuth.otel.bridge.SpanExporterCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable tracing via Spring Cloud Sleuth and OpenTelemetry SDK.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ io.opentelemetry.api.trace.Tracer.class, OtelProperties.class })
@ConditionalOnOtelEnabled
@ConditionalOnProperty(value = "spring.sleuth.enabled", matchIfMissing = true)
@ConditionalOnMissingBean(org.springframework.cloud.sleuth.Tracer.class)
@EnableConfigurationProperties({ OtelProperties.class, SleuthSpanFilterProperties.class, SleuthBaggageProperties.class,
SleuthTracerProperties.class })
@Import({ OtelBridgeConfiguation.class, OtelPropagationConfiguration.class, TraceConfiguration.class,
SleuthAnnotationConfiguration.class })
public class OtelAutoConfiguration {
@Bean
@ConditionalOnMissingBean
OpenTelemetry otel(TracerProviderFactory tracerProviderFactory, MeterProviderFactory meterProviderFactory,
TracerProvider tracerProvider, MeterProvider meterProvider, ContextPropagators contextPropagators) {
OtelOpenTelemetry otelOpenTelemetry = new OtelOpenTelemetry(tracerProviderFactory, meterProviderFactory,
tracerProvider, meterProvider, contextPropagators);
OpenTelemetry.set(otelOpenTelemetry);
OpenTelemetry.setGlobalPropagators(contextPropagators);
return otelOpenTelemetry;
}
@Bean
@ConditionalOnMissingBean
TracerProviderFactory otelTracerProviderFactory() {
return new TracerProviderFactorySdk();
}
@Bean
@ConditionalOnMissingBean
TracerProvider otelTracerProvider(TracerProviderFactory tracerProviderFactory) {
return tracerProviderFactory.create();
}
@Bean
@ConditionalOnMissingBean
MeterProviderFactory otelMeterProviderFactory() {
return OpenTelemetry::getGlobalMeterProvider;
}
@Bean
@ConditionalOnMissingBean
MeterProvider otelMeterProvider(MeterProviderFactory meterProviderFactory) {
return meterProviderFactory.create();
}
@Bean
@ConditionalOnMissingBean
TraceConfig otelTracerConfig(OtelProperties otelProperties, Sampler sampler) {
return TraceConfig.getDefault().toBuilder().setMaxLengthOfAttributeValues(otelProperties.getMaxAttrLength())
.setMaxNumberOfAttributes(otelProperties.getMaxAttrs())
.setMaxNumberOfAttributesPerEvent(otelProperties.getMaxEventAttrs())
.setMaxNumberOfAttributesPerLink(otelProperties.getMaxLinkAttrs())
.setMaxNumberOfEvents(otelProperties.getMaxEvents()).setMaxNumberOfLinks(otelProperties.getMaxLinks())
.setSampler(sampler).build();
}
@Bean
@ConditionalOnMissingBean
Tracer otelTracer(TracerProvider tracerProvider, ObjectProvider<TracerSdkProvider> tracerSdkObjectProvider,
TraceConfig traceConfig, OtelProperties otelProperties, ObjectProvider<List<SpanProcessor>> spanProcessors,
ObjectProvider<List<SpanExporter>> spanExporters, SpanExporterCustomizer spanExporterCustomizer) {
tracerSdkObjectProvider.ifAvailable(tracerSdkProvider -> {
List<SpanProcessor> processors = spanProcessors.getIfAvailable(ArrayList::new);
processors.addAll(spanExporters.getIfAvailable(ArrayList::new).stream()
.map(e -> SimpleSpanProcessor.builder(spanExporterCustomizer.customize(e)).build())
.collect(Collectors.toList()));
processors.forEach(tracerSdkProvider::addSpanProcessor);
tracerSdkProvider.updateActiveTraceConfig(traceConfig);
});
return tracerProvider.get(otelProperties.getInstrumentationName());
}
@Bean
@ConditionalOnMissingBean
Sampler otelSampler(OtelProperties otelProperties) {
return Sampler.traceIdRatioBased(otelProperties.getTraceIdRatioBased());
}
@Bean
SleuthContextListener sleuthContextListener() {
return new SleuthContextListener();
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.regex.Pattern;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.context.propagation.ContextPropagators;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.SamplerFunction;
import org.springframework.cloud.sleuth.SpanCustomizer;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.autoconfig.instrument.web.ConditionalOnSleuthWeb;
import org.springframework.cloud.sleuth.autoconfig.instrument.web.SleuthWebProperties;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.http.HttpRequest;
import org.springframework.cloud.sleuth.http.HttpRequestParser;
import org.springframework.cloud.sleuth.http.HttpResponseParser;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.instrument.web.HttpClientRequestParser;
import org.springframework.cloud.sleuth.instrument.web.HttpClientResponseParser;
import org.springframework.cloud.sleuth.instrument.web.HttpClientSampler;
import org.springframework.cloud.sleuth.instrument.web.HttpServerRequestParser;
import org.springframework.cloud.sleuth.instrument.web.HttpServerResponseParser;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
import org.springframework.cloud.sleuth.otel.bridge.OtelBaggageManager;
import org.springframework.cloud.sleuth.otel.bridge.OtelCurrentTraceContext;
import org.springframework.cloud.sleuth.otel.bridge.OtelHttpClientHandler;
import org.springframework.cloud.sleuth.otel.bridge.OtelHttpServerHandler;
import org.springframework.cloud.sleuth.otel.bridge.OtelPropagator;
import org.springframework.cloud.sleuth.otel.bridge.OtelSpanCustomizer;
import org.springframework.cloud.sleuth.otel.bridge.OtelTracer;
import org.springframework.cloud.sleuth.otel.bridge.SkipPatternSampler;
import org.springframework.cloud.sleuth.otel.bridge.SpanExporterCustomizer;
import org.springframework.cloud.sleuth.propagation.Propagator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.lang.Nullable;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable the bridge between Sleuth API and OpenTelemetry.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(OpenTelemetry.class)
@Import({ OtelLogConfiguration.class, OtelExporterConfiguration.class })
class OtelBridgeConfiguation {
@Bean
Tracer otelTracerBridge(io.opentelemetry.api.trace.Tracer tracer, ApplicationEventPublisher publisher,
CurrentTraceContext currentTraceContext, SleuthBaggageProperties sleuthBaggageProperties) {
return new OtelTracer(tracer, publisher, new OtelBaggageManager(currentTraceContext,
sleuthBaggageProperties.getRemoteFields(), sleuthBaggageProperties.getTagFields(), publisher));
}
// Both CurrentTraceContext & ContextStorageProvider
@Bean
@ConditionalOnMissingBean
OtelCurrentTraceContext otelCurrentTraceContext(ApplicationEventPublisher publisher) {
return new OtelCurrentTraceContext(publisher);
}
@Bean
SpanCustomizer otelSpanCustomizer() {
return new OtelSpanCustomizer();
}
@Bean
Propagator otelPropagator(ContextPropagators contextPropagators, io.opentelemetry.api.trace.Tracer tracer) {
return new OtelPropagator(contextPropagators, tracer);
}
@Bean
@ConditionalOnMissingBean
SpanExporterCustomizer noOpSleuthSpanFilterConverter() {
return new SpanExporterCustomizer() {
};
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnSleuthWeb
@EnableConfigurationProperties(SleuthWebProperties.class)
static class TraceOtelHttpBridgeConfiguration {
@Bean
HttpClientHandler otelHttpClientHandler(io.opentelemetry.api.trace.Tracer tracer,
@Nullable @HttpClientRequestParser HttpRequestParser httpClientRequestParser,
@Nullable @HttpClientResponseParser HttpResponseParser httpClientResponseParser,
SamplerFunction<HttpRequest> samplerFunction) {
return new OtelHttpClientHandler(tracer, httpClientRequestParser, httpClientResponseParser,
samplerFunction);
}
@Bean
HttpServerHandler otelHttpServerHandler(io.opentelemetry.api.trace.Tracer tracer,
@Nullable @HttpServerRequestParser HttpRequestParser httpServerRequestParser,
@Nullable @HttpServerResponseParser HttpResponseParser httpServerResponseParser,
ObjectProvider<SkipPatternProvider> skipPatternProvider) {
return new OtelHttpServerHandler(tracer, httpServerRequestParser, httpServerResponseParser,
skipPatternProvider.getIfAvailable(() -> () -> Pattern.compile("")));
}
@Bean
@ConditionalOnMissingBean(name = HttpClientSampler.NAME)
SamplerFunction<HttpRequest> defaultHttpClientSampler(SleuthWebProperties sleuthWebProperties) {
String skipPattern = sleuthWebProperties.getClient().getSkipPattern();
if (skipPattern == null) {
return SamplerFunction.deferDecision();
}
return new SkipPatternSampler(Pattern.compile(skipPattern));
}
}
}

View File

@@ -1,55 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.List;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.exporter.SpanFilter;
import org.springframework.cloud.sleuth.otel.bridge.CompositeSpanExporter;
import org.springframework.cloud.sleuth.otel.bridge.SpanExporterCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable OpenTelemetry exporters.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(SpanExporter.class)
@EnableConfigurationProperties(OtelExporterProperties.class)
class OtelExporterConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.sleuth.otel.exporter.sleuth-span-filter.enabled", matchIfMissing = true)
SpanExporterCustomizer sleuthSpanFilterConverter(List<SpanFilter> spanFilters) {
return new SpanExporterCustomizer() {
@Override
public SpanExporter customize(SpanExporter spanExporter) {
return new CompositeSpanExporter(spanExporter, spanFilters);
}
};
}
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Sleuth settings for OpenTelemetry.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@ConfigurationProperties("spring.sleuth.otel.exporter")
public class OtelExporterProperties {
private SleuthSpanFilter sleuthSpanFilter = new SleuthSpanFilter();
public SleuthSpanFilter getSleuthSpanFilter() {
return this.sleuthSpanFilter;
}
public void setSleuthSpanFilter(SleuthSpanFilter sleuthSpanFilter) {
this.sleuthSpanFilter = sleuthSpanFilter;
}
/**
* Integrations with core Sleuth handler mechanism.
*/
public static class SleuthSpanFilter {
/**
* Enables Sleuth span filter.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import io.opentelemetry.exporter.logging.LoggingSpanExporter;
import org.slf4j.MDC;
import org.springframework.beans.factory.BeanFactory;
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.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.otel.bridge.Slf4jBaggageSpanProcessor;
import org.springframework.cloud.sleuth.otel.bridge.Slf4jSpanProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable logging configuration via Spring Cloud Sleuth and
* OpenTelemetry SDK.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(OtelLogProperties.class)
class OtelLogConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MDC.class)
@ConditionalOnProperty(value = "spring.sleuth.otel.log.slf4j.enabled", matchIfMissing = true)
static class Slf4jConfiguration {
@Bean
@ConditionalOnMissingBean
Slf4jSpanProcessor otelSlf4jSpanProcessor() {
return new Slf4jSpanProcessor();
}
@Bean
@ConditionalOnMissingBean
Slf4jBaggageSpanProcessor otelSlf4jBaggageSpanProcessor(BeanFactory beanFactory,
SleuthBaggageProperties baggageProperties) {
return new Slf4jBaggageSpanProcessor(baggageProperties.getCorrelationFields(), beanFactory);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(LoggingSpanExporter.class)
@ConditionalOnProperty("spring.sleuth.otel.log.exporter.enabled")
static class LoggingExporterConfiguration {
@Bean
LoggingSpanExporter otelLoggingSpanExporter() {
return new LoggingSpanExporter();
}
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Sleuth settings for OpenTelemetry.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@ConfigurationProperties("spring.sleuth.otel.log")
public class OtelLogProperties {
private Exporter exporter = new Exporter();
private Slf4j slf4j = new Slf4j();
public Exporter getExporter() {
return this.exporter;
}
public void setExporter(Exporter exporter) {
this.exporter = exporter;
}
public Slf4j getSlf4j() {
return this.slf4j;
}
public void setSlf4j(Slf4j slf4j) {
this.slf4j = slf4j;
}
public static class Exporter {
/**
* Enable log exporter for OTel.
*/
private boolean enabled = false;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
public static class Slf4j {
/**
* Enable slf4j support for OTel.
*/
private boolean enabled;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View File

@@ -1,126 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.DefaultContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.BaggageManager;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.otel.propagation.BaggageTextMapPropagator;
import org.springframework.cloud.sleuth.otel.propagation.CompositeTextMapPropagator;
import org.springframework.cloud.sleuth.otel.propagation.PropagationType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable propagation configuration via Spring Cloud Sleuth and
* OpenTelemetry SDK.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ SleuthPropagationProperties.class, OtelPropagationProperties.class })
class OtelPropagationConfiguration {
@Bean
@ConditionalOnMissingBean
ContextPropagators otelContextPropagators(ObjectProvider<List<TextMapPropagator>> propagators) {
List<TextMapPropagator> mapPropagators = propagators.getIfAvailable(ArrayList::new);
if (mapPropagators.isEmpty()) {
return noOpContextPropagator();
}
DefaultContextPropagators.Builder builder = DefaultContextPropagators.builder();
mapPropagators.forEach(builder::addTextMapPropagator);
return builder.build();
}
private ContextPropagators noOpContextPropagator() {
return () -> new TextMapPropagator() {
@Override
public List<String> fields() {
return Collections.emptyList();
}
@Override
public <C> void inject(Context context, @Nullable C carrier, Setter<C> setter) {
}
@Override
public <C> Context extract(Context context, @Nullable C carrier, Getter<C> getter) {
return context;
}
};
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "spring.sleuth.otel.propagation.composite-text-map-propagator.enabled",
matchIfMissing = true)
static class PropagatorsConfiguration {
@Bean
TextMapPropagator compositeTextMapPropagator(BeanFactory beanFactory, SleuthPropagationProperties properties) {
return new CompositeTextMapPropagator(beanFactory, properties.getType());
}
}
@Configuration(proxyBeanMethods = false)
@Conditional(B3PresentOrPropertyEnabledCondition.class)
static class BaggagePropagatorConfiguration {
@Bean
TextMapPropagator baggageTextMapPropagator(SleuthBaggageProperties properties, BaggageManager baggageManager) {
return new BaggageTextMapPropagator(properties.getRemoteFields(), baggageManager);
}
}
static class B3PresentOrPropertyEnabledCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String type = context.getEnvironment()
.getProperty("spring.sleuth.propagation.type", PropagationType.B3.toString()).toLowerCase();
boolean sleuthBaggageEnabled = context.getEnvironment()
.getProperty("spring.sleuth.otel.propagation.sleuth-baggage.enabled", Boolean.class, false);
return type.contains(PropagationType.B3.toString().toLowerCase()) || sleuthBaggageEnabled;
}
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Sleuth settings for OpenTelemetry propagation.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@ConfigurationProperties("spring.sleuth.otel.propagation")
public class OtelPropagationProperties {
private SleuthBaggage sleuthBaggage = new SleuthBaggage();
public SleuthBaggage getSleuthBaggage() {
return this.sleuthBaggage;
}
public void setSleuthBaggage(SleuthBaggage sleuthBaggage) {
this.sleuthBaggage = sleuthBaggage;
}
public static class SleuthBaggage {
/**
* Enables default B3 Sleuth Baggage propagation. This will be automatically
* turned on when B3 propagation type gets picked.
*/
private boolean enabled;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View File

@@ -1,150 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.sdk.trace.config.TraceConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Sleuth settings for OpenTelemetry.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@ConfigurationProperties("spring.sleuth.otel.config")
public class OtelProperties {
/**
* Instrumentation name to be used to find a Tracer.
*/
private String instrumentationName = "org.springframework.cloud.spring-cloud-sleuth";
/**
* Instrumentation version to be used to find a Tracer.
*/
private String instrumentationVersion;
/**
* Sets the global default {@code Sampler} value.
*/
private double traceIdRatioBased = 0.1;
/**
* Returns the global default max number of attributes per {@link Span}.
*/
private int maxAttrs = TraceConfig.getDefault().getMaxNumberOfAttributes();
/**
* Returns the global default max number of events per {@link Span}.
*/
private int maxEvents = TraceConfig.getDefault().getMaxNumberOfEvents();
/**
* Returns the global default max number of link entries per {@link Span}.
*/
private int maxLinks = TraceConfig.getDefault().getMaxNumberOfLinks();
/**
* Returns the global default max number of attributes per event.
*/
private int maxEventAttrs = TraceConfig.getDefault().getMaxNumberOfAttributesPerEvent();
/**
* Returns the global default max number of attributes per link.
*/
private int maxLinkAttrs = TraceConfig.getDefault().getMaxNumberOfAttributesPerLink();
/**
* Returns the global default max length of string attribute value in characters.
*/
private int maxAttrLength = TraceConfig.getDefault().getMaxLengthOfAttributeValues();
public String getInstrumentationName() {
return this.instrumentationName;
}
public void setInstrumentationName(String instrumentationName) {
this.instrumentationName = instrumentationName;
}
public String getInstrumentationVersion() {
return instrumentationVersion;
}
public void setInstrumentationVersion(String instrumentationVersion) {
this.instrumentationVersion = instrumentationVersion;
}
public double getTraceIdRatioBased() {
return this.traceIdRatioBased;
}
public void setTraceIdRatioBased(int traceIdRatioBased) {
this.traceIdRatioBased = traceIdRatioBased;
}
public int getMaxAttrs() {
return this.maxAttrs;
}
public void setMaxAttrs(int maxAttrs) {
this.maxAttrs = maxAttrs;
}
public int getMaxEvents() {
return this.maxEvents;
}
public void setMaxEvents(int maxEvents) {
this.maxEvents = maxEvents;
}
public int getMaxLinks() {
return this.maxLinks;
}
public void setMaxLinks(int maxLinks) {
this.maxLinks = maxLinks;
}
public int getMaxEventAttrs() {
return this.maxEventAttrs;
}
public void setMaxEventAttrs(int maxEventAttrs) {
this.maxEventAttrs = maxEventAttrs;
}
public int getMaxLinkAttrs() {
return this.maxLinkAttrs;
}
public void setMaxLinkAttrs(int maxLinkAttrs) {
this.maxLinkAttrs = maxLinkAttrs;
}
public int getMaxAttrLength() {
return this.maxAttrLength;
}
public void setMaxAttrLength(int maxAttrLength) {
this.maxAttrLength = maxAttrLength;
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.sleuth.otel.propagation.PropagationType;
/**
* Sleuth propagation types.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
@ConfigurationProperties("spring.sleuth.propagation")
public class SleuthPropagationProperties {
/**
* Tracing context propagation types.
*/
private List<PropagationType> type = Collections.singletonList(PropagationType.B3);
public List<PropagationType> getType() {
return this.type;
}
public void setType(List<PropagationType> type) {
this.type = type;
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel.instrument.opentracing;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.opentracingshim.OpenTracingShim;
import io.opentracing.Tracer;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
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.cloud.sleuth.autoconfig.SleuthOpentracingProperties;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} to enable tracing via Opentracing.
*
* @author Spencer Gibb
* @author Marcin Grzejszczak
* @since 2.0.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.opentracing.enabled", matchIfMissing = true)
@ConditionalOnBean(OpenTelemetry.class)
@ConditionalOnClass(OpenTracingShim.class)
@AutoConfigureAfter(OtelAutoConfiguration.class)
@EnableConfigurationProperties(SleuthOpentracingProperties.class)
public class OtelOpentracingAutoConfiguration {
@Bean
@ConditionalOnMissingBean
Tracer sleuthOpenTracing(OpenTelemetry openTelemetry) {
return OpenTracingShim.createTracerShim(openTelemetry);
}
}

View File

@@ -45,7 +45,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.commons.util.InetUtils;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.zipkin2.DefaultEndpointLocator;
import org.springframework.cloud.sleuth.zipkin2.DefaultZipkinRestTemplateCustomizer;
import org.springframework.cloud.sleuth.zipkin2.EndpointLocator;
@@ -76,9 +75,8 @@ import org.springframework.web.client.RestTemplate;
@ConditionalOnClass({ Sender.class, EndpointLocator.class })
@ConditionalOnProperty(value = { "spring.sleuth.enabled", "spring.zipkin.enabled" }, matchIfMissing = true)
@AutoConfigureAfter(name = "org.springframework.cloud.autoconfigure.RefreshAutoConfiguration")
@AutoConfigureBefore({ OtelAutoConfiguration.class, BraveAutoConfiguration.class })
@Import({ ZipkinSenderConfigurationImportSelector.class, ZipkinBraveConfiguration.class,
ZipkinOtelConfiguration.class })
@AutoConfigureBefore(BraveAutoConfiguration.class)
@Import({ ZipkinSenderConfigurationImportSelector.class, ZipkinBraveConfiguration.class })
public class ZipkinAutoConfiguration {
/**

View File

@@ -1,76 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.zipkin2;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.exporter.zipkin.ZipkinSpanExporter;
import zipkin2.reporter.Sender;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.zipkin2.DefaultZipkinRestTemplateCustomizer;
import org.springframework.cloud.sleuth.zipkin2.EndpointLocator;
import org.springframework.cloud.sleuth.zipkin2.ZipkinProperties;
import org.springframework.cloud.sleuth.zipkin2.ZipkinRestTemplateCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} enables reporting to Zipkin via HTTP.
*
* The {@link ZipkinRestTemplateCustomizer} allows you to customize the
* {@link RestTemplate} that is used to send Spans to Zipkin. Its default implementation -
* {@link DefaultZipkinRestTemplateCustomizer} adds the GZip compression.
*
* @author Spencer Gibb
* @author Tim Ysewyn
* @since 1.0.0
* @see ZipkinRestTemplateCustomizer
* @see DefaultZipkinRestTemplateCustomizer
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = { "spring.sleuth.enabled", "spring.zipkin.enabled" }, matchIfMissing = true)
@ConditionalOnClass({ Tracer.class, EndpointLocator.class })
class ZipkinOtelConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ZipkinSpanExporter.class)
static class ZipkinConfiguration {
@Bean
@ConditionalOnMissingBean
ZipkinSpanExporter otelZipkinSpanExporter(ZipkinProperties zipkinProperties,
@Qualifier(ZipkinAutoConfiguration.SENDER_BEAN_NAME) Sender sender, Environment env) {
return ZipkinSpanExporter.builder().setEndpoint(zipkinProperties.getBaseUrl() + "api/v2/spans")
.setSender(sender).setEncoder(zipkinProperties.getEncoder())
.setServiceName(
StringUtils.hasText(zipkinProperties.getService().getName())
? zipkinProperties.getService().getName()
: env.getProperty("spring.application.name", env.getProperty(
"spring.zipkin.service.name", ZipkinSpanExporter.DEFAULT_SERVICE_NAME)))
.build();
}
}
}

View File

@@ -35,18 +35,6 @@
"description": "Enable instrumenting of Spring Cloud Function and Spring Cloud Function based projects (e.g. Spring Cloud Stream).",
"defaultValue": true
},
{
"name": "spring.sleuth.otel.propagation.sleuth-baggage.enabled",
"type": "java.lang.Boolean",
"description": "Enable propagating baggage in a Sleuth compatible way (baggage key & value pair means e.g. a key & value HTTP pair).",
"defaultValue": true
},
{
"name": "spring.sleuth.otel.propagation.composite-text-map-propagator.enabled",
"type": "java.lang.Boolean",
"description": "Enable a composite text map propagator that can combine multiple propagation types into a single text map propagator.",
"defaultValue": true
},
{
"name": "spring.sleuth.integration.websockets.enabled",
"type": "java.lang.Boolean",

View File

@@ -25,8 +25,6 @@ org.springframework.cloud.sleuth.autoconfig.brave.instrument.messaging.BraveMess
org.springframework.cloud.sleuth.autoconfig.brave.instrument.opentracing.BraveOpentracingAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.brave.instrument.redis.BraveRedisAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.brave.instrument.mongodb.BraveMongoDbAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.otel.instrument.opentracing.OtelOpentracingAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.zipkin2.ZipkinAutoConfiguration
# Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=\

View File

@@ -25,7 +25,6 @@ import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.autoconfig.instrument.web.ConditionalOnSleuthWeb;
import org.springframework.cloud.sleuth.autoconfig.instrument.web.client.ConditionalnOnSleuthWebClient;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.propagation.Propagator;
@@ -44,7 +43,7 @@ import org.springframework.context.annotation.Import;
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.sleuth.noop.enabled")
@AutoConfigureBefore({ BraveAutoConfiguration.class, OtelAutoConfiguration.class })
@AutoConfigureBefore(BraveAutoConfiguration.class)
@Import(TraceConfiguration.class)
public class TraceNoOpAutoConfiguration {

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.brave;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packagesOf = ArchitectureTests.class)
public class ArchitectureTests {
@ArchTest
public static final ArchRule should_not_contain_any_reference_to_other_tracers = noClasses().should()
.dependOnClassesThat().resideInAnyPackage("..org.springframework.cloud.sleuth.otel..",
"..org.springframework.cloud.sleuth.autoconfig.otel..", "..io.opentelemetry..");
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packagesOf = ArchitectureTests.class)
public class ArchitectureTests {
@ArchTest
public static final ArchRule should_not_contain_any_reference_to_other_tracers = noClasses().should()
.dependOnClassesThat().resideInAnyPackage("..org.springframework.cloud.sleuth.brave..",
"..org.springframework.cloud.sleuth.autoconfig.brave..", "brave..");
}

View File

@@ -1,194 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapPropagator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration;
import org.springframework.cloud.sleuth.otel.propagation.CompositeTextMapPropagator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
class OtelPropagationConfigurationTests {
@Test
void should_start_a_composite_text_map_propagator_with_b3_as_default() {
ApplicationContextRunner runner = new ApplicationContextRunner()
.withPropertyValues("spring.sleuth.tracer.mode=OTEL").withUserConfiguration(Config.class);
runner.run(context -> {
assertThat(context).hasNotFailed();
CompositeTextMapPropagator propagator = context.getBean(CompositeTextMapPropagator.class);
assertThat(propagator.fields()).contains("X-B3-TraceId");
});
}
@Test
void should_start_a_composite_text_map_propagator_with_a_single_propagation_type() {
ApplicationContextRunner runner = new ApplicationContextRunner().withUserConfiguration(Config.class)
.withPropertyValues("spring.sleuth.tracer.mode=OTEL")
.withPropertyValues("spring.sleuth.propagation.type=w3c");
runner.run(context -> {
assertThat(context).hasNotFailed();
CompositeTextMapPropagator propagator = context.getBean(CompositeTextMapPropagator.class);
assertThat(propagator.fields()).doesNotContain("X-B3-TraceId").contains("traceparent");
});
}
@Test
void should_start_a_composite_text_map_propagator_with_multiple_propagation_types() {
ApplicationContextRunner runner = new ApplicationContextRunner().withUserConfiguration(Config.class)
.withPropertyValues("spring.sleuth.tracer.mode=OTEL")
.withPropertyValues("spring.sleuth.propagation.type=b3,w3c");
runner.run(context -> {
assertThat(context).hasNotFailed();
CompositeTextMapPropagator propagator = context.getBean(CompositeTextMapPropagator.class);
assertThat(propagator.fields()).contains("X-B3-TraceId", "traceparent");
});
}
@Test
void should_start_a_composite_text_map_propagator_with_custom_propagation_types() {
ApplicationContextRunner runner = new ApplicationContextRunner()
.withUserConfiguration(CustomPropagatorConfig.class)
.withPropertyValues("spring.sleuth.tracer.mode=OTEL")
.withPropertyValues("spring.sleuth.propagation.type=custom");
runner.run(context -> {
assertThat(context).hasNotFailed();
CompositeTextMapPropagator propagator = context.getBean(CompositeTextMapPropagator.class);
assertThat(propagator.fields()).doesNotContain("myCustomTraceId", "myCustomSpanId", "X-B3-TraceId",
"traceparent");
});
}
@Test
void should_inject_and_extract_from_custom_propagator() {
CustomPropagator customPropagator = new CustomPropagator();
Map<String, String> carrier = carrierWithTracingData();
// Extraction
Context extract = customPropagator.extract(Context.current(), carrier,
new TextMapPropagator.Getter<Map<String, String>>() {
@Override
public Iterable<String> keys(Map<String, String> carrier) {
return carrier.keySet();
}
@Nullable
@Override
public String get(@Nullable Map<String, String> carrier, String key) {
return carrier.get(key);
}
});
Span spanFromContext = Span.fromContext(extract);
assertThat(spanFromContext.getSpanContext().getTraceIdAsHexString())
.isEqualTo("ff000000000000000000000000000041");
assertThat(spanFromContext.getSpanContext().getSpanIdAsHexString()).isEqualTo("ff00000000000041");
// Injection
Map<String, String> emptyMap = new HashMap<>();
customPropagator.inject(extract, emptyMap, Map::put);
assertThat(emptyMap).containsEntry("myCustomTraceId", "ff000000000000000000000000000041")
.containsEntry("myCustomSpanId", "ff00000000000041");
}
private Map<String, String> carrierWithTracingData() {
Map<String, String> carrier = new HashMap<>();
carrier.put("myCustomTraceId", "ff000000000000000000000000000041");
carrier.put("myCustomSpanId", "ff00000000000041");
return carrier;
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
MongoAutoConfiguration.class, QuartzAutoConfiguration.class })
static class Config {
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
MongoAutoConfiguration.class, QuartzAutoConfiguration.class })
static class CustomPropagatorConfig {
@Bean
TextMapPropagator myCustomPropagator() {
return new CustomPropagator();
}
}
}
// tag::custom_propagator[]
class CustomPropagator implements TextMapPropagator {
@Override
public List<String> fields() {
return Arrays.asList("myCustomTraceId", "myCustomSpanId");
}
@Override
public <C> void inject(Context context, C carrier, Setter<C> setter) {
SpanContext spanContext = Span.fromContext(context).getSpanContext();
if (!spanContext.isValid()) {
return;
}
setter.set(carrier, "myCustomTraceId", spanContext.getTraceIdAsHexString());
setter.set(carrier, "myCustomSpanId", spanContext.getSpanIdAsHexString());
}
@Override
public <C> Context extract(Context context, C carrier, Getter<C> getter) {
String traceParent = getter.get(carrier, "myCustomTraceId");
if (traceParent == null) {
return Span.getInvalid().storeInContext(context);
}
String spanId = getter.get(carrier, "myCustomSpanId");
return Span.wrap(SpanContext.createFromRemoteParent(traceParent, spanId, TraceFlags.getSampled(),
TraceState.builder().build())).storeInContext(context);
}
}
// end::custom_propagator[]

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel;
import io.opentelemetry.api.trace.Tracer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.gateway.config.GatewayAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayClassPathWarningAutoConfiguration;
import org.springframework.cloud.gateway.config.GatewayMetricsAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
class TraceOtelAutoConfigurationTests {
@Test
void should_start_context_with_otel_tracer_when_sleuth_enabled() {
ApplicationContextRunner runner = new ApplicationContextRunner()
.withPropertyValues("spring.sleuth.tracer.mode=OTEL").withUserConfiguration(Config.class);
runner.run(context -> assertThat(context).hasNotFailed().hasSingleBean(Tracer.class));
}
@Test
void should_start_context_without_tracer_when_sleuth_disabled() {
ApplicationContextRunner runner = new ApplicationContextRunner().withUserConfiguration(Config.class)
.withPropertyValues("spring.sleuth.enabled=false");
runner.run(context -> assertThat(context).hasNotFailed().doesNotHaveBean(Tracer.class));
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,
MongoAutoConfiguration.class, QuartzAutoConfiguration.class })
static class Config {
}
}

View File

@@ -1,52 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.autoconfig.otel.instrument.opentracing;
import io.opentelemetry.api.trace.Tracer;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.cloud.sleuth.autoconfig.otel.OtelAutoConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
class OtelBraveOpentracingAutoConfigurationTests {
@Test
void should_start_context_with_otel_tracer_when_sleuth_enabled() {
ApplicationContextRunner runner = withAutoConfiguration();
runner.run(context -> assertThat(context).hasNotFailed().hasSingleBean(Tracer.class)
.hasSingleBean(io.opentracing.Tracer.class));
}
private ApplicationContextRunner withAutoConfiguration() {
return new ApplicationContextRunner().withPropertyValues("spring.sleuth.tracer.mode=OTEL").withConfiguration(
AutoConfigurations.of(OtelAutoConfiguration.class, OtelOpentracingAutoConfiguration.class));
}
@Test
void should_start_context_without_tracer_when_sleuth_disabled() {
ApplicationContextRunner runner = withAutoConfiguration()
.withPropertyValues("spring.sleuth.opentracing.enabled=false");
runner.run(context -> assertThat(context).hasNotFailed().hasSingleBean(Tracer.class)
.doesNotHaveBean(io.opentracing.Tracer.class));
}
}

View File

@@ -50,19 +50,6 @@ public class ZipkinSamplerTests {
});
}
@Test
void should_set_sampler_to_non_off_when_zipkin_handler_on_classpath_for_otel() {
ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.sleuth.tracer.mode=OTEL")
.withConfiguration(AutoConfigurations.of(TestConfig.class));
contextRunner.run(context -> {
io.opentelemetry.sdk.trace.samplers.Sampler sampler = context
.getBean(io.opentelemetry.sdk.trace.samplers.Sampler.class);
BDDAssertions.then(sampler).isNotSameAs(io.opentelemetry.sdk.trace.samplers.Sampler.alwaysOff());
});
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration(exclude = { GatewayClassPathWarningAutoConfiguration.class, GatewayAutoConfiguration.class,
GatewayMetricsAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class,

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2013-2019 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.cloud.sleuth.instrument.web.client;
import java.io.IOException;
import brave.spring.web.TracingClientHttpRequestInterceptor;
import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import static org.mockito.BDDMockito.then;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
class LazyTracingClientHttpRequestInterceptorTests {
@Test
void should_not_retrieve_bean_from_context_when_context_is_not_ready() throws IOException {
BeanFactory beanFactory = mock(BeanFactory.class);
LazyTracingClientHttpRequestInterceptor interceptor = new LazyTracingClientHttpRequestInterceptor(beanFactory);
interceptor.intercept(mock(HttpRequest.class), new byte[0], mock(ClientHttpRequestExecution.class));
then(beanFactory).should(never()).getBean(TracingClientHttpRequestInterceptor.class);
}
@Test
void should_retrieve_bean_from_context_when_context_is_ready() throws IOException {
BeanFactory beanFactory = mock(BeanFactory.class);
ClientHttpRequestInterceptor requestInterceptor = mock(ClientHttpRequestInterceptor.class);
LazyTracingClientHttpRequestInterceptor interceptor = new LazyTracingClientHttpRequestInterceptor(beanFactory) {
@Override
ClientHttpRequestInterceptor interceptor() {
return requestInterceptor;
}
@Override
boolean isContextUnusable() {
return false;
}
};
interceptor.intercept(mock(HttpRequest.class), new byte[0], mock(ClientHttpRequestExecution.class));
then(requestInterceptor).should().intercept(BDDMockito.any(HttpRequest.class), BDDMockito.any(byte[].class),
BDDMockito.any(ClientHttpRequestExecution.class));
}
}

View File

@@ -34,7 +34,6 @@
<brave.version>5.13.2</brave.version>
<brave.opentracing.version>0.37.4</brave.opentracing.version>
<grpc.spring.boot.version>4.2.2</grpc.spring.boot.version>
<opentelemetry.version>0.11.0</opentelemetry.version>
</properties>
<dependencyManagement>
<dependencies>
@@ -58,11 +57,6 @@
<artifactId>spring-cloud-sleuth-brave</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
@@ -98,14 +92,6 @@
</exclusion>
</exclusions>
</dependency>
<!-- OpenTelemetry -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-bom</artifactId>
<version>${opentelemetry.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- GRPC -->
<dependency>
<groupId>io.github.lognet</groupId>

View File

@@ -1,162 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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.
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Sleuth OTel</name>
<description>Spring Cloud Sleuth OpenTelemetry</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-instrumentation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-common</artifactId>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-sdk-tracing</artifactId>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>opentelemetry-instrumentation-api</artifactId>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
<exclusion>
<groupId>io.opentelemetry.instrumentation</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-logging</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-opentracing-shim</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>io.opentelemetry</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>fast</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>4</forkCount>
<reuseForks>true</reuseForks>
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
/**
* Stores spans in a queue.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class ArrayListSpanProcessor implements SpanProcessor, SpanExporter {
Queue<SpanData> spans = new LinkedBlockingQueue<>(50);
@Override
public void onStart(Context parent, ReadWriteSpan span) {
}
@Override
public boolean isStartRequired() {
return false;
}
@Override
public void onEnd(ReadableSpan span) {
this.spans.add(span.toSpanData());
}
@Override
public boolean isEndRequired() {
return true;
}
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode flush() {
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode shutdown() {
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode forceFlush() {
return CompletableResultCode.ofSuccess();
}
public SpanData takeLocalSpan() {
return this.spans.poll();
}
public Queue<SpanData> spans() {
return this.spans;
}
public void clear() {
this.spans.clear();
}
@Override
public String toString() {
return "ArrayListSpanProcessor{" + "spans=" + spans + '}';
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Arrays;
import io.opentelemetry.api.internal.Utils;
/**
* Copied from io.opentelemetry.api.trace.BigendianEncoding.
*/
final class BigendianEncoding {
static final int LONG_BYTES = Long.SIZE / Byte.SIZE;
static final int BYTE_BASE16 = 2;
static final int LONG_BASE16 = BYTE_BASE16 * LONG_BYTES;
private static final String ALPHABET = "0123456789abcdef";
private static final int ASCII_CHARACTERS = 128;
private static final byte[] DECODING = buildDecodingArray();
private BigendianEncoding() {
}
private static byte[] buildDecodingArray() {
byte[] decoding = new byte[ASCII_CHARACTERS];
Arrays.fill(decoding, (byte) -1);
for (int i = 0; i < ALPHABET.length(); i++) {
char c = ALPHABET.charAt(i);
decoding[c] = (byte) i;
}
return decoding;
}
/**
* Returns the {@code long} value whose base16 representation is stored in the first
* 16 chars of {@code chars} starting from the {@code offset}.
* @param chars the base16 representation of the {@code long}.
*/
static long longFromBase16String(CharSequence chars) {
return longFromBase16String(chars, 0);
}
/**
* Returns the {@code long} value whose base16 representation is stored in the first
* 16 chars of {@code chars} starting from the {@code offset}.
* @param chars the base16 representation of the {@code long}.
*/
static long longFromBase16String(CharSequence chars, int offset) {
Utils.checkArgument(chars.length() >= offset + LONG_BASE16, "chars too small");
return (decodeByte(chars.charAt(offset), chars.charAt(offset + 1)) & 0xFFL) << 56
| (decodeByte(chars.charAt(offset + 2), chars.charAt(offset + 3)) & 0xFFL) << 48
| (decodeByte(chars.charAt(offset + 4), chars.charAt(offset + 5)) & 0xFFL) << 40
| (decodeByte(chars.charAt(offset + 6), chars.charAt(offset + 7)) & 0xFFL) << 32
| (decodeByte(chars.charAt(offset + 8), chars.charAt(offset + 9)) & 0xFFL) << 24
| (decodeByte(chars.charAt(offset + 10), chars.charAt(offset + 11)) & 0xFFL) << 16
| (decodeByte(chars.charAt(offset + 12), chars.charAt(offset + 13)) & 0xFFL) << 8
| (decodeByte(chars.charAt(offset + 14), chars.charAt(offset + 15)) & 0xFFL);
}
private static byte decodeByte(char hi, char lo) {
Utils.checkArgument(lo < ASCII_CHARACTERS && DECODING[lo] != -1, "invalid character " + lo);
Utils.checkArgument(hi < ASCII_CHARACTERS && DECODING[hi] != -1, "invalid character " + hi);
int decoded = DECODING[hi] << 4 | DECODING[lo];
return (byte) decoded;
}
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.cloud.sleuth.exporter.SpanFilter;
/**
* Composes multiple {@link SpanFilter} into a single {@link SpanExporter}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class CompositeSpanExporter implements io.opentelemetry.sdk.trace.export.SpanExporter {
private final io.opentelemetry.sdk.trace.export.SpanExporter delegate;
private final List<SpanFilter> filters;
public CompositeSpanExporter(io.opentelemetry.sdk.trace.export.SpanExporter delegate, List<SpanFilter> filters) {
this.delegate = delegate;
this.filters = filters;
}
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
return this.delegate.export(spans.stream().filter(this::shouldProcess).collect(Collectors.toList()));
}
private boolean shouldProcess(SpanData span) {
for (SpanFilter exporter : this.filters) {
if (!exporter.isExportable(OtelFinishedSpan.fromOtel(span))) {
return false;
}
}
return true;
}
@Override
public CompletableResultCode flush() {
return this.delegate.flush();
}
@Override
public CompletableResultCode shutdown() {
return this.delegate.shutdown();
}
}

View File

@@ -1,172 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
/**
* OpenTelemetry implementation of a {@link BaggageInScope}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelBaggageInScope implements BaggageInScope {
private final OtelBaggageManager otelBaggageManager;
private final CurrentTraceContext currentTraceContext;
private final ApplicationEventPublisher publisher;
private final List<String> tagFields;
private final AtomicReference<Entry> entry = new AtomicReference<>();
private final AtomicReference<Scope> scope = new AtomicReference<>();
OtelBaggageInScope(OtelBaggageManager otelBaggageManager, CurrentTraceContext currentTraceContext,
ApplicationEventPublisher publisher, List<String> tagFields, Entry entry) {
this.otelBaggageManager = otelBaggageManager;
this.currentTraceContext = currentTraceContext;
this.publisher = publisher;
this.tagFields = tagFields;
this.entry.set(entry);
}
@Override
public String name() {
return entry().getKey();
}
@Override
public String get() {
return this.otelBaggageManager.currentBaggage().getEntryValue(entry().getKey());
}
@Override
public String get(TraceContext traceContext) {
Entry entry = this.otelBaggageManager.getEntry((OtelTraceContext) traceContext, entry().getKey());
if (entry == null) {
return null;
}
return entry.getValue();
}
@Override
public BaggageInScope set(String value) {
return doSet(this.currentTraceContext.context(), value);
}
private BaggageInScope doSet(TraceContext context, String value) {
Context current = Context.current();
Span currentSpan = Span.current();
io.opentelemetry.api.baggage.Baggage baggage;
if (context != null) {
OtelTraceContext ctx = (OtelTraceContext) context;
Context storedCtx = ctx.context();
Baggage fromContext = Baggage.fromContext(storedCtx);
baggage = fromContext.toBuilder().setParent(current)
.put(entry().getKey(), value, entry().getEntryMetadata()).build();
current = baggage.storeInContext(current);
ctx.updateContext(current);
}
else {
baggage = Baggage.builder().put(entry().getKey(), value, entry().getEntryMetadata()).build();
}
Context withBaggage = current.with(baggage);
this.scope.set(withBaggage.makeCurrent());
if (this.tagFields.stream().map(String::toLowerCase).anyMatch(s -> s.equals(entry().getKey()))) {
currentSpan.setAttribute(entry().getKey(), value);
}
this.publisher.publishEvent(new BaggageChanged(this, baggage, entry().getKey(), value));
Entry previous = entry();
this.entry.set(new Entry(previous.getKey(), value, previous.getEntryMetadata()));
return this;
}
private Entry entry() {
return this.entry.get();
}
@Override
public BaggageInScope set(TraceContext traceContext, String value) {
return doSet(traceContext, value);
}
@Override
public BaggageInScope makeCurrent() {
close();
Entry entry = entry();
Scope scope = Baggage.builder().put(entry.getKey(), entry.getValue(), entry.getEntryMetadata()).build()
.makeCurrent();
this.scope.set(scope);
return this;
}
@Override
public void close() {
Scope scope = this.scope.get();
if (scope != null) {
this.scope.set(null);
scope.close();
}
}
static class BaggageChanged extends ApplicationEvent {
/**
* Baggage with the new entry.
*/
Baggage baggage;
/**
* Baggage entry name.
*/
String name;
/**
* Baggage entry value.
*/
String value;
BaggageChanged(OtelBaggageInScope source, Baggage baggage, String name, String value) {
super(source);
this.baggage = baggage;
this.name = name;
this.value = value;
}
@Override
public String toString() {
return "BaggageChanged{" + "name='" + name + '\'' + ", value='" + value + '\'' + '}';
}
}
}

View File

@@ -1,265 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.baggage.BaggageBuilder;
import io.opentelemetry.api.baggage.BaggageConsumer;
import io.opentelemetry.api.baggage.EntryMetadata;
import io.opentelemetry.context.Context;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.BaggageManager;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.ApplicationEventPublisher;
/**
* OpenTelemetry implementation of a {@link BaggageManager}. Doesn't implement an
* interface cause {@link Tracer} already implements it.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelBaggageManager implements BaggageManager {
private final CurrentTraceContext currentTraceContext;
private final List<String> remoteFields;
private final List<String> tagFields;
private final ApplicationEventPublisher publisher;
public OtelBaggageManager(CurrentTraceContext currentTraceContext, List<String> remoteFields,
List<String> tagFields, ApplicationEventPublisher publisher) {
this.currentTraceContext = currentTraceContext;
this.remoteFields = remoteFields;
this.tagFields = tagFields;
this.publisher = publisher;
}
@Override
public Map<String, String> getAllBaggage() {
Map<String, String> baggage = new HashMap<>();
currentBaggage().getEntries().forEach(entry -> baggage.put(entry.getKey(), entry.getValue()));
return baggage;
}
CompositeBaggage currentBaggage() {
OtelTraceContext traceContext = (OtelTraceContext) currentTraceContext.context();
Context context = Context.current();
Deque<Context> stack = new ArrayDeque<>();
if (traceContext != null) {
stack.addFirst(traceContext.context());
}
stack.addFirst(context);
return new CompositeBaggage(stack);
}
@Override
public BaggageInScope getBaggage(String name) {
Entry entry = getBaggage(name, currentBaggage());
return createNewEntryIfMissing(name, entry);
}
BaggageInScope createNewEntryIfMissing(String name, Entry entry) {
if (entry == null) {
return createBaggage(name);
}
return otelBaggage(entry);
}
private Entry getBaggage(String name, io.opentelemetry.api.baggage.Baggage baggage) {
return entryForName(name, baggage);
}
@Override
public BaggageInScope getBaggage(TraceContext traceContext, String name) {
OtelTraceContext context = (OtelTraceContext) traceContext;
// TODO: Refactor
Deque<Context> stack = new ArrayDeque<>();
stack.addFirst(Context.current());
stack.addFirst(context.context());
Context ctx = removeFirst(stack);
Entry entry = null;
while (ctx != null && entry == null) {
entry = getBaggage(name, Baggage.fromContext(ctx));
ctx = removeFirst(stack);
}
return createNewEntryIfMissing(name, entry);
}
Entry getEntry(OtelTraceContext traceContext, String name) {
OtelTraceContext context = traceContext;
Context ctx = context.context();
return getBaggage(name, Baggage.fromContext(ctx));
}
Context removeFirst(Deque<Context> stack) {
return stack.isEmpty() ? null : stack.removeFirst();
}
private Entry entryForName(String name, io.opentelemetry.api.baggage.Baggage baggage) {
return Entry.fromBaggage(baggage).stream().filter(e -> e.getKey().toLowerCase().equals(name.toLowerCase()))
.findFirst().orElse(null);
}
private BaggageInScope otelBaggage(Entry entry) {
return new OtelBaggageInScope(this, this.currentTraceContext, this.publisher, this.tagFields, entry);
}
@Override
public BaggageInScope createBaggage(String name) {
return createBaggage(name, "");
}
@Override
public BaggageInScope createBaggage(String name, String value) {
BaggageInScope baggageInScope = baggageWithValue(name, "");
return baggageInScope.set(value);
}
private BaggageInScope baggageWithValue(String name, String value) {
List<String> remoteFieldsFields = this.remoteFields;
boolean remoteField = remoteFieldsFields.stream().map(String::toLowerCase)
.anyMatch(s -> s.equals(name.toLowerCase()));
EntryMetadata entryMetadata = EntryMetadata.create(propagationString(remoteField));
Entry entry = new Entry(name, value, entryMetadata);
return new OtelBaggageInScope(this, this.currentTraceContext, this.publisher, this.tagFields, entry);
}
private String propagationString(boolean remoteField) {
// TODO: [OTEL] Magic strings
String propagation = "";
if (remoteField) {
propagation = "propagation=unlimited";
}
return propagation;
}
}
class CompositeBaggage implements io.opentelemetry.api.baggage.Baggage {
private final Deque<Context> stack;
private final Collection<Entry> entries;
CompositeBaggage(Deque<Context> stack) {
this.stack = stack;
this.entries = getEntries();
}
Collection<Entry> getEntries() {
// parent baggage foo=bar
// child baggage foo=baz - we want the last one to override the previous one
Map<String, Entry> map = new HashMap<>();
Iterator<Context> iterator = this.stack.descendingIterator();
while (iterator.hasNext()) {
Context next = iterator.next();
Baggage baggage = Baggage.fromContext(next);
baggage.forEach((key, value, metadata) -> map.put(key, new Entry(key, value, metadata)));
}
return map.values();
}
@Override
public int size() {
return this.entries.size();
}
@Override
public void forEach(BaggageConsumer consumer) {
this.entries.forEach(entry -> consumer.accept(entry.getKey(), entry.getValue(), entry.getEntryMetadata()));
}
@Override
public String getEntryValue(String entryKey) {
return this.entries.stream().filter(entry -> entryKey.equals(entry.getKey())).map(Entry::getValue).findFirst()
.orElse(null);
}
@Override
public BaggageBuilder toBuilder() {
return Baggage.builder();
}
}
class Entry {
final String key;
final String value;
final EntryMetadata entryMetadata;
Entry(String key, String value, EntryMetadata entryMetadata) {
this.key = key;
this.value = value;
this.entryMetadata = entryMetadata;
}
String getKey() {
return this.key;
}
String getValue() {
return this.value;
}
EntryMetadata getEntryMetadata() {
return this.entryMetadata;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Entry entry = (Entry) o;
return Objects.equals(this.key, entry.key) && Objects.equals(this.value, entry.value)
&& Objects.equals(this.entryMetadata, entry.entryMetadata);
}
@Override
public int hashCode() {
return Objects.hash(this.key, this.value, this.entryMetadata);
}
static List<Entry> fromBaggage(Baggage baggage) {
List<Entry> list = new ArrayList<>(baggage.size());
baggage.forEach((key, value, metadata) -> list.add(new Entry(key, value, metadata)));
return list;
}
}

View File

@@ -1,186 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.ContextStorage;
import io.opentelemetry.context.ContextStorageProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.lang.Nullable;
/**
* OpenTelemetry implementation of a {@link CurrentTraceContext}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelCurrentTraceContext implements CurrentTraceContext, ContextStorageProvider {
private static final Log log = LogFactory.getLog(OtelCurrentTraceContext.class);
private final ApplicationEventPublisher publisher;
private final ContextStorageProvider delegate = ContextStorage::get;
public OtelCurrentTraceContext(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Override
public TraceContext context() {
Span currentSpan = Span.current();
if (Span.getInvalid().equals(currentSpan)) {
return null;
}
if (currentSpan instanceof SpanFromSpanContext) {
return new OtelTraceContext((SpanFromSpanContext) currentSpan);
}
return new OtelTraceContext(currentSpan);
}
@Override
public Scope newScope(TraceContext context) {
OtelTraceContext otelTraceContext = (OtelTraceContext) context;
if (otelTraceContext == null) {
return io.opentelemetry.context.Scope::noop;
}
Context current = Context.current();
Context old = otelTraceContext.context();
Span currentSpan = Span.fromContext(current);
Span oldSpan = Span.fromContext(otelTraceContext.context());
SpanContext spanContext = otelTraceContext.delegate;
boolean sameSpan = currentSpan.getSpanContext().equals(oldSpan.getSpanContext())
&& currentSpan.getSpanContext().equals(spanContext);
Baggage currentBaggage = Baggage.fromContext(current);
Baggage oldBaggage = Baggage.fromContext(old);
boolean sameBaggage = sameBaggage(currentBaggage, oldBaggage);
if (sameSpan && sameBaggage) {
return io.opentelemetry.context.Scope::noop;
}
SpanFromSpanContext fromContext = new SpanFromSpanContext(((OtelTraceContext) context).span, spanContext,
otelTraceContext);
Context newContext = old.with(fromContext).with(currentBaggage.toBuilder().setParent(old).build());
io.opentelemetry.context.Scope attach = get().attach(newContext);
return attach::close;
}
private boolean sameBaggage(Baggage currentBaggage, Baggage oldBaggage) {
Set<Entry> entries = new HashSet<>(Entry.fromBaggage(currentBaggage));
entries.removeAll(Entry.fromBaggage(oldBaggage));
return entries.isEmpty();
}
@Override
public Scope maybeScope(TraceContext context) {
return newScope(context);
}
@Override
public <C> Callable<C> wrap(Callable<C> task) {
return get().current().wrap(task);
}
@Override
public Runnable wrap(Runnable task) {
return get().current().wrap(task);
}
@Override
public Executor wrap(Executor delegate) {
return get().current().wrap(delegate);
}
@Override
public ExecutorService wrap(ExecutorService delegate) {
return get().current().wrap(delegate);
}
@Override
public ContextStorage get() {
ContextStorage threadLocalStorage = this.delegate.get();
return new ContextStorage() {
@Override
public io.opentelemetry.context.Scope attach(Context toAttach) {
io.opentelemetry.context.Scope scope = threadLocalStorage.attach(toAttach);
Span currentSpan = Span.fromContext(Context.current());
if (scope != io.opentelemetry.context.Scope.noop()) {
Span fromContext = Span.fromContext(toAttach);
publisher.publishEvent(new ScopeChanged(this, fromContext));
}
return () -> {
publisher.publishEvent(new OtelCurrentTraceContext.ScopeClosed(this));
publisher.publishEvent(new ScopeChanged(this, currentSpan));
scope.close();
};
}
@Override
public Context current() {
return threadLocalStorage.current();
}
};
}
static class ScopeChanged extends ApplicationEvent {
/**
* Span corresponding to the changed scope. Might be {@code null}.
*/
final Span span;
/**
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with which
* the event is associated (never {@code null})
* @param span corresponding trace context
*/
ScopeChanged(Object source, @Nullable Span span) {
super(source);
this.span = span;
}
}
static class ScopeClosed extends ApplicationEvent {
/**
* Create a new {@code ApplicationEvent}.
* @param source the object on which the event initially occurred or with which
* the event is associated (never {@code null})
*/
ScopeClosed(Object source) {
super(source);
}
}
}

View File

@@ -1,154 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.AbstractMap;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import io.opentelemetry.api.common.AttributeConsumer;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.sdk.trace.data.SpanData;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
/**
* OpenTelemetry implementation of a {@link FinishedSpan}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelFinishedSpan implements FinishedSpan {
private final SpanData spanData;
private final Map<String, String> tags = new HashMap<>();
OtelFinishedSpan(SpanData spanData) {
this.spanData = spanData;
}
static FinishedSpan fromOtel(SpanData span) {
return new OtelFinishedSpan(span);
}
@Override
public String getName() {
return this.spanData.getName();
}
@Override
public long getStartTimestamp() {
return this.spanData.getStartEpochNanos();
}
@Override
public long getEndTimestamp() {
return this.spanData.getEndEpochNanos();
}
@Override
public Map<String, String> getTags() {
if (this.tags.isEmpty()) {
this.spanData.getAttributes().forEach(new AttributeConsumer() {
@Override
public <T> void accept(AttributeKey<T> key, T value) {
tags.put(key.getKey(), String.valueOf(value));
}
});
}
return this.tags;
}
@Override
public Collection<Map.Entry<Long, String>> getEvents() {
return this.spanData.getEvents().stream()
.map(e -> new AbstractMap.SimpleEntry<>(e.getEpochNanos(), e.getName())).collect(Collectors.toList());
}
@Override
public String getSpanId() {
return this.spanData.getSpanId();
}
@Override
public String getParentId() {
return this.spanData.getParentSpanId();
}
@Override
public String getRemoteIp() {
return getTags().get("net.peer.name");
}
@Override
public int getRemotePort() {
return Integer.valueOf(getTags().get("net.peer.port"));
}
@Override
public String getTraceId() {
return this.spanData.getTraceId();
}
@Override
public Throwable getError() {
Attributes attributes = this.spanData.getEvents().stream().filter(e -> e.getName().equals("exception"))
.findFirst().map(e -> e.getAttributes()).orElse(null);
if (attributes != null) {
return new AssertingThrowable(attributes);
}
return null;
}
@Override
public Span.Kind getKind() {
if (this.spanData.getKind() == io.opentelemetry.api.trace.Span.Kind.INTERNAL) {
return null;
}
return Span.Kind.valueOf(this.spanData.getKind().name());
}
@Override
public String getRemoteServiceName() {
return this.spanData.getAttributes().get(AttributeKey.stringKey("peer.service"));
}
@Override
public String toString() {
return "SpanDataToReportedSpan{" + "spanData=" + spanData + ", tags=" + tags + '}';
}
static class AssertingThrowable extends Throwable {
/**
* Attritbues set on the span.
*/
public final Attributes attributes;
AssertingThrowable(Attributes attributes) {
super(attributes.get(AttributeKey.stringKey("exception.message")));
this.attributes = attributes;
}
}
}

View File

@@ -1,193 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.net.URI;
import java.net.URISyntaxException;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Scope;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.sleuth.SamplerFunction;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.http.HttpClientRequest;
import org.springframework.cloud.sleuth.http.HttpClientResponse;
import org.springframework.cloud.sleuth.http.HttpRequest;
import org.springframework.cloud.sleuth.http.HttpRequestParser;
import org.springframework.cloud.sleuth.http.HttpResponseParser;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* OpenTelemetry implementation of a {@link HttpClientHandler}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelHttpClientHandler extends HttpClientTracer<HttpClientRequest, HttpClientRequest, HttpClientResponse>
implements HttpClientHandler {
private static final Log log = LogFactory.getLog(OtelHttpClientHandler.class);
private final HttpRequestParser httpClientRequestParser;
private final HttpResponseParser httpClientResponseParser;
private final SamplerFunction<HttpRequest> samplerFunction;
public OtelHttpClientHandler(Tracer tracer, @Nullable HttpRequestParser httpClientRequestParser,
@Nullable HttpResponseParser httpClientResponseParser, SamplerFunction<HttpRequest> samplerFunction) {
super(tracer);
this.httpClientRequestParser = httpClientRequestParser;
this.httpClientResponseParser = httpClientResponseParser;
this.samplerFunction = samplerFunction;
}
@Override
public Span handleSend(HttpClientRequest request) {
if (Boolean.FALSE.equals(this.samplerFunction.trySample(request))) {
if (log.isDebugEnabled()) {
log.debug("The sampler function filtered this request, will return an invalid span");
}
return OtelSpan.fromOtel(io.opentelemetry.api.trace.Span.getInvalid());
}
io.opentelemetry.api.trace.Span span = startSpan(request);
return span(request, span);
}
@Override
public Span handleSend(HttpClientRequest request, TraceContext parent) {
if (Boolean.FALSE.equals(this.samplerFunction.trySample(request))) {
if (log.isDebugEnabled()) {
log.debug("Returning an invalid span since url [" + request.path() + "] is on a list of urls to skip");
}
return OtelSpan.fromOtel(io.opentelemetry.api.trace.Span.getInvalid());
}
io.opentelemetry.api.trace.Span span = parent != null ? ((OtelTraceContext) parent).span() : null;
if (span == null) {
return span(request, startSpan(request));
}
try (Scope scope = span.makeCurrent()) {
io.opentelemetry.api.trace.Span withParent = startSpan(request);
return span(request, withParent);
}
}
private Span span(HttpClientRequest request, io.opentelemetry.api.trace.Span span) {
try (Scope scope = startScope(span, request)) {
if (span.isRecording()) {
String remoteIp = request.remoteIp();
if (StringUtils.hasText(remoteIp)) {
span.setAttribute("net.peer.ip", remoteIp);
}
span.setAttribute("net.peer.port", request.remotePort());
}
return OtelSpan.fromOtel(span);
}
}
@Override
protected io.opentelemetry.api.trace.Span onRequest(io.opentelemetry.api.trace.Span span,
HttpClientRequest httpClientRequest) {
io.opentelemetry.api.trace.Span afterRequest = super.onRequest(span, httpClientRequest);
if (this.httpClientRequestParser != null) {
Span fromOtel = OtelSpan.fromOtel(afterRequest);
this.httpClientRequestParser.parse(httpClientRequest, fromOtel.context(), fromOtel);
}
String path = httpClientRequest.path();
if (path != null) {
span.setAttribute("http.path", path);
}
return afterRequest;
}
@Override
protected io.opentelemetry.api.trace.Span onResponse(io.opentelemetry.api.trace.Span span,
HttpClientResponse httpClientResponse) {
io.opentelemetry.api.trace.Span afterResponse = super.onResponse(span, httpClientResponse);
if (this.httpClientResponseParser != null) {
Span fromOtel = OtelSpan.fromOtel(afterResponse);
this.httpClientResponseParser.parse(httpClientResponse, fromOtel.context(), fromOtel);
}
return afterResponse;
}
@Override
public void handleReceive(HttpClientResponse response, Span span) {
if (OtelSpan.toOtel(span).equals(io.opentelemetry.api.trace.Span.getInvalid())) {
if (log.isDebugEnabled()) {
log.debug("Not doing anything cause the span is invalid");
}
return;
}
io.opentelemetry.api.trace.Span otel = OtelSpan.toOtel(span);
if (response.error() != null) {
if (log.isDebugEnabled()) {
log.debug("There was an error, will finish span [" + otel + "] exceptionally");
}
endExceptionally(otel, response, response.error());
}
else {
if (log.isDebugEnabled()) {
log.debug("There was no error, will finish span [" + otel + "] in a standard way");
}
end(otel, response);
}
}
@Override
protected String method(HttpClientRequest httpClientRequest) {
return httpClientRequest.method();
}
@Override
protected URI url(HttpClientRequest httpClientRequest) throws URISyntaxException {
return URI.create(httpClientRequest.url());
}
@Override
protected Integer status(HttpClientResponse httpClientResponse) {
return httpClientResponse.statusCode();
}
@Override
protected String requestHeader(HttpClientRequest httpClientRequest, String s) {
return httpClientRequest.header(s);
}
@Override
protected String responseHeader(HttpClientResponse httpClientResponse, String s) {
return httpClientResponse.header(s);
}
@Override
protected TextMapPropagator.Setter<HttpClientRequest> getSetter() {
return HttpClientRequest::header;
}
@Override
protected String getInstrumentationName() {
return "org.springframework.cloud.sleuth";
}
}

View File

@@ -1,179 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.net.URI;
import java.util.regex.Pattern;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.instrumentation.api.tracer.HttpServerTracer;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.http.HttpRequestParser;
import org.springframework.cloud.sleuth.http.HttpResponseParser;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.http.HttpServerRequest;
import org.springframework.cloud.sleuth.http.HttpServerResponse;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
import org.springframework.util.StringUtils;
/**
* OpenTelemetry implementation of a {@link HttpServerHandler}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelHttpServerHandler
extends HttpServerTracer<HttpServerRequest, HttpServerResponse, HttpServerRequest, HttpServerRequest>
implements HttpServerHandler {
private final HttpRequestParser httpServerRequestParser;
private final HttpResponseParser httpServerResponseParser;
private final Pattern pattern;
public OtelHttpServerHandler(Tracer tracer, HttpRequestParser httpServerRequestParser,
HttpResponseParser httpServerResponseParser, SkipPatternProvider skipPatternProvider) {
super(tracer);
this.httpServerRequestParser = httpServerRequestParser;
this.httpServerResponseParser = httpServerResponseParser;
this.pattern = skipPatternProvider.skipPattern();
}
@Override
public Span handleReceive(HttpServerRequest request) {
String url = request.path();
boolean shouldSkip = !StringUtils.isEmpty(url) && this.pattern.matcher(url).matches();
if (shouldSkip) {
return OtelSpan.fromOtel(io.opentelemetry.api.trace.Span.getInvalid());
}
Context context = startSpan(request, request, request.method());
return OtelSpan.fromOtel(io.opentelemetry.api.trace.Span.fromContext(context), context);
}
@Override
public void handleSend(HttpServerResponse response, Span span) {
Throwable throwable = response.error();
io.opentelemetry.api.trace.Span otel = OtelSpan.toOtel(span);
parseResponse(span, response);
if (throwable == null) {
end(otel, response);
}
else {
endExceptionally(otel, throwable, response);
}
}
private void parseResponse(Span span, HttpServerResponse response) {
if (this.httpServerResponseParser != null) {
this.httpServerResponseParser.parse(response, span.context(), span);
}
}
@Override
protected void onConnectionAndRequest(io.opentelemetry.api.trace.Span span, HttpServerRequest connection,
HttpServerRequest request) {
super.onConnectionAndRequest(span, connection, request);
if (this.httpServerRequestParser != null) {
Span fromOtel = OtelSpan.fromOtel(span);
this.httpServerRequestParser.parse(request, fromOtel.context(), fromOtel);
}
}
@Override
protected void onRequest(io.opentelemetry.api.trace.Span span, HttpServerRequest request) {
super.onRequest(span, request);
String path = request.path();
if (StringUtils.hasText(path)) {
span.setAttribute("http.path", path);
}
}
@Override
public Context getServerContext(HttpServerRequest request) {
Object context = request.getAttribute(CONTEXT_ATTRIBUTE);
return context instanceof Context ? (Context) context : null;
}
@Override
protected Integer peerPort(HttpServerRequest request) {
return toUri(request).getPort();
}
@Override
protected String peerHostIP(HttpServerRequest request) {
return toUri(request).getHost();
}
@Override
protected String flavor(HttpServerRequest request, HttpServerRequest request2) {
return toUri(request).getScheme();
}
@Override
protected TextMapPropagator.Getter<HttpServerRequest> getGetter() {
return new TextMapPropagator.Getter<HttpServerRequest>() {
@Override
public Iterable<String> keys(HttpServerRequest carrier) {
return carrier.headerNames();
}
@Override
public String get(HttpServerRequest carrier, String key) {
return carrier.header(key);
}
};
}
@Override
protected String url(HttpServerRequest request) {
return request.url();
}
protected URI toUri(HttpServerRequest request) {
return URI.create(request.url());
}
@Override
protected String method(HttpServerRequest request) {
return request.method();
}
@Override
protected String requestHeader(HttpServerRequest request, String s) {
return request.header(s);
}
@Override
protected int responseStatus(HttpServerResponse httpServerResponse) {
return httpServerResponse.statusCode();
}
@Override
protected void attachServerContext(Context context, HttpServerRequest request) {
request.setAttribute(CONTEXT_ATTRIBUTE, context);
}
@Override
protected String getInstrumentationName() {
return "org.springframework.cloud.sleuth";
}
}

View File

@@ -1,127 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Objects;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.spi.metrics.MeterProviderFactory;
import io.opentelemetry.spi.trace.TracerProviderFactory;
/**
* Sleuth implementation of a {@link OpenTelemetry}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelOpenTelemetry implements OpenTelemetry {
private final TracerProviderFactory tracerProviderFactory;
private final MeterProviderFactory meterProviderFactory;
private final TracerProvider tracerProvider;
private final MeterProvider meterProvider;
private final ContextPropagators contextPropagators;
public OtelOpenTelemetry(TracerProviderFactory tracerProviderFactory, MeterProviderFactory meterProviderFactory,
TracerProvider tracerProvider, MeterProvider meterProvider, ContextPropagators contextPropagators) {
this.tracerProviderFactory = tracerProviderFactory;
this.meterProviderFactory = meterProviderFactory;
this.tracerProvider = tracerProvider;
this.meterProvider = meterProvider;
this.contextPropagators = contextPropagators;
}
@Override
public TracerProvider getTracerProvider() {
return this.tracerProvider;
}
@Override
public MeterProvider getMeterProvider() {
return this.meterProvider;
}
@Override
public ContextPropagators getPropagators() {
return this.contextPropagators;
}
@Override
public io.opentelemetry.api.OpenTelemetryBuilder<OtelOpenTelemetry.Builder> toBuilder() {
return new Builder(this.meterProviderFactory, this.tracerProviderFactory);
}
static class Builder implements io.opentelemetry.api.OpenTelemetryBuilder<OtelOpenTelemetry.Builder> {
private ContextPropagators propagators;
private TracerProvider tracerProvider;
private MeterProvider meterProvider;
private final MeterProviderFactory meterProviderFactory;
private final TracerProviderFactory tracerProviderFactory;
Builder(MeterProviderFactory meterProviderFactory, TracerProviderFactory tracerProviderFactory) {
this.meterProviderFactory = meterProviderFactory;
this.tracerProviderFactory = tracerProviderFactory;
}
public OtelOpenTelemetry.Builder setTracerProvider(TracerProvider tracerProvider) {
Objects.requireNonNull(tracerProvider, "tracerProvider");
this.tracerProvider = tracerProvider;
return this;
}
public OtelOpenTelemetry.Builder setMeterProvider(MeterProvider meterProvider) {
Objects.requireNonNull(meterProvider, "meterProvider");
this.meterProvider = meterProvider;
return this;
}
public OtelOpenTelemetry.Builder setPropagators(ContextPropagators propagators) {
Objects.requireNonNull(propagators, "propagators");
this.propagators = propagators;
return this;
}
public OpenTelemetry build() {
MeterProvider meterProvider = this.meterProvider;
if (meterProvider == null) {
meterProvider = this.meterProviderFactory.create();
}
TracerProvider tracerProvider = this.tracerProvider;
if (tracerProvider == null) {
tracerProvider = this.tracerProviderFactory.create();
}
return new OtelOpenTelemetry(tracerProviderFactory, meterProviderFactory, tracerProvider, meterProvider,
this.propagators);
}
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.List;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.TextMapPropagator;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.propagation.Propagator;
/**
* OpenTelemetry implementation of a {@link Propagator}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelPropagator implements Propagator {
private final TextMapPropagator propagator;
private final Tracer tracer;
public OtelPropagator(ContextPropagators propagation, Tracer tracer) {
this.propagator = propagation.getTextMapPropagator();
this.tracer = tracer;
}
@Override
public List<String> fields() {
return this.propagator.fields();
}
@Override
public <C> void inject(TraceContext traceContext, C carrier, Setter<C> setter) {
Context context = OtelTraceContext.toOtelContext(traceContext);
this.propagator.inject(context, carrier, setter::set);
}
@Override
public <C> Span.Builder extract(C carrier, Getter<C> getter) {
Context extracted = this.propagator.extract(Context.current(), carrier, new TextMapPropagator.Getter<C>() {
@Override
public Iterable<String> keys(C carrier) {
return fields();
}
@Override
public String get(C carrier, String key) {
return getter.get(carrier, key);
}
});
io.opentelemetry.api.trace.Span span = io.opentelemetry.api.trace.Span.fromContextOrNull(extracted);
if (span == null || span.equals(io.opentelemetry.api.trace.Span.getInvalid())) {
return OtelSpanBuilder.fromOtel(tracer.spanBuilder(""));
}
return OtelSpanBuilder.fromOtel(this.tracer.spanBuilder("").setParent(extracted));
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Scope;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.TraceContext;
/**
* OpenTelemetry implementation of a {@link ScopedSpan}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelScopedSpan implements ScopedSpan {
final Span span;
final Scope scope;
OtelScopedSpan(Span span, Scope scope) {
this.span = span;
this.scope = scope;
}
@Override
public boolean isNoop() {
return !this.span.isRecording();
}
@Override
public TraceContext context() {
return new OtelTraceContext(this.span);
}
@Override
public ScopedSpan name(String name) {
this.span.updateName(name);
return this;
}
@Override
public ScopedSpan tag(String key, String value) {
this.span.setAttribute(key, value);
return this;
}
@Override
public ScopedSpan event(String value) {
this.span.addEvent(value);
return this;
}
@Override
public ScopedSpan error(Throwable throwable) {
this.span.recordException(throwable);
return this;
}
@Override
public void end() {
this.scope.close();
this.span.end();
}
}

View File

@@ -1,303 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.lang.Nullable;
/**
* OpenTelemetry implementation of a {@link Span}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelSpan implements Span {
final io.opentelemetry.api.trace.Span delegate;
private final AtomicReference<Context> context;
OtelSpan(io.opentelemetry.api.trace.Span delegate) {
this.delegate = delegate;
if (delegate instanceof SpanFromSpanContext) {
SpanFromSpanContext fromSpanContext = (SpanFromSpanContext) delegate;
this.context = fromSpanContext.otelTraceContext.context;
}
else {
this.context = new AtomicReference<>(Context.current());
}
}
OtelSpan(io.opentelemetry.api.trace.Span delegate, Context context) {
this.delegate = delegate;
this.context = new AtomicReference<>(context);
}
static io.opentelemetry.api.trace.Span toOtel(Span span) {
return ((OtelSpan) span).delegate;
}
static Span fromOtel(io.opentelemetry.api.trace.Span span) {
return new OtelSpan(span);
}
static Span fromOtel(io.opentelemetry.api.trace.Span span, Context context) {
return new OtelSpan(span, context);
}
@Override
public boolean isNoop() {
return !this.delegate.isRecording();
}
@Override
public TraceContext context() {
if (this.delegate == null) {
return null;
}
return new OtelTraceContext(this.context, this.delegate.getSpanContext(), this.delegate);
}
@Override
public Span start() {
// they are already started via the builder
return this;
}
@Override
public Span name(String name) {
this.delegate.updateName(name);
return new OtelSpan(this.delegate);
}
@Override
public Span event(String value) {
this.delegate.addEvent(value);
return new OtelSpan(this.delegate);
}
@Override
public Span tag(String key, String value) {
this.delegate.setAttribute(key, value);
return new OtelSpan(this.delegate);
}
@Override
public Span error(Throwable throwable) {
this.delegate.recordException(throwable);
return new OtelSpan(this.delegate);
}
@Override
public void end() {
this.delegate.end();
}
@Override
public void abandon() {
// TODO: [OTEL] doesn't seem to have this notion yet
}
@Override
public String toString() {
return this.delegate != null ? this.delegate.toString() : "null";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OtelSpan otelSpan = (OtelSpan) o;
return Objects.equals(this.delegate, otelSpan.delegate);
}
@Override
public int hashCode() {
return Objects.hash(this.delegate);
}
}
class SpanFromSpanContext implements io.opentelemetry.api.trace.Span {
final io.opentelemetry.api.trace.Span span;
final SpanContext newSpanContext;
final OtelTraceContext otelTraceContext;
SpanFromSpanContext(io.opentelemetry.api.trace.Span span, SpanContext newSpanContext,
OtelTraceContext otelTraceContext) {
this.span = span != null ? span : io.opentelemetry.api.trace.Span.wrap(newSpanContext);
this.newSpanContext = newSpanContext;
this.otelTraceContext = otelTraceContext;
}
@Override
public io.opentelemetry.api.trace.Span setAttribute(String key, @Nullable String value) {
return span.setAttribute(key, value);
}
@Override
public io.opentelemetry.api.trace.Span setAttribute(String key, long value) {
return span.setAttribute(key, value);
}
@Override
public io.opentelemetry.api.trace.Span setAttribute(String key, double value) {
return span.setAttribute(key, value);
}
@Override
public io.opentelemetry.api.trace.Span setAttribute(String key, boolean value) {
return span.setAttribute(key, value);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name) {
return span.addEvent(name);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name, long timestamp, TimeUnit unit) {
return span.addEvent(name, timestamp, unit);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name, Instant timestamp) {
return span.addEvent(name, timestamp);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name, Attributes attributes) {
return span.addEvent(name, attributes);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name, Attributes attributes, long timestamp, TimeUnit unit) {
return span.addEvent(name, attributes, timestamp, unit);
}
@Override
public io.opentelemetry.api.trace.Span addEvent(String name, Attributes attributes, Instant timestamp) {
return span.addEvent(name, attributes, timestamp);
}
@Override
public io.opentelemetry.api.trace.Span setStatus(StatusCode canonicalCode) {
return span.setStatus(canonicalCode);
}
@Override
public io.opentelemetry.api.trace.Span setStatus(StatusCode canonicalCode, String description) {
return span.setStatus(canonicalCode, description);
}
@Override
public io.opentelemetry.api.trace.Span setAttribute(AttributeKey<Long> key, int value) {
return span.setAttribute(key, value);
}
@Override
public <T> io.opentelemetry.api.trace.Span setAttribute(AttributeKey<T> key, T value) {
return span.setAttribute(key, value);
}
@Override
public io.opentelemetry.api.trace.Span recordException(Throwable exception) {
return span.recordException(exception);
}
@Override
public io.opentelemetry.api.trace.Span recordException(Throwable exception, Attributes additionalAttributes) {
return span.recordException(exception, additionalAttributes);
}
@Override
public io.opentelemetry.api.trace.Span updateName(String name) {
return span.updateName(name);
}
@Override
public void end() {
span.end();
}
@Override
public void end(long timestamp, TimeUnit unit) {
span.end(timestamp, unit);
}
@Override
public void end(Instant timestamp) {
span.end(timestamp);
}
@Override
public SpanContext getSpanContext() {
return newSpanContext;
}
@Override
public boolean isRecording() {
return span.isRecording();
}
@Override
public Context storeInContext(Context context) {
return span.storeInContext(context);
}
@Override
public String toString() {
return "SpanFromSpanContext{" + "span=" + span + ", newSpanContext=" + newSpanContext + '}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SpanFromSpanContext that = (SpanFromSpanContext) o;
return Objects.equals(span, that.span) && Objects.equals(this.newSpanContext, that.newSpanContext);
}
@Override
public int hashCode() {
return Objects.hash(this.span, this.newSpanContext);
}
}

View File

@@ -1,130 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.LinkedList;
import java.util.List;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.util.StringUtils;
/**
* OpenTelemetry implementation of a {@link Span.Builder}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelSpanBuilder implements Span.Builder {
private final io.opentelemetry.api.trace.SpanBuilder delegate;
private final List<String> annotations = new LinkedList<>();
private String name;
private Throwable error;
OtelSpanBuilder(io.opentelemetry.api.trace.SpanBuilder delegate) {
this.delegate = delegate;
}
static Span.Builder fromOtel(io.opentelemetry.api.trace.SpanBuilder builder) {
return new OtelSpanBuilder(builder);
}
@Override
public Span.Builder setParent(TraceContext context) {
this.delegate.setParent(OtelTraceContext.toOtelContext(context));
return this;
}
@Override
public Span.Builder setNoParent() {
this.delegate.setNoParent();
return this;
}
@Override
public Span.Builder name(String name) {
this.name = name;
return this;
}
@Override
public Span.Builder event(String value) {
this.annotations.add(value);
return this;
}
@Override
public Span.Builder tag(String key, String value) {
this.delegate.setAttribute(key, value);
return this;
}
@Override
public Span.Builder error(Throwable throwable) {
this.error = throwable;
return this;
}
@Override
public Span.Builder kind(Span.Kind spanKind) {
if (spanKind == null) {
this.delegate.setSpanKind(io.opentelemetry.api.trace.Span.Kind.INTERNAL);
return this;
}
io.opentelemetry.api.trace.Span.Kind kind = io.opentelemetry.api.trace.Span.Kind.INTERNAL;
switch (spanKind) {
case CLIENT:
kind = io.opentelemetry.api.trace.Span.Kind.CLIENT;
break;
case SERVER:
kind = io.opentelemetry.api.trace.Span.Kind.SERVER;
break;
case PRODUCER:
kind = io.opentelemetry.api.trace.Span.Kind.PRODUCER;
break;
case CONSUMER:
kind = io.opentelemetry.api.trace.Span.Kind.CONSUMER;
break;
}
this.delegate.setSpanKind(kind);
return this;
}
@Override
public Span.Builder remoteServiceName(String remoteServiceName) {
this.delegate.setAttribute("peer.service", remoteServiceName);
return this;
}
@Override
public Span start() {
io.opentelemetry.api.trace.Span span = this.delegate.startSpan();
if (StringUtils.hasText(this.name)) {
span.updateName(this.name);
}
if (this.error != null) {
span.recordException(error);
}
this.annotations.forEach(span::addEvent);
return OtelSpan.fromOtel(span);
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import io.opentelemetry.api.trace.Span;
import org.springframework.cloud.sleuth.SpanCustomizer;
/**
* OpenTelemetry implementation of a {@link SpanCustomizer}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelSpanCustomizer implements SpanCustomizer {
@Override
public SpanCustomizer name(String name) {
currentSpan().updateName(name);
return this;
}
private Span currentSpan() {
return Span.current();
}
@Override
public SpanCustomizer tag(String key, String value) {
currentSpan().setAttribute(key, value);
return this;
}
@Override
public SpanCustomizer event(String value) {
currentSpan().addEvent(value);
return this;
}
}

View File

@@ -1,141 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.trace.ReadableSpan;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.lang.Nullable;
/**
* OpenTelemetry implementation of a {@link TraceContext}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
class OtelTraceContext implements TraceContext {
final AtomicReference<Context> context;
final SpanContext delegate;
final Span span;
OtelTraceContext(Context context, SpanContext delegate, @Nullable Span span) {
this(new AtomicReference<>(context), delegate, span);
}
OtelTraceContext(AtomicReference<Context> context, SpanContext delegate, @Nullable Span span) {
this.context = context;
this.delegate = delegate;
this.span = span;
}
OtelTraceContext(SpanContext delegate, @Nullable Span span) {
this.context = new AtomicReference<>(Context.current());
this.delegate = delegate;
this.span = span;
}
OtelTraceContext(Span span) {
this(Context.current(), span.getSpanContext(), span);
}
OtelTraceContext(SpanFromSpanContext span) {
this(span.otelTraceContext.context.get(), span.getSpanContext(), span);
}
static TraceContext fromOtel(SpanContext traceContext) {
return new OtelTraceContext(traceContext, null);
}
static Context toOtelContext(TraceContext context) {
if (context instanceof OtelTraceContext) {
Span span = ((OtelTraceContext) context).span;
if (span != null) {
return span.storeInContext(Context.current());
}
}
return Context.current();
}
@Override
public String traceId() {
return this.delegate.getTraceIdAsHexString();
}
@Override
@Nullable
public String parentId() {
if (this.span instanceof ReadableSpan) {
ReadableSpan readableSpan = (ReadableSpan) this.span;
return readableSpan.toSpanData().getParentSpanId();
}
return null;
}
@Override
public String spanId() {
return this.delegate.getSpanIdAsHexString();
}
@Override
public Boolean sampled() {
return this.delegate.isSampled();
}
@Override
public String toString() {
return this.delegate != null ? this.delegate.toString() : "null";
}
Span span() {
return this.span;
}
Context context() {
return this.context.get();
}
void updateContext(Context context) {
this.context.set(context);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OtelTraceContext context = (OtelTraceContext) o;
return Objects.equals(this.delegate, context.delegate);
}
@Override
public int hashCode() {
return Objects.hash(this.delegate);
}
}

View File

@@ -1,163 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.Map;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.Scope;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.sleuth.BaggageInScope;
import org.springframework.cloud.sleuth.BaggageManager;
import org.springframework.cloud.sleuth.ScopedSpan;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanCustomizer;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.ApplicationEventPublisher;
/**
* OpenTelemetry implementation of a {@link Tracer}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class OtelTracer implements Tracer {
private final io.opentelemetry.api.trace.Tracer tracer;
private final BaggageManager otelBaggageManager;
private final ApplicationEventPublisher publisher;
public OtelTracer(io.opentelemetry.api.trace.Tracer tracer, ApplicationEventPublisher publisher,
BaggageManager otelBaggageManager) {
this.tracer = tracer;
this.publisher = publisher;
this.otelBaggageManager = otelBaggageManager;
}
@Override
public Span nextSpan(Span parent) {
if (parent == null) {
return nextSpan();
}
return OtelSpan.fromOtel(
this.tracer.spanBuilder("").setParent(OtelTraceContext.toOtelContext(parent.context())).startSpan());
}
@Override
public SpanInScope withSpan(Span span) {
io.opentelemetry.api.trace.Span delegate = delegate(span);
return new OtelSpanInScope((OtelSpan) span, delegate);
}
protected io.opentelemetry.api.trace.Span delegate(Span span) {
if (span == null) {
this.publisher.publishEvent(new OtelCurrentTraceContext.ScopeClosed(this));
return io.opentelemetry.api.trace.Span.getInvalid();
}
return ((OtelSpan) span).delegate;
}
@Override
public SpanCustomizer currentSpanCustomizer() {
return new OtelSpanCustomizer();
}
@Override
public Span currentSpan() {
io.opentelemetry.api.trace.Span currentSpan = io.opentelemetry.api.trace.Span.current();
if (currentSpan == null || currentSpan.equals(io.opentelemetry.api.trace.Span.getInvalid())) {
return null;
}
return new OtelSpan(currentSpan);
}
@Override
public Span nextSpan() {
return new OtelSpan(this.tracer.spanBuilder("").startSpan());
}
@Override
public ScopedSpan startScopedSpan(String name) {
io.opentelemetry.api.trace.Span span = this.tracer.spanBuilder(name).startSpan();
return new OtelScopedSpan(span, span.makeCurrent());
}
@Override
public Span.Builder spanBuilder() {
return new OtelSpanBuilder(this.tracer.spanBuilder(""));
}
@Override
public Map<String, String> getAllBaggage() {
return this.otelBaggageManager.getAllBaggage();
}
@Override
public BaggageInScope getBaggage(String name) {
return this.otelBaggageManager.getBaggage(name);
}
@Override
public BaggageInScope getBaggage(TraceContext traceContext, String name) {
return this.otelBaggageManager.getBaggage(traceContext, name);
}
@Override
public BaggageInScope createBaggage(String name) {
return this.otelBaggageManager.createBaggage(name);
}
@Override
public BaggageInScope createBaggage(String name, String value) {
return this.otelBaggageManager.createBaggage(name, value);
}
}
class OtelSpanInScope implements Tracer.SpanInScope {
private static final Log log = LogFactory.getLog(OtelSpanInScope.class);
final Scope delegate;
final OtelSpan sleuthSpan;
final io.opentelemetry.api.trace.Span otelSpan;
final SpanContext spanContext;
OtelSpanInScope(OtelSpan sleuthSpan, io.opentelemetry.api.trace.Span otelSpan) {
this.sleuthSpan = sleuthSpan;
this.otelSpan = otelSpan;
this.delegate = otelSpan.makeCurrent();
this.spanContext = otelSpan.getSpanContext();
}
@Override
public void close() {
if (log.isTraceEnabled()) {
log.trace("Will close scope for trace context [" + this.spanContext + "]");
}
this.delegate.close();
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.regex.Pattern;
import org.springframework.cloud.sleuth.SamplerFunction;
import org.springframework.cloud.sleuth.http.HttpRequest;
/**
* Decides if sampling should take place for the given request.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class SkipPatternSampler implements SamplerFunction<HttpRequest> {
private final Pattern pattern;
public SkipPatternSampler(Pattern pattern) {
this.pattern = pattern;
}
@Override
public final Boolean trySample(HttpRequest request) {
String url = request.path();
boolean shouldSkip = this.pattern.matcher(url).matches();
if (shouldSkip) {
return false;
}
return null;
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.cloud.sleuth.BaggageManager;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class Slf4jBaggageSpanProcessor implements SpanProcessor, ApplicationListener {
private static final Log log = LogFactory.getLog(Slf4jBaggageSpanProcessor.class);
private final List<String> correlationFields;
private final BeanFactory beanFactory;
private BaggageManager baggageManager;
public Slf4jBaggageSpanProcessor(List<String> correlationFields, BeanFactory beanFactory) {
this.correlationFields = correlationFields;
this.beanFactory = beanFactory;
}
private BaggageManager baggageManager() {
if (this.baggageManager == null) {
this.baggageManager = this.beanFactory.getBean(BaggageManager.class);
}
return this.baggageManager;
}
@Override
public void onStart(Context parent, ReadWriteSpan span) {
onStart();
}
private void onStart() {
flushAllBaggageEntries();
}
@Override
public boolean isStartRequired() {
return true;
}
@Override
public void onEnd(ReadableSpan span) {
removeAllBaggageEntries();
}
@Override
public boolean isEndRequired() {
return true;
}
@Override
public CompletableResultCode shutdown() {
onEnd(null);
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode forceFlush() {
flushAllBaggageEntries();
return CompletableResultCode.ofSuccess();
}
private void flushAllBaggageEntries() {
onEachCorrelatedBaggageEntry(e -> MDC.put(e.getKey(), e.getValue()));
}
private void onEachCorrelatedBaggageEntry(Consumer<Map.Entry<String, String>> consumer) {
List<String> correlationFields = lowerCaseCorrelationFields();
baggageManager().getAllBaggage().entrySet().stream()
.filter(e -> correlationFields.contains(e.getKey().toLowerCase())).forEach(consumer);
}
private void removeAllBaggageEntries() {
onEachCorrelatedBaggageEntry(e -> MDC.remove(e.getKey()));
}
private List<String> lowerCaseCorrelationFields() {
return this.correlationFields.stream().map(String::toLowerCase).collect(Collectors.toList());
}
private void onBaggageChanged(OtelBaggageInScope.BaggageChanged event) {
if (log.isTraceEnabled()) {
log.trace("Got baggage changed event [" + event + "]");
}
if (lowerCaseCorrelationFields().contains(event.name.toLowerCase())) {
if (log.isTraceEnabled()) {
log.trace("Correlation enabled and baggage with name [" + event.name
+ "] is present on the list of correlated fields");
}
MDC.put(event.name, event.value);
}
}
private void onScopeChanged(OtelCurrentTraceContext.ScopeChanged event) {
if (log.isTraceEnabled()) {
log.trace("Got scope changed event [" + event + "]");
}
if (event.span != null) {
onStart();
}
}
private void onScopeClosed(OtelCurrentTraceContext.ScopeClosed event) {
if (log.isTraceEnabled()) {
log.trace("Got scope closed event [" + event + "]");
}
onEnd(null);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof OtelBaggageInScope.BaggageChanged) {
onBaggageChanged((OtelBaggageInScope.BaggageChanged) event);
}
else if (event instanceof OtelCurrentTraceContext.ScopeChanged) {
onScopeChanged((OtelCurrentTraceContext.ScopeChanged) event);
}
else if (event instanceof OtelCurrentTraceContext.ScopeClosed) {
onScopeClosed((OtelCurrentTraceContext.ScopeClosed) event);
}
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.slf4j.MDC;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
public class Slf4jSpanProcessor implements SpanProcessor, ApplicationListener {
private static final Log log = LogFactory.getLog(Slf4jSpanProcessor.class);
@Override
public void onStart(Context parent, ReadWriteSpan span) {
onStart(span.getSpanContext().getTraceIdAsHexString(), span.getSpanContext().getSpanIdAsHexString());
}
private void onStart(String traceId, String spanId) {
MDC.put("traceId", traceId);
MDC.put("spanId", spanId);
}
@Override
public boolean isStartRequired() {
return true;
}
@Override
public void onEnd(ReadableSpan span) {
MDC.remove("traceId");
MDC.remove("spanId");
}
@Override
public boolean isEndRequired() {
return true;
}
@Override
public CompletableResultCode shutdown() {
onEnd(null);
return CompletableResultCode.ofSuccess();
}
@Override
public CompletableResultCode forceFlush() {
return CompletableResultCode.ofSuccess();
}
private void onScopeChanged(OtelCurrentTraceContext.ScopeChanged event) {
if (log.isTraceEnabled()) {
log.trace("Got scope changed event [" + event + "]");
}
if (event.span != null) {
onStart(event.span.getSpanContext().getTraceIdAsHexString(),
event.span.getSpanContext().getSpanIdAsHexString());
}
}
private void onScopeClosed(OtelCurrentTraceContext.ScopeClosed event) {
if (log.isTraceEnabled()) {
log.trace("Got scope closed event [" + event + "]");
}
onEnd(null);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof OtelCurrentTraceContext.ScopeChanged) {
onScopeChanged((OtelCurrentTraceContext.ScopeChanged) event);
}
else if (event instanceof OtelCurrentTraceContext.ScopeClosed) {
onScopeClosed((OtelCurrentTraceContext.ScopeClosed) event);
}
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import io.opentelemetry.sdk.trace.export.SpanExporter;
/**
* Allows customization of a {@link SpanExporter}.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface SpanExporterCustomizer {
/**
* Customizes a span exporter.
* @param spanExporter to customize
* @return customized span exporter
*/
default SpanExporter customize(SpanExporter spanExporter) {
return spanExporter;
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.propagation;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import io.opentelemetry.api.baggage.Baggage;
import io.opentelemetry.api.baggage.BaggageBuilder;
import io.opentelemetry.api.baggage.EntryMetadata;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapPropagator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cloud.sleuth.BaggageManager;
/**
* {@link TextMapPropagator} that adds Sleuth compatible baggage entries (name of the
* field means an HTTP header entry).
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class BaggageTextMapPropagator implements TextMapPropagator {
private static final Log log = LogFactory.getLog(BaggageTextMapPropagator.class);
private final List<String> remoteFields;
private final BaggageManager baggageManager;
public BaggageTextMapPropagator(List<String> remoteFields, BaggageManager baggageManager) {
this.remoteFields = remoteFields;
this.baggageManager = baggageManager;
}
@Override
public List<String> fields() {
return this.remoteFields;
}
@Override
public <C> void inject(Context context, C c, Setter<C> setter) {
List<Map.Entry<String, String>> baggageEntries = applicableBaggageEntries(c);
baggageEntries.forEach(e -> setter.set(c, e.getKey(), e.getValue()));
}
private <C> List<Map.Entry<String, String>> applicableBaggageEntries(C c) {
Map<String, String> allBaggage = this.baggageManager.getAllBaggage();
List<String> lowerCaseKeys = this.remoteFields.stream().map(String::toLowerCase).collect(Collectors.toList());
return allBaggage.entrySet().stream().filter(e -> lowerCaseKeys.contains(e.getKey().toLowerCase()))
.collect(Collectors.toList());
}
@Override
public <C> Context extract(Context context, C c, Getter<C> getter) {
Map<String, String> baggageEntries = this.remoteFields.stream()
.map(s -> new AbstractMap.SimpleEntry<>(s, getter.get(c, s))).filter(e -> e.getValue() != null)
.collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue()));
BaggageBuilder builder = Baggage.builder().setParent(context);
// TODO: [OTEL] magic string
baggageEntries.forEach((key, value) -> builder.put(key, value, EntryMetadata.create("propagation=unlimited")));
Baggage baggage = builder.build();
Context withBaggage = context.with(baggage);
if (log.isDebugEnabled()) {
log.debug("Will propagate new baggage context for entries " + baggageEntries);
}
return withBaggage;
}
}

View File

@@ -1,180 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.propagation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.propagation.HttpTraceContext;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.extension.trace.propagation.JaegerPropagator;
import io.opentelemetry.extension.trace.propagation.OtTracerPropagator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
* {@link TextMapPropagator} implementation that can read / write from multiple
* {@link TextMapPropagator} implementations.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public class CompositeTextMapPropagator implements TextMapPropagator {
private static final Log log = LogFactory.getLog(CompositeTextMapPropagator.class);
private final Map<PropagationType, TextMapPropagator> mapping = new HashMap<>();
private final List<PropagationType> types;
public CompositeTextMapPropagator(BeanFactory beanFactory, List<PropagationType> types) {
this.types = types;
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.AwsXRayPropagator")) {
this.mapping.put(PropagationType.AWS, beanFactory.getBeanProvider(AwsXRayPropagator.class)
.getIfAvailable(AwsXRayPropagator::getInstance));
}
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.B3Propagator")) {
this.mapping.put(PropagationType.B3,
beanFactory.getBeanProvider(B3Propagator.class).getIfAvailable(B3Propagator::getInstance));
}
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.JaegerPropagator")) {
this.mapping.put(PropagationType.JAEGER,
beanFactory.getBeanProvider(JaegerPropagator.class).getIfAvailable(JaegerPropagator::getInstance));
}
if (isOnClasspath("io.opentelemetry.extension.trace.propagation.OtTracerPropagator")) {
this.mapping.put(PropagationType.OT_TRACER, beanFactory.getBeanProvider(OtTracerPropagator.class)
.getIfAvailable(OtTracerPropagator::getInstance));
}
this.mapping.put(PropagationType.W3C, new MultiTextMapPropagator(
Arrays.asList(HttpTraceContext.getInstance(), W3CBaggagePropagator.getInstance())));
this.mapping.put(PropagationType.CUSTOM, NoopTextMapPropagator.INSTANCE);
log.info("Registered the following context propagation types " + this.mapping.keySet());
}
private boolean isOnClasspath(String clazz) {
return ClassUtils.isPresent(clazz, null);
}
@Override
public List<String> fields() {
return this.types.stream().map(key -> this.mapping.getOrDefault(key, NoopTextMapPropagator.INSTANCE))
.flatMap(p -> p.fields().stream()).collect(Collectors.toList());
}
@Override
public <C> void inject(Context context, C carrier, Setter<C> setter) {
this.types.stream().map(key -> this.mapping.getOrDefault(key, NoopTextMapPropagator.INSTANCE))
.forEach(p -> p.inject(context, carrier, setter));
}
@Override
public <C> Context extract(Context context, C carrier, Getter<C> getter) {
for (PropagationType type : this.types) {
TextMapPropagator propagator = this.mapping.get(type);
if (propagator == null || propagator == NoopTextMapPropagator.INSTANCE) {
continue;
}
Context extractedContext = propagator.extract(context, carrier, getter);
Span span = Span.fromContextOrNull(extractedContext);
if (span != null) {
return extractedContext;
}
}
return context;
}
private static final class NoopTextMapPropagator implements TextMapPropagator {
private static final NoopTextMapPropagator INSTANCE = new NoopTextMapPropagator();
@Override
public List<String> fields() {
return Collections.emptyList();
}
@Override
public <C> void inject(Context context, C carrier, Setter<C> setter) {
}
@Override
public <C> Context extract(Context context, C carrier, Getter<C> getter) {
return context;
}
}
// Taken from OTel
private static final class MultiTextMapPropagator implements TextMapPropagator {
private final TextMapPropagator[] textPropagators;
private final List<String> allFields;
private MultiTextMapPropagator(List<TextMapPropagator> textPropagators) {
this.textPropagators = new TextMapPropagator[textPropagators.size()];
textPropagators.toArray(this.textPropagators);
this.allFields = Collections.unmodifiableList(getAllFields(this.textPropagators));
}
private static List<String> getAllFields(TextMapPropagator[] textPropagators) {
Set<String> fields = new LinkedHashSet<>();
for (int i = 0; i < textPropagators.length; i++) {
fields.addAll(textPropagators[i].fields());
}
return new ArrayList<>(fields);
}
@Override
public List<String> fields() {
return allFields;
}
@Override
public <C> void inject(Context context, @Nullable C carrier, Setter<C> setter) {
for (int i = 0; i < textPropagators.length; i++) {
textPropagators[i].inject(context, carrier, setter);
}
}
@Override
public <C> Context extract(Context context, @Nullable C carrier, Getter<C> getter) {
for (int i = 0; i < textPropagators.length; i++) {
context = textPropagators[i].extract(context, carrier, getter);
}
return context;
}
}
}

View File

@@ -1,57 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.propagation;
/*
* Supported propagation types.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public enum PropagationType {
/**
* AWS propagation type.
*/
AWS,
/**
* B3 propagation type.
*/
B3,
/**
* Jaeger propagation type.
*/
JAEGER,
/**
* Lightstep propagation type.
*/
OT_TRACER,
/**
* W3C propagation type.
*/
W3C,
/**
* Custom propagation type.
*/
CUSTOM
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth;
import com.tngtech.archunit.core.importer.ImportOption;
import com.tngtech.archunit.core.importer.Location;
import com.tngtech.archunit.junit.AnalyzeClasses;
import com.tngtech.archunit.junit.ArchTest;
import com.tngtech.archunit.lang.ArchRule;
import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
@AnalyzeClasses(packagesOf = ArchitectureTests.class, importOptions = ArchitectureTests.ProductionCode.class)
public class ArchitectureTests {
@ArchTest
public static final ArchRule should_not_contain_any_spring_configuration_reference_in_module = noClasses().should()
.dependOnClassesThat().resideInAnyPackage("..org.springframework.boot.context.properties..",
"..org.springframework.context.annotation..");
static class ProductionCode implements ImportOption {
@Override
public boolean includes(Location location) {
return Predefined.DO_NOT_INCLUDE_TESTS.includes(location)
&& Predefined.DO_NOT_INCLUDE_JARS.includes(location);
}
}
}

View File

@@ -1,5 +0,0 @@
logging.level.org.springframework.cloud: DEBUG
logging.level.com.netflix.discovery.InstanceInfoReplicator: ERROR
logging.level.org.springframework.cloud.sleuth.brave.instrument.web.client.feign: TRACE
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration, org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration

View File

@@ -40,18 +40,6 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
<!-- TODO: [OTEL] breaking change -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<!-- TODO: [OTEL] breaking change -->
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>

View File

@@ -129,26 +129,11 @@
<artifactId>brave-tests</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-extension-trace-propagators</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-zipkin</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zipkin.zipkin2</groupId>
<artifactId>zipkin</artifactId>

View File

@@ -1,129 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import io.opentelemetry.context.Context;
import io.opentelemetry.sdk.common.CompletableResultCode;
import io.opentelemetry.sdk.trace.ReadWriteSpan;
import io.opentelemetry.sdk.trace.ReadableSpan;
import io.opentelemetry.sdk.trace.SpanProcessor;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SpanExporter;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
import org.springframework.cloud.sleuth.otel.bridge.ArrayListSpanProcessor;
import org.springframework.cloud.sleuth.otel.bridge.OtelAccessor;
import org.springframework.cloud.sleuth.test.TestSpanHandler;
public class OtelTestSpanHandler implements TestSpanHandler, SpanProcessor, SpanExporter {
private final ArrayListSpanProcessor spanProcessor;
public OtelTestSpanHandler(ArrayListSpanProcessor spanProcessor) {
this.spanProcessor = spanProcessor;
}
@Override
public List<FinishedSpan> reportedSpans() {
return spanProcessor.spans().stream().map(OtelAccessor::finishedSpan).collect(Collectors.toList());
}
@Override
public FinishedSpan takeLocalSpan() {
return OtelAccessor.finishedSpan(spanProcessor.takeLocalSpan());
}
@Override
public void clear() {
spanProcessor.clear();
}
@Override
public FinishedSpan takeRemoteSpan(Span.Kind kind) {
return reportedSpans().stream().filter(s -> s.getKind().name().equals(kind.name())).findFirst()
.orElseThrow(() -> new AssertionError("No span with kind [" + kind.name() + "] found."));
}
@Override
public FinishedSpan takeRemoteSpanWithError(Span.Kind kind) {
return reportedSpans().stream().filter(s -> s.getKind().name().equals(kind.name()) && s.getError() != null)
.findFirst()
.orElseThrow(() -> new AssertionError("No span with kind [" + kind.name() + "] and error found."));
}
@Override
public FinishedSpan get(int index) {
return reportedSpans().get(index);
}
@Override
public Iterator<FinishedSpan> iterator() {
return reportedSpans().iterator();
}
@Override
public void onStart(Context parentContext, ReadWriteSpan span) {
spanProcessor.onStart(parentContext, span);
}
@Override
public boolean isStartRequired() {
return spanProcessor.isStartRequired();
}
@Override
public void onEnd(ReadableSpan span) {
spanProcessor.onEnd(span);
}
@Override
public boolean isEndRequired() {
return spanProcessor.isEndRequired();
}
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
return spanProcessor.export(spans);
}
@Override
public CompletableResultCode flush() {
return spanProcessor.flush();
}
@Override
public CompletableResultCode shutdown() {
return spanProcessor.shutdown();
}
@Override
public CompletableResultCode forceFlush() {
return spanProcessor.forceFlush();
}
@Override
public String toString() {
return "OtelTestSpanHandler{" + "spanProcessor=" + this.spanProcessor + '}';
}
}

View File

@@ -1,191 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel;
import java.io.Closeable;
import java.util.regex.Pattern;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.metrics.MeterProvider;
import io.opentelemetry.api.trace.TracerProvider;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.context.propagation.DefaultContextPropagators;
import io.opentelemetry.extension.trace.propagation.B3Propagator;
import io.opentelemetry.sdk.trace.TracerSdkProvider;
import io.opentelemetry.sdk.trace.config.TraceConfig;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import io.opentelemetry.sdk.trace.spi.TracerProviderFactorySdk;
import io.opentelemetry.spi.metrics.MeterProviderFactory;
import io.opentelemetry.spi.trace.TracerProviderFactory;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.SamplerFunction;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.http.HttpRequestParser;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.otel.bridge.ArrayListSpanProcessor;
import org.springframework.cloud.sleuth.otel.bridge.OtelAccessor;
import org.springframework.cloud.sleuth.otel.bridge.OtelOpenTelemetry;
import org.springframework.cloud.sleuth.propagation.Propagator;
import org.springframework.cloud.sleuth.test.TestSpanHandler;
import org.springframework.cloud.sleuth.test.TestTracingAssertions;
import org.springframework.cloud.sleuth.test.TestTracingAware;
import org.springframework.cloud.sleuth.test.TestTracingAwareSupplier;
import org.springframework.cloud.sleuth.test.TracerAware;
import org.springframework.context.ApplicationEventPublisher;
public class OtelTestTracing implements TracerAware, TestTracingAware, TestTracingAwareSupplier, Closeable {
ArrayListSpanProcessor spanProcessor = new ArrayListSpanProcessor();
ContextPropagators contextPropagators = contextPropagators();
OpenTelemetry openTelemetry = otel();
ContextPropagators defaultContextPropagators = OpenTelemetry.getGlobalPropagators();
Sampler sampler = Sampler.alwaysOn();
HttpRequestParser clientRequestParser;
io.opentelemetry.api.trace.Tracer tracer = otelTracer();
CurrentTraceContext currentTraceContext = OtelAccessor.currentTraceContext(publisher());
io.opentelemetry.api.trace.Tracer otelTracer() {
TracerSdkProvider provider = TracerSdkProvider.builder().build();
provider.addSpanProcessor(this.spanProcessor);
provider.updateActiveTraceConfig(TraceConfig.getDefault().toBuilder().setSampler(this.sampler).build());
return provider.get("org.springframework.cloud.sleuth");
}
protected ContextPropagators contextPropagators() {
return DefaultContextPropagators.builder()
.addTextMapPropagator(B3Propagator.builder().injectMultipleHeaders().build()).build();
}
OpenTelemetry otel() {
TracerProviderFactory providerFactory = otelTracerProviderFactory();
MeterProviderFactory meterProviderFactory = otelMeterProviderFactory();
OtelOpenTelemetry otelOpenTelemetry = new OtelOpenTelemetry(providerFactory, meterProviderFactory,
otelTracerProvider(providerFactory), otelMeterProvider(meterProviderFactory), this.contextPropagators);
OpenTelemetry.set(otelOpenTelemetry);
OpenTelemetry.setGlobalPropagators(contextPropagators);
return otelOpenTelemetry;
}
TracerProviderFactory otelTracerProviderFactory() {
return new TracerProviderFactorySdk();
}
TracerProvider otelTracerProvider(TracerProviderFactory tracerProviderFactory) {
return tracerProviderFactory.create();
}
MeterProviderFactory otelMeterProviderFactory() {
return OpenTelemetry::getGlobalMeterProvider;
}
MeterProvider otelMeterProvider(MeterProviderFactory meterProviderFactory) {
return meterProviderFactory.create();
}
private void reset() {
this.contextPropagators = contextPropagators();
this.tracer = otelTracer();
this.currentTraceContext = OtelAccessor.currentTraceContext(publisher());
}
@Override
public TracerAware sampler(TraceSampler sampler) {
this.sampler = sampler == TraceSampler.ON ? Sampler.alwaysOn() : Sampler.alwaysOff();
return this;
}
@Override
public TracerAware tracing() {
return this;
}
@Override
public TestSpanHandler handler() {
return new OtelTestSpanHandler(this.spanProcessor);
}
@Override
public TestTracingAssertions assertions() {
return new OtelTestTracingAssertions();
}
@Override
public void close() {
this.spanProcessor.clear();
OpenTelemetry.setGlobalPropagators(this.defaultContextPropagators);
this.sampler = Sampler.alwaysOn();
}
@Override
public TestTracingAware tracerTest() {
return this;
}
@Override
public Tracer tracer() {
reset();
return OtelAccessor.tracer(this.tracer, this.currentTraceContext, new SleuthBaggageProperties(), publisher());
}
@Override
public CurrentTraceContext currentTraceContext() {
reset();
return OtelAccessor.currentTraceContext(publisher());
}
@Override
public Propagator propagator() {
reset();
return OtelAccessor.propagator(this.contextPropagators, this.tracer);
}
@Override
public HttpServerHandler httpServerHandler() {
reset();
return OtelAccessor.httpServerHandler(this.tracer, null, null, () -> Pattern.compile(""));
}
@Override
public TracerAware clientRequestParser(HttpRequestParser httpRequestParser) {
this.clientRequestParser = httpRequestParser;
return this;
}
@Override
public HttpClientHandler httpClientHandler() {
reset();
return OtelAccessor.httpClientHandler(this.tracer, this.clientRequestParser, null,
SamplerFunction.alwaysSample());
}
ApplicationEventPublisher publisher() {
return event -> {
};
}
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel;
import org.assertj.core.api.BDDAssertions;
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
import org.springframework.cloud.sleuth.test.TestTracingAssertions;
public class OtelTestTracingAssertions implements TestTracingAssertions {
@Override
public void assertThatNoParentPresent(FinishedSpan finishedSpan) {
BDDAssertions.then(Long.valueOf(finishedSpan.getParentId())).isEqualTo(0L);
}
@Override
public String or128Bit(String id) {
return "0000000000000000" + id;
}
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.bridge;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.context.propagation.ContextPropagators;
import io.opentelemetry.sdk.trace.data.SpanData;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.SamplerFunction;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.SleuthBaggageProperties;
import org.springframework.cloud.sleuth.exporter.FinishedSpan;
import org.springframework.cloud.sleuth.http.HttpClientHandler;
import org.springframework.cloud.sleuth.http.HttpRequest;
import org.springframework.cloud.sleuth.http.HttpRequestParser;
import org.springframework.cloud.sleuth.http.HttpResponseParser;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
import org.springframework.cloud.sleuth.propagation.Propagator;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.lang.Nullable;
public final class OtelAccessor {
private OtelAccessor() {
throw new IllegalStateException("Can't instantiate a utility class");
}
public static Tracer tracer(io.opentelemetry.api.trace.Tracer tracer, CurrentTraceContext currentTraceContext,
SleuthBaggageProperties sleuthBaggageProperties, ApplicationEventPublisher publisher) {
return new OtelTracer(tracer, publisher, new OtelBaggageManager(currentTraceContext,
sleuthBaggageProperties.getRemoteFields(), sleuthBaggageProperties.getTagFields(), publisher));
}
public static CurrentTraceContext currentTraceContext(ApplicationEventPublisher publisher) {
return new OtelCurrentTraceContext(publisher);
}
public static CurrentTraceContext currentTraceContext() {
return currentTraceContext(event -> {
});
}
public static TraceContext traceContext(SpanContext spanContext) {
return OtelTraceContext.fromOtel(spanContext);
}
public static Propagator propagator(ContextPropagators propagators, io.opentelemetry.api.trace.Tracer tracer) {
return new OtelPropagator(propagators, tracer);
}
public static HttpClientHandler httpClientHandler(io.opentelemetry.api.trace.Tracer tracer,
@Nullable HttpRequestParser httpClientRequestParser, @Nullable HttpResponseParser httpClientResponseParser,
SamplerFunction<HttpRequest> samplerFunction) {
return new OtelHttpClientHandler(tracer, httpClientRequestParser, httpClientResponseParser, samplerFunction);
}
public static HttpServerHandler httpServerHandler(io.opentelemetry.api.trace.Tracer tracer,
HttpRequestParser httpServerRequestParser, HttpResponseParser httpServerResponseParser,
SkipPatternProvider skipPatternProvider) {
return new OtelHttpServerHandler(tracer, httpServerRequestParser, httpServerResponseParser,
skipPatternProvider);
}
public static FinishedSpan finishedSpan(SpanData spanData) {
return new OtelFinishedSpan(spanData);
}
}

View File

@@ -1,68 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2020 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.
~
~
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-sleuth-otel-tests</artifactId>
<packaging>pom</packaging>
<name>Spring Cloud Sleuth Otel Tests</name>
<description>Spring Cloud Sleuth Otel Tests</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-tests</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<modules>
<module>spring-cloud-sleuth-instrumentation-annotation-tests</module>
<module>spring-cloud-sleuth-instrumentation-async-tests</module>
<module>spring-cloud-sleuth-instrumentation-baggage-tests</module>
<module>spring-cloud-sleuth-instrumentation-circuitbreaker-tests</module>
<module>spring-cloud-sleuth-instrumentation-feign-tests</module>
<module>spring-cloud-sleuth-instrumentation-gateway-tests</module>
<module>spring-cloud-sleuth-instrumentation-messaging-tests</module>
<module>spring-cloud-sleuth-instrumentation-mvc-tests</module>
<module>spring-cloud-sleuth-instrumentation-quartz-tests</module>
<module>spring-cloud-sleuth-instrumentation-reactor-tests</module>
<module>spring-cloud-sleuth-instrumentation-rxjava-tests</module>
<module>spring-cloud-sleuth-instrumentation-scheduling-tests</module>
<module>spring-cloud-sleuth-instrumentation-webflux-tests</module>
<module>spring-cloud-sleuth-zipkin-tests</module>
</modules>
<build>
<pluginManagement>
<plugins>
<plugin>
<!--skip deploy (this is just a test module) -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

View File

@@ -1,91 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2020 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.
~
~
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-sleuth-instrumentation-annotation-otel-tests</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Sleuth Otel Annotation Instrumentation Tests</name>
<description>Spring Cloud Sleuth Otel Annotation Instrumentation Tests</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel-tests</artifactId>
<version>3.0.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<properties>
<sonar.skip>true</sonar.skip>
</properties>
<build>
<plugins>
<plugin>
<!--skip deploy -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-tests-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.annotation;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.otel.OtelTestSpanHandler;
import org.springframework.cloud.sleuth.otel.bridge.ArrayListSpanProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
@ContextConfiguration(classes = NullSpanTagAnnotationHandlerTests.Config.class)
public class NullSpanTagAnnotationHandlerTests
extends org.springframework.cloud.sleuth.instrument.annotation.NullSpanTagAnnotationHandlerTests {
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
OtelTestSpanHandler testSpanHandlerSupplier() {
return new OtelTestSpanHandler(new ArrayListSpanProcessor());
}
@Bean
Sampler alwaysSampler() {
return Sampler.alwaysOn();
}
}
}

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.annotation;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.SpanId;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceId;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.otel.OtelTestSpanHandler;
import org.springframework.cloud.sleuth.otel.bridge.ArrayListSpanProcessor;
import org.springframework.cloud.sleuth.otel.bridge.OtelAccessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
@ContextConfiguration(classes = SleuthSpanCreatorAspectFluxTests.Config.class)
public class SleuthSpanCreatorAspectFluxTests
extends org.springframework.cloud.sleuth.instrument.annotation.SleuthSpanCreatorAspectFluxTests {
@Override
public TraceContext traceContext() {
return OtelAccessor.traceContext(SpanContext.create(TraceId.fromLongs(1L, 0L), SpanId.fromLong(2L),
TraceFlags.getSampled(), TraceState.builder().build()));
}
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
OtelTestSpanHandler testSpanHandlerSupplier() {
return new OtelTestSpanHandler(new ArrayListSpanProcessor());
}
@Bean
Sampler alwaysSampler() {
return Sampler.alwaysOn();
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2013-2020 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.cloud.sleuth.otel.annotation;
import io.opentelemetry.sdk.trace.samplers.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.otel.OtelTestSpanHandler;
import org.springframework.cloud.sleuth.otel.bridge.ArrayListSpanProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
@ContextConfiguration(classes = SleuthSpanCreatorAspectMonoTests.Config.class)
public class SleuthSpanCreatorAspectMonoTests
extends org.springframework.cloud.sleuth.instrument.annotation.SleuthSpanCreatorAspectMonoTests {
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
OtelTestSpanHandler testSpanHandlerSupplier() {
return new OtelTestSpanHandler(new ArrayListSpanProcessor());
}
@Bean
Sampler alwaysSampler() {
return Sampler.alwaysOn();
}
}
}

Some files were not shown because too many files have changed in this diff Show More