Skip to content

Commit

Permalink
Added an option to have baggage through Observation API (#688)
Browse files Browse the repository at this point in the history
whenever a key-value matches a preconfigured baggage config and an Observation started a scope then automatically baggages will also be started

fixes gh-455
  • Loading branch information
marcingrzejszczak authored May 20, 2024
1 parent ba27961 commit 4b2a93e
Show file tree
Hide file tree
Showing 12 changed files with 298 additions and 39 deletions.
15 changes: 15 additions & 0 deletions docs/modules/ROOT/pages/api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ IMPORTANT: For Brave, remember to set up the `PropagationFactory` so that it con
include::{include-java}/tracing/TracingApiTests.java[tags=baggage_brave_setup,indent=0]
-----

=== Baggage with Micrometer Observation API

If you're using Micrometer Observation API, there's no notion of baggage. If you set up a `BaggageManager` to have the baggage fields configured, we will assume that when the Observation gets put in scope, whatever low and high cardinality keys are set on the Observation will be put in scope as baggage (assuming that their names match with the configuration on the `BaggageManager`). Below you can find example of such setup with OpenTelemetry `BaggageManager`.

[source,java,subs=+attributes]
-----
include::{include-bridges-java}/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/BaggageTests.java[tags=baggageManager,indent=0]
include::{include-bridges-java}/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/BaggageTests.java[tags=observationRegistrySetup,indent=0]
include::{include-bridges-java}/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/BaggageTests.java[tags=observation,indent=0]
include::{include-bridges-java}/micrometer-tracing-bridge-otel/src/test/java/io/micrometer/tracing/otel/bridge/BaggageTests.java[tags=observationScope,indent=0]
-----

== Aspect Oriented Programming

Micrometer Tracing contains `@NewSpan`, `@ContinueSpan`, and `@SpanTag` annotations that frameworks can use to create or customize spans for either specific types of methods such as those serving web request endpoints or, more generally, to all methods.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022 the original author or authors.
* Copyright 2024 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.
Expand All @@ -22,9 +22,7 @@
import io.micrometer.tracing.*;

import java.io.Closeable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.*;

/**
* Brave implementation of a {@link BaggageManager}.
Expand All @@ -36,15 +34,28 @@ public class BraveBaggageManager implements Closeable, BaggageManager {

private final List<String> tagFields;

private final List<String> remoteFields;

private final List<String> baggageFields;

@Nullable
private Tracer tracer;

/**
* Create an instance of {@link BraveBaggageManager}.
* @param tagFields fields of baggage keys that should become tags on a span
* @param remoteFields fields of baggage keys that should be propagated over the wire
*/
public BraveBaggageManager(List<String> tagFields) {
public BraveBaggageManager(List<String> tagFields, List<String> remoteFields) {
this.tagFields = tagFields;
this.remoteFields = remoteFields;
this.baggageFields = baggageFields(tagFields, remoteFields);
}

private static List<String> baggageFields(List<String> tagFields, List<String> remoteFields) {
Set<String> combined = new HashSet<>(tagFields);
combined.addAll(remoteFields);
return new ArrayList<>(combined);
}

/**
Expand All @@ -53,6 +64,18 @@ public BraveBaggageManager(List<String> tagFields) {
*/
public BraveBaggageManager() {
this.tagFields = Collections.emptyList();
this.remoteFields = Collections.emptyList();
this.baggageFields = Collections.emptyList();
}

/**
* Create an instance of {@link BraveBaggageManager}.
* @param tagFields fields of baggage keys that should become tags on a span
*/
public BraveBaggageManager(List<String> tagFields) {
this.tagFields = tagFields;
this.remoteFields = Collections.emptyList();
this.baggageFields = new ArrayList<>(tagFields);
}

@Override
Expand Down Expand Up @@ -136,4 +159,9 @@ void setTracer(Tracer tracer) {
this.tracer = tracer;
}

@Override
public List<String> getBaggageFields() {
return this.baggageFields;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import brave.propagation.TraceContextOrSamplingFlags;
import io.micrometer.tracing.*;

import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -156,6 +157,11 @@ public CurrentTraceContext currentTraceContext() {
return this.currentTraceContext;
}

@Override
public List<String> getBaggageFields() {
return this.braveBaggageManager.getBaggageFields();
}

}

class BraveSpanInScope implements Tracer.SpanInScope {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022 the original author or authors.
* Copyright 2024 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.
Expand Down Expand Up @@ -27,13 +27,17 @@
import io.micrometer.common.util.internal.logging.InternalLogger;
import io.micrometer.common.util.internal.logging.InternalLoggerFactory;
import io.micrometer.context.ContextRegistry;
import io.micrometer.observation.Observation;
import io.micrometer.observation.Observation.Scope;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import io.micrometer.tracing.*;
import io.micrometer.tracing.contextpropagation.ObservationAwareSpanThreadLocalAccessor;
import io.micrometer.tracing.handler.DefaultTracingObservationHandler;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import reactor.core.observability.micrometer.Micrometer;
import reactor.core.publisher.Hooks;
Expand All @@ -42,6 +46,7 @@
import reactor.core.scheduler.Schedulers;

import java.time.Duration;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -61,6 +66,10 @@ class BaggageTests {

public static final String TAG_VALUE = "tagValue";

public static final String OBSERVATION_BAGGAGE_KEY = "observationKey";

public static final String OBSERVATION_BAGGAGE_VALUE = "observationValue";

TestSpanHandler spanHandler = new TestSpanHandler();

StrictCurrentTraceContext braveCurrentTraceContext = StrictCurrentTraceContext.create();
Expand All @@ -73,6 +82,7 @@ class BaggageTests {
.traceId128Bit(true)
.propagationFactory(BaggagePropagation.newFactoryBuilder(B3Propagation.FACTORY)
.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(KEY_1)))
.add(BaggagePropagationConfig.SingleBaggageField.remote(BaggageField.create(OBSERVATION_BAGGAGE_KEY)))
.add(BaggagePropagationConfig.SingleBaggageField.local(BaggageField.create(TAG_KEY)))
.build())
.sampler(Sampler.ALWAYS_SAMPLE)
Expand All @@ -84,10 +94,15 @@ class BaggageTests {
BravePropagator propagator = new BravePropagator(tracing);

Tracer tracer = new BraveTracer(this.braveTracer, this.bridgeContext,
new BraveBaggageManager(Collections.singletonList(TAG_KEY)));
new BraveBaggageManager(Collections.singletonList(TAG_KEY), Arrays.asList(KEY_1, OBSERVATION_BAGGAGE_KEY)));

ObservationRegistry observationRegistry = ObservationThreadLocalAccessor.getInstance().getObservationRegistry();

@BeforeEach
void setupHandler() {
observationRegistry.observationConfig().observationHandler(new DefaultTracingObservationHandler(tracer));
}

@AfterEach
void cleanup() {
tracing.close();
Expand Down Expand Up @@ -258,6 +273,30 @@ void baggageTagKey() {
then(mutableSpan.tags().get(TAG_KEY)).isEqualTo(TAG_VALUE);
}

@Test
void baggageWithObservationApiWithRemoteFields() {
Observation observation = Observation.start("foo", observationRegistry)
.lowCardinalityKeyValue(KEY_1, TAG_VALUE)
.highCardinalityKeyValue(OBSERVATION_BAGGAGE_KEY, OBSERVATION_BAGGAGE_VALUE);
then(tracer.getBaggage(KEY_1).get()).isNull();
then(tracer.getBaggage(OBSERVATION_BAGGAGE_KEY).get()).isNull();

try (Scope scope = observation.openScope()) {
then(tracer.getBaggage(KEY_1).get()).isEqualTo(TAG_VALUE);
then(tracer.getBaggage(OBSERVATION_BAGGAGE_KEY).get()).isEqualTo(OBSERVATION_BAGGAGE_VALUE);
}

then(tracer.currentSpan()).isNull();
then(tracer.getBaggage(KEY_1).get()).isNull();
then(tracer.getBaggage(OBSERVATION_BAGGAGE_KEY).get()).isNull();
observation.stop();

then(spanHandler.spans()).hasSize(1);
MutableSpan mutableSpan = spanHandler.spans().get(0);
then(mutableSpan.tags().get(KEY_1)).isEqualTo(TAG_VALUE);
then(mutableSpan.tags().get(OBSERVATION_BAGGAGE_KEY)).isEqualTo(OBSERVATION_BAGGAGE_VALUE);
}

@Test
void baggageTagKeyWithLegacyApi() {
ScopedSpan span = this.tracer.startScopedSpan("call1");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,6 @@
*/
package io.micrometer.tracing.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.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;

import io.micrometer.common.lang.Nullable;
import io.micrometer.tracing.BaggageInScope;
import io.micrometer.tracing.BaggageManager;
Expand All @@ -38,6 +26,9 @@
import io.opentelemetry.api.baggage.BaggageEntryMetadata;
import io.opentelemetry.context.Context;

import java.util.*;
import java.util.function.BiConsumer;

import static java.util.Collections.unmodifiableCollection;
import static java.util.Collections.unmodifiableMap;
import static java.util.function.Function.identity;
Expand All @@ -60,6 +51,8 @@ public class OtelBaggageManager implements BaggageManager {

private final List<String> remoteFields;

private final List<String> baggageFields;

private final List<String> tagFields;

/**
Expand All @@ -73,6 +66,13 @@ public OtelBaggageManager(CurrentTraceContext currentTraceContext, List<String>
this.currentTraceContext = currentTraceContext;
this.remoteFields = remoteFields;
this.tagFields = tagFields;
this.baggageFields = baggageFields(tagFields, remoteFields);
}

private static List<String> baggageFields(List<String> tagFields, List<String> remoteFields) {
Set<String> combined = new HashSet<>(tagFields);
combined.addAll(remoteFields);
return new ArrayList<>(combined);
}

@Override
Expand Down Expand Up @@ -213,6 +213,11 @@ private String propagationString(boolean remoteField) {
return propagation;
}

@Override
public List<String> getBaggageFields() {
return this.remoteFields;
}

}

class CompositeBaggage implements io.opentelemetry.api.baggage.Baggage {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022 the original author or authors.
* Copyright 2024 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.
Expand All @@ -19,6 +19,7 @@
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;

import java.util.List;
import java.util.Map;

/**
Expand Down Expand Up @@ -196,6 +197,11 @@ public BaggageInScope createBaggageInScope(TraceContext traceContext, String nam
return this.otelBaggageManager.createBaggageInScope(traceContext, name, value);
}

@Override
public List<String> getBaggageFields() {
return this.otelBaggageManager.getBaggageFields();
}

/**
* Publisher of events.
*/
Expand Down
Loading

0 comments on commit 4b2a93e

Please sign in to comment.