Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Now MultiTextMapPropagator allows to select extractors and injectors separately #3366

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.context.propagation;

import java.util.ArrayList;
import java.util.List;

/**
* A builder for configuring an {@link TextMapPropagator} specifying which propagators should be used for extracting the context and which should be used for injecting the context.
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
*/
public final class CompositeTextMapPropagatorBuilder {

private final List<TextMapPropagator> extractors;
private final List<TextMapPropagator> injectors;

/**
* Package protected to disallow direct initialization.
*
* @see TextMapPropagator#builder()
*/
CompositeTextMapPropagatorBuilder() {
this.extractors = new ArrayList<>();
this.injectors = new ArrayList<>();
}

/**
* Add a {@link TextMapPropagator} to be used only to extract the context.
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
*/
public CompositeTextMapPropagatorBuilder extractor(TextMapPropagator propagator) {
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
this.extractors.add(propagator);
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
return this;
}

/**
* Add a {@link TextMapPropagator} to be used only to inject the context.
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
*/
public CompositeTextMapPropagatorBuilder injector(TextMapPropagator propagator) {
this.injectors.add(propagator);
return this;
}

/**
* Add a {@link TextMapPropagator} to be used both to extract and inject the context.
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
*/
public CompositeTextMapPropagatorBuilder propagator(TextMapPropagator propagator) {
this.injectors.add(propagator);
this.extractors.add(propagator);
return this;
}

/**
* Returns the built {@link TextMapPropagator}
*
* @see CompositeTextMapPropagatorBuilder
*/
public TextMapPropagator build() {
if (this.injectors.isEmpty()) {
this.injectors.add(TextMapPropagator.noop());
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
}
if (this.extractors.isEmpty()) {
this.extractors.add(TextMapPropagator.noop());
}

return new MultiTextMapPropagator(this.extractors, this.injectors);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,29 @@
import javax.annotation.Nullable;

final class MultiTextMapPropagator implements TextMapPropagator {
slinkydeveloper marked this conversation as resolved.
Show resolved Hide resolved
private final TextMapPropagator[] textPropagators;
private final TextMapPropagator[] extractors;
private final TextMapPropagator[] injectors;
private final Collection<String> allFields;

MultiTextMapPropagator(TextMapPropagator... textPropagators) {
this(Arrays.asList(textPropagators));
}

MultiTextMapPropagator(List<TextMapPropagator> textPropagators) {
this.textPropagators = new TextMapPropagator[textPropagators.size()];
textPropagators.toArray(this.textPropagators);
this.allFields = Collections.unmodifiableList(getAllFields(this.textPropagators));
this.extractors = new TextMapPropagator[textPropagators.size()];
textPropagators.toArray(this.extractors);
this.injectors = this.extractors; // No need to copy
this.allFields = Collections.unmodifiableList(getAllFields(this.injectors));
}

MultiTextMapPropagator(List<TextMapPropagator> extractors, List<TextMapPropagator> injectors) {
this.extractors = new TextMapPropagator[extractors.size()];
extractors.toArray(this.extractors);

this.injectors = new TextMapPropagator[injectors.size()];
injectors.toArray(this.injectors);

this.allFields = Collections.unmodifiableList(getAllFields(this.injectors));
}

@Override
Expand All @@ -48,7 +60,7 @@ public <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> se
if (context == null || setter == null) {
return;
}
for (TextMapPropagator textPropagator : textPropagators) {
for (TextMapPropagator textPropagator : injectors) {
textPropagator.inject(context, carrier, setter);
}
}
Expand All @@ -61,7 +73,7 @@ public <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C
if (getter == null) {
return context;
}
for (TextMapPropagator textPropagator : textPropagators) {
for (TextMapPropagator textPropagator : extractors) {
context = textPropagator.extract(context, carrier, getter);
}
return context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
@ThreadSafe
public interface TextMapPropagator {

/**
* Returns a composite text map propagator builder that allows to specify specific propagators as extractors and specific propagators as injectors.
*/
static CompositeTextMapPropagatorBuilder builder() {
return new CompositeTextMapPropagatorBuilder();
}

/**
* Returns a {@link TextMapPropagator} which simply delegates injection and extraction to the
* provided propagators.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

Expand Down Expand Up @@ -168,4 +169,32 @@ void inject_nullSetter() {
new MultiTextMapPropagator(propagator1, propagator2).inject(context, carrier, null);
assertThat(carrier).isEmpty();
}

@Test
void different_inject_and_extract() {
Map<String, String> carrier = new HashMap<>();

TextMapPropagator prop = TextMapPropagator.builder()
.injector(propagator1)
.extractor(propagator2)
.propagator(propagator3)
.build();

Context context1 = mock(Context.class);
Context context2 = mock(Context.class);
Context expectedContext = mock(Context.class);

when(propagator2.extract(context1, carrier, getter)).thenReturn(context2);
when(propagator3.extract(context2, carrier, getter)).thenReturn(expectedContext);

assertThat(prop.extract(context1, carrier, getter)).isEqualTo(expectedContext);

Context context = mock(Context.class);
TextMapSetter<Map<String, String>> setter = Map::put;

prop.inject(context, carrier, setter);
verify(propagator1).inject(context, carrier, setter);
verify(propagator2, never()).inject(context, carrier, setter);
verify(propagator3).inject(context, carrier, setter);
}
}