Spring Cloud Sleuth currently is an autoconfiguration over Brave. It also consists of various instrumentation mechanisms for libraries that are not supported by Brave (e.g. Spring Cloud Circuitbreaker).
We would like to abstract Brave so that Spring Cloud Sleuth becomes an autoconfiguration for any tracer implementation that is compatible with Spring Cloud Sleuth. That way Spring Cloud Sleuth in its core module would consist of an API and various tracer implementations would implement that API which would also allow automatic instrumentation of libraries that are supported by Spring Cloud Sleuth.
## OpenTelemetry Support
Thanks to doing this abstraction we are able to support new tracer implementations, not only Brave. We've decided to add support for the OpenTelemetry SDK as the second one. If in the future if we decide to add new tracers then it will be just a matter of adding a new module that bridges to the Spring Cloud Sleuth one. Thanks to abstraction of tests as well we will be easily able to plug that tracer mechanism into our current suite of tests.
`SpanHandler` is the base type for the now deprecated `FinishedSpanHandler`.
Notable, it can not just handle things at the end of a recording, but also the
beginning.
For example, this permits set-once baggage without the HTTP abstraction:
```java
static final BaggageField EPOCH_SECONDS = BaggageField.create("epoch_seconds");
static final class RootOnlyBaggage extends SpanHandler {
@Override
public boolean begin(TraceContext context, MutableSpan span, @Nullable TraceContext parent) {
if (EPOCH_SECONDS.getValue(context) == null) { // only set at the first span
long epochSeconds = System.currentTimeMillis() / 1000;
EPOCH_SECONDS.updateValue(context, String.valueOf(epochSeconds));
}
return true;
}
@Override public boolean end(TraceContext context, MutableSpan span, Cause cause) {
Tags.BAGGAGE_FIELD.tag(EPOCH_SECONDS, context, span);
return true;
}
}
```
As the parent is available, it can also facilitate advanced tasks like counting
children, or summarizing entire local roots.
See https://github.com/openzipkin/brave/tree/master/brave/src/test/java/brave/features/handler
and https://github.com/openzipkin/brave/blob/master/brave/src/main/java/brave/handler/SpanHandler.java for more
Sleuth is unlike most tracing configuration libraries, as it has a
legacy from 1.x as being primarily log correlation. In short, when
Zipkin is not installed, it ignored the sampling properties. This
behavior was managed implicitly through an untested combination of
configuration conventions between the core and zipkin modules.
16fb8e3 broke this and this change puts it back, in a way not tightly
coupled to Zipkin and neither requires the more simple, but confusing
"import SamplerAutoConfiguration" approach. It also backfills tests
that should have broken earlier.
In practice, a site that only uses logging is likely uniform in that, so
whether or not the sampled bit is set is of no consequence. However,
there's a chance that someone might rely on this historical behavior.
We should follow-up on 3.0 and remove this as it is very unintuitive to
intentionally ignore sampling properties. For now, this restores the old
behavior based on heuristics of bean definitions.
While some overview is important, the direct implementation details of tracing
not only drifted since Sleuth 1.x, but also caused a complaint #1466
This deletes most documentation that applies to an abstraction lower than sleuth
and reworks existing docs to focus on features it enables. By doing so, we have
less to maintain and users will have a clearer idea about the relationship
between Sleuth, Zipkin and Brave. Also important is this uses updated screen
shots and is in general less cluttered than before.
Note: the relationship between Sleuth and Brave was already redone in #1603
Note: this also removes the pws app which is usually broken or out of date.
Fixes#1466
This moves code and properties under org.springframework.cloud.sleuth.baggage
Properties are now under "spring.sleuth.baggage"
Those coming from 2.x should migrate with the following:
* spring.sleuth.baggage-keys -> `BaggagePropagationCustomizer`
* spring.sleuth.local-keys -> spring.sleuth.baggage.local-fields
* spring.sleuth.propagation-keys -> spring.sleuth.baggage.remote-fields
* spring.sleuth.propagation.tag.whitelisted-keys -> spring.sleuth.baggage.tag-fields
* spring.sleuth.log.slf4j.whitelisted-mdc-keys -> spring.sleuth.baggage.correlation-fields
* spring.sleuth.log.slf4j.enabled -> spring.sleuth.baggage.correlation-enabled
Those using MDC should know that for performance reasons, we no longer
set the following fields: `parentId` `spanExportable`.
We also do not set fields to "dirty" by default. Doing this by default
raised the overhead substantially, especially in reactive applications.
Those who want sleuth to override manual `MDC.put` operations as
described in #1416, or with to add back `parentId` `spanExportable` need
to define their own bean:
Ex. this is the former setup:
```java
@Bean CorrelationScopeDecorator oldConfig(List<String> myFieldNames) {
CorrelationScopeDecorator.Builder builder = MDCScopeDecorator.newBuilder().clear()
.add(SingleCorrelationField.create(BaggageFields.TRACE_ID))
.add(SingleCorrelationField.create(BaggageFields.PARENT_ID))
.add(SingleCorrelationField.create(BaggageFields.SPAN_ID))
.add(SingleCorrelationField.newBuilder(BaggageFields.SAMPLED)
.name("spanExportable").build());
// Set all fields dirty, so that any changes made by MDC directly are reverted.
for (String name : myFieldNames) {
builder.add(SingleCorrelationField.newBuilder(BaggageField.create(name))
.dirty().build());
}
return builder.build();
}
```
The `spring.sleuth.baggage-keys` property assigned two headers for each
baggage. This causes unnecessary overhead and can be accomplished in another
way now:
```java
public class MyCode {
static final BaggageField USER_ID = BaggageField.create("userId");
@Autowired CurrentTraceContext currentTraceContext;
@Nullable
public String currentUserId() {
return USER_ID.getValue(currentTraceContext.get());
}
}
// In your @Configuration type, if you want to map multiple prefixes...
@Bean
BaggagePropagationConfig userIdBaggageConfig() {
return SingleBaggageField.newBuilder(MyBaggage.USER_ID)
.addKeyName("baggage-userId")
.addKeyName("baggage_userId")
.build();
}
```