CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-opentelemetry--opentelemetry-context

OpenTelemetry Context propagation mechanism for carrying scoped values across API boundaries and between threads in Java applications

Pending
Overview
Eval results
Files

context-propagation.mddocs/

Context Propagation

Context propagation enables transmission of contextual information across service boundaries using configurable text map propagators. This is essential for distributed tracing, baggage propagation, and other cross-cutting concerns in microservices architectures.

Context Propagators

Creating Context Propagators

Creates a ContextPropagators instance with a text map propagator.

static ContextPropagators create(TextMapPropagator textPropagator);

Parameters:

  • textPropagator - The text map propagator to use

Returns: A ContextPropagators instance

Usage Example:

// Create with single propagator
TextMapPropagator traceContext = HttpTraceContext.getInstance();
ContextPropagators propagators = ContextPropagators.create(traceContext);

// Create with composite propagator
TextMapPropagator composite = TextMapPropagator.composite(
    HttpTraceContext.getInstance(),
    W3CBaggagePropagator.getInstance(),
    new CustomPropagator()
);
ContextPropagators propagators = ContextPropagators.create(composite);

No-op Context Propagators

Creates a no-op ContextPropagators that performs no injection or extraction.

static ContextPropagators noop();

Usage Example:

ContextPropagators noopPropagators = ContextPropagators.noop();
TextMapPropagator propagator = noopPropagators.getTextMapPropagator();
// propagator.fields() returns empty collection
// propagator.inject() does nothing
// propagator.extract() returns original context

Get Text Map Propagator

Returns the composite text map propagator.

TextMapPropagator getTextMapPropagator();

Usage Example:

ContextPropagators propagators = ContextPropagators.create(somePropagator);
TextMapPropagator textMapPropagator = propagators.getTextMapPropagator();

// Use for injection/extraction
Map<String, String> headers = new HashMap<>();
textMapPropagator.inject(Context.current(), headers, Map::put);

Text Map Propagation

Composite Propagators

Creates a composite propagator that delegates to multiple propagators.

static TextMapPropagator composite(TextMapPropagator... propagators);
static TextMapPropagator composite(Iterable<TextMapPropagator> propagators);

Usage Example:

// Array version
TextMapPropagator composite = TextMapPropagator.composite(
    HttpTraceContext.getInstance(),
    W3CBaggagePropagator.getInstance(),
    JaegerPropagator.getInstance()
);

// Iterable version
List<TextMapPropagator> propagatorList = Arrays.asList(
    HttpTraceContext.getInstance(),
    CustomPropagator.getInstance()
);
TextMapPropagator composite = TextMapPropagator.composite(propagatorList);

No-op Text Map Propagator

Creates a no-op propagator that performs no operations.

static TextMapPropagator noop();

Get Propagation Fields

Returns the field names that will be used for propagation.

Collection<String> fields();

Usage Example:

TextMapPropagator propagator = TextMapPropagator.composite(
    HttpTraceContext.getInstance(),
    W3CBaggagePropagator.getInstance()
);

Collection<String> fields = propagator.fields();
// Might return: ["traceparent", "tracestate", "baggage"]

// Clear fields before injection if reusing carrier
for (String field : fields) {
    headers.remove(field);
}

Context Injection

Injects context data into a carrier for downstream consumption.

<C> void inject(Context context, C carrier, TextMapSetter<C> setter);

Parameters:

  • context - The context containing values to inject
  • carrier - The carrier to inject into (e.g., HTTP headers)
  • setter - Function to set values in the carrier

Usage Example:

// HTTP client injection
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
Map<String, String> headers = new HashMap<>();

// Inject current context
TextMapPropagator propagator = propagators.getTextMapPropagator();
propagator.inject(Context.current(), headers, (map, key, value) -> {
    map.put(key, value);
    connection.setRequestProperty(key, value);
});

// Alternative with lambda
propagator.inject(Context.current(), connection, HttpURLConnection::setRequestProperty);

Context Extraction

Extracts context data from a carrier and merges with existing context.

<C> Context extract(Context context, C carrier, TextMapGetter<C> getter);

Parameters:

  • context - The base context to merge extracted data into
  • carrier - The carrier containing propagated data
  • getter - Function to retrieve values from the carrier

Returns: A new Context with extracted data merged in

Usage Example:

// HTTP server extraction
HttpServletRequest request = getRequest();

TextMapPropagator propagator = propagators.getTextMapPropagator();
Context extractedContext = propagator.extract(
    Context.current(),
    request,
    new TextMapGetter<HttpServletRequest>() {
        @Override
        public Iterable<String> keys(HttpServletRequest carrier) {
            return Collections.list(carrier.getHeaderNames());
        }
        
        @Override
        public String get(HttpServletRequest carrier, String key) {
            return carrier.getHeader(key);
        }
    }
);

// Use extracted context
try (Scope scope = extractedContext.makeCurrent()) {
    processRequest();
}

Text Map Getters and Setters

Text Map Getter

Interface for extracting values from carriers.

interface TextMapGetter<C> {
    Iterable<String> keys(C carrier);
    String get(C carrier, String key);
    default Iterator<String> getAll(C carrier, String key);
}

Usage Example:

// HTTP headers getter
TextMapGetter<Map<String, String>> httpGetter = new TextMapGetter<Map<String, String>>() {
    @Override
    public Iterable<String> keys(Map<String, String> carrier) {
        return carrier.keySet();
    }
    
    @Override
    public String get(Map<String, String> carrier, String key) {
        return carrier.get(key);
    }
    
    @Override
    public Iterator<String> getAll(Map<String, String> carrier, String key) {
        String value = carrier.get(key);
        return value != null ? Collections.singleton(value).iterator() 
                            : Collections.emptyIterator();
    }
};

Text Map Setter

Interface for setting values in carriers.

interface TextMapSetter<C> {
    void set(C carrier, String key, String value);
}

Usage Example:

// HTTP headers setter
TextMapSetter<HttpURLConnection> httpSetter = (connection, key, value) -> {
    connection.setRequestProperty(key, value);
};

// Map setter
TextMapSetter<Map<String, String>> mapSetter = Map::put;

Complete Propagation Examples

HTTP Client with Propagation

public class HttpClientWithPropagation {
    private final ContextPropagators propagators;
    
    public HttpClientWithPropagation(ContextPropagators propagators) {
        this.propagators = propagators;
    }
    
    public String makeRequest(String url) throws IOException {
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        
        // Inject current context into HTTP headers
        TextMapPropagator propagator = propagators.getTextMapPropagator();
        propagator.inject(Context.current(), connection, (conn, key, value) -> {
            conn.setRequestProperty(key, value);
        });
        
        // Make request
        try (InputStream is = connection.getInputStream()) {
            return new String(is.readAllBytes(), StandardCharsets.UTF_8);
        }
    }
}

HTTP Server with Propagation

public class HttpServerWithPropagation {
    private final ContextPropagators propagators;
    
    public HttpServerWithPropagation(ContextPropagators propagators) {
        this.propagators = propagators;
    }
    
    public void handleRequest(HttpServletRequest request, HttpServletResponse response) {
        // Extract context from incoming request
        TextMapPropagator propagator = propagators.getTextMapPropagator();
        Context extractedContext = propagator.extract(
            Context.current(),
            request,
            new HttpServletRequestGetter()
        );
        
        // Process request with extracted context
        try (Scope scope = extractedContext.makeCurrent()) {
            String result = processRequest(request);
            response.getWriter().write(result);
        } catch (IOException e) {
            response.setStatus(500);
        }
    }
    
    private static class HttpServletRequestGetter implements TextMapGetter<HttpServletRequest> {
        @Override
        public Iterable<String> keys(HttpServletRequest request) {
            return Collections.list(request.getHeaderNames());
        }
        
        @Override
        public String get(HttpServletRequest request, String key) {
            return request.getHeader(key);
        }
    }
}

Custom Propagator Implementation

public class CustomBaggagePropagator implements TextMapPropagator {
    private static final String BAGGAGE_HEADER = "custom-baggage";
    private static final Collection<String> FIELDS = Collections.singleton(BAGGAGE_HEADER);
    
    @Override
    public Collection<String> fields() {
        return FIELDS;
    }
    
    @Override
    public <C> void inject(Context context, C carrier, TextMapSetter<C> setter) {
        String baggage = context.get(CUSTOM_BAGGAGE_KEY);
        if (baggage != null) {
            setter.set(carrier, BAGGAGE_HEADER, baggage);
        }
    }
    
    @Override
    public <C> Context extract(Context context, C carrier, TextMapGetter<C> getter) {
        String baggage = getter.get(carrier, BAGGAGE_HEADER);
        if (baggage != null) {
            return context.with(CUSTOM_BAGGAGE_KEY, baggage);
        }
        return context;
    }
    
    private static final ContextKey<String> CUSTOM_BAGGAGE_KEY = 
        ContextKey.named("custom-baggage");
}

Integration Patterns

Spring Boot Integration

@Configuration
public class TracingConfiguration {
    
    @Bean
    public ContextPropagators contextPropagators() {
        return ContextPropagators.create(
            TextMapPropagator.composite(
                HttpTraceContext.getInstance(),
                W3CBaggagePropagator.getInstance()
            )
        );
    }
    
    @Bean
    public RestTemplate restTemplate(ContextPropagators propagators) {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getInterceptors().add(new TracingClientInterceptor(propagators));
        return restTemplate;
    }
}

Asynchronous Propagation

public class AsyncPropagationExample {
    private final ContextPropagators propagators;
    
    public CompletableFuture<String> processAsync(String data) {
        // Capture current context for propagation
        Context currentContext = Context.current();
        
        return CompletableFuture.supplyAsync(() -> {
            // Manually apply context in async operation
            try (Scope scope = currentContext.makeCurrent()) {
                return processWithContext(data);
            }
        });
    }
    
    public void sendMessage(String message) {
        // Serialize context for message queue
        Map<String, String> headers = new HashMap<>();
        TextMapPropagator propagator = propagators.getTextMapPropagator();
        propagator.inject(Context.current(), headers, Map::put);
        
        // Send message with headers
        messageQueue.send(message, headers);
    }
    
    public void receiveMessage(String message, Map<String, String> headers) {
        // Deserialize context from message headers
        TextMapPropagator propagator = propagators.getTextMapPropagator();
        
        TextMapGetter<Map<String, String>> getter = new TextMapGetter<Map<String, String>>() {
            @Override
            public Iterable<String> keys(Map<String, String> carrier) {
                return carrier.keySet();
            }
            
            @Override
            public String get(Map<String, String> carrier, String key) {
                return carrier.get(key);
            }
        };
        
        Context extractedContext = propagator.extract(Context.current(), headers, getter);
        
        try (Scope scope = extractedContext.makeCurrent()) {
            processMessage(message);
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-io-opentelemetry--opentelemetry-context

docs

context-keys-scoping.md

context-propagation.md

core-context.md

executor-integration.md

function-wrapping.md

implicit-context-values.md

index.md

storage-customization.md

tile.json