Skip to content

Commit

Permalink
Merge branch 'master' into sezen.leblay/APPSEC-55380-translateEscapes…
Browse files Browse the repository at this point in the history
…-propagation
  • Loading branch information
sezen-datadog authored Jan 15, 2025
2 parents 378bd84 + 8b63e5a commit 65ee3e0
Show file tree
Hide file tree
Showing 44 changed files with 1,179 additions and 129 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.continue.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ instrumentation_modules: &instrumentation_modules "dd-java-agent/instrumentation
debugger_modules: &debugger_modules "dd-java-agent/agent-debugger|dd-java-agent/agent-bootstrap|dd-java-agent/agent-builder|internal-api|communication|dd-trace-core"
profiling_modules: &profiling_modules "dd-java-agent/agent-profiling"

default_system_tests_commit: &default_system_tests_commit c6e54d143cfdf97b2f0a815f22f53247c119f635
default_system_tests_commit: &default_system_tests_commit 2d531d6f809cfcdd5d6d375f92bda86202dea332

parameters:
nightly:
Expand Down
2 changes: 0 additions & 2 deletions components/context/src/main/java/datadog/context/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import static datadog.context.ContextProviders.manager;

import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;

/**
* Immutable context scoped to an execution unit or carrier object.
Expand Down Expand Up @@ -36,7 +35,6 @@
*
* @see ContextKey
*/
@ParametersAreNonnullByDefault
public interface Context {
/**
* Returns the root context.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package datadog.context;

import javax.annotation.ParametersAreNonnullByDefault;

/** Binds context to carrier objects. */
@ParametersAreNonnullByDefault
public interface ContextBinder {
/**
* Returns the context attached to the given carrier object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*/
public final class ContextKey<T> {
private static final AtomicInteger NEXT_INDEX = new AtomicInteger(0);
/** The key name, for debugging purpose only . */
/** The key name, for debugging purpose only. */
private final String name;
/** The key unique context, related to {@link IndexedContext} implementation. */
final int index;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@ParametersAreNonnullByDefault
package datadog.context;

import javax.annotation.ParametersAreNonnullByDefault;
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package datadog.context.propagation;

import javax.annotation.Nullable;

@FunctionalInterface
public interface CarrierSetter<C> {
/**
* Sets a carrier key/value pair.
*
* @param carrier the carrier to store key/value into.
* @param key the key to set.
* @param value the value to set.
*/
void set(@Nullable C carrier, String key, String value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package datadog.context.propagation;

import java.util.function.BiConsumer;

/**
* This interface represents the capacity of walking through a carrier content, iterating over its
* key/value pairs.
*
* <p>Walking through carrier is preferred to direct access to carrier key/value pairs as some
* carrier implementations do not have built-in direct access and require walking over the full
* carrier structure to find the requested key/value pair, leading to multiple walks when multiple
* keys are requested, whereas the visitor is expected to walk through only once, and the
* propagators to keep the data they need using the visitor callback.
*
* @param <C> the type of carrier.
*/
@FunctionalInterface
public interface CarrierVisitor<C> {
/**
* Iterates over the carrier content and calls the visitor callback for every key/value found.
*
* @param carrier the carrier to iterate over.
* @param visitor the callback to call for each carrier key/value pair found.
*/
void forEachKeyValue(C carrier, BiConsumer<String, String> visitor);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package datadog.context.propagation;

import datadog.context.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;

class CompositePropagator implements Propagator {
private final Propagator[] propagators;

CompositePropagator(Propagator[] propagators) {
this.propagators = propagators;
}

@Override
public <C> void inject(Context context, C carrier, CarrierSetter<C> setter) {
for (Propagator propagator : this.propagators) {
propagator.inject(context, carrier, setter);
}
}

@Override
public <C> Context extract(Context context, C carrier, CarrierVisitor<C> visitor) {
// Extract and cache carrier key/value pairs
CarrierCache carrierCache = new CarrierCache();
visitor.forEachKeyValue(carrier, carrierCache);
// Run the multiple extractions on cache
for (Propagator propagator : this.propagators) {
context = propagator.extract(context, carrierCache, carrierCache);
}
return context;
}

static class CarrierCache implements BiConsumer<String, String>, CarrierVisitor<CarrierCache> {
/** Cached key/values from carrier (even indexes are keys, odd indexes are values). */
private final List<String> keysAndValues;

public CarrierCache() {
this.keysAndValues = new ArrayList<>(32);
}

@Override
public void accept(String key, String value) {
this.keysAndValues.add(key);
this.keysAndValues.add(value);
}

@Override
public void forEachKeyValue(CarrierCache carrier, BiConsumer<String, String> visitor) {
for (int i = 0; i < carrier.keysAndValues.size() - 1; i += 2) {
visitor.accept(carrier.keysAndValues.get(i), carrier.keysAndValues.get(i + 1));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package datadog.context.propagation;

import static java.util.Objects.requireNonNull;

import datadog.context.Context;

/** This class defines a cross-cutting concern to be propagated from a {@link Context}. */
public class Concern {
/** The concern default priority. */
public static final int DEFAULT_PRIORITY = 100;
/** The concern name, for debugging purpose only. */
private final String name;
/** The concern priority, lower value means higher priority. */
private final int priority;

/**
* Creates a concern.
*
* @param name the concern name, for debugging purpose only.
* @return The created concern.
*/
public static Concern named(String name) {
return new Concern(name, DEFAULT_PRIORITY);
}

/**
* Creates a concern with a specific priority.
*
* @param name the concern name, for debugging purpose only.
* @param priority the concern priority (lower value means higher priority, while the default is
* {@link #DEFAULT_PRIORITY}),
* @return The created concern.
*/
public static Concern withPriority(String name, int priority) {
return new Concern(name, priority);
}

private Concern(String name, int priority) {
requireNonNull(name, "Concern name cannot be null");
if (priority < 0) {
throw new IllegalArgumentException("Concern priority cannot be negative");
}
this.name = name;
this.priority = priority;
}

int priority() {
return this.priority;
}

// We want identity equality, so no need to override equals().

@Override
public String toString() {
return this.name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package datadog.context.propagation;

import datadog.context.Context;

final class NoopPropagator implements Propagator {
static final NoopPropagator INSTANCE = new NoopPropagator();

private NoopPropagator() {}

@Override
public <C> void inject(Context context, C carrier, CarrierSetter<C> setter) {
// noop
}

@Override
public <C> Context extract(Context context, C carrier, CarrierVisitor<C> visitor) {
return context;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package datadog.context.propagation;

import datadog.context.Context;

/**
* This interface represents a {@link Context} propagator for a given {@link Concern}.
*
* <p>Its goal is to {@link #inject} context values into carriers, or {@link #extract} them from
* carriers to populate context. Carrier could be any kind of object that stores key/value pairs,
* like HTTP or messages headers. {@link CarrierSetter}s and {@link CarrierVisitor}s define how to
* store and retrieve key/value pairs from carriers.
*/
public interface Propagator {
/**
* Injects a context into a downstream service using the given carrier.
*
* @param context the context containing the values to be injected.
* @param carrier the instance that will receive the key/value pairs to propagate.
* @param setter the callback to set key/value pairs into the carrier.
* @param <C> the type of carrier instance.
*/
<C> void inject(Context context, C carrier, CarrierSetter<C> setter);

/**
* Extracts a context from un upstream service.
*
* @param context the base context to store the extracted values on top, use {@link
* Context#root()} for a default base context.
* @param carrier the instance to fetch the propagated key/value pairs from.
* @param visitor the callback to walk over the carrier and extract its key/value pais.
* @param <C> the type of the carrier.
* @return A context with the extracted values on top of the given base context.
*/
<C> Context extract(Context context, C carrier, CarrierVisitor<C> visitor);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package datadog.context.propagation;

import static java.util.Collections.synchronizedMap;
import static java.util.Comparator.comparingInt;

import java.util.IdentityHashMap;
import java.util.Map;

public final class Propagators {
private static final Map<Concern, Propagator> PROPAGATORS =
synchronizedMap(new IdentityHashMap<>());
private static volatile Propagator defaultPropagator = null;
private static volatile boolean defaultPropagatorSet = false;

private Propagators() {}

/**
* Gets the default propagator that applies all registered propagators in their priority order.
*
* @return The default propagator.
*/
public static Propagator defaultPropagator() {
if (!defaultPropagatorSet) {
Propagator[] propagatorsByPriority =
PROPAGATORS.entrySet().stream()
.sorted(comparingInt(entry -> entry.getKey().priority()))
.map(Map.Entry::getValue)
.toArray(Propagator[]::new);
defaultPropagator = composite(propagatorsByPriority);
defaultPropagatorSet = true;
}
return defaultPropagator;
}

/**
* Gets the propagator for a given concern.
*
* @param concern the concern to get propagator for.
* @return the related propagator if registered, a {@link #noop()} propagator otherwise.
*/
public static Propagator forConcern(Concern concern) {
return PROPAGATORS.getOrDefault(concern, NoopPropagator.INSTANCE);
}

/**
* Gets the propagator for the given concerns.
*
* @param concerns the concerns to get propagators for.
* @return A propagator that will apply the concern propagators if registered, in the given
* concern order.
*/
public static Propagator forConcerns(Concern... concerns) {
Propagator[] propagators = new Propagator[concerns.length];
for (int i = 0; i < concerns.length; i++) {
propagators[i] = forConcern(concerns[i]);
}
return composite(propagators);
}

/**
* Returns a noop propagator.
*
* @return a noop propagator.
*/
public static Propagator noop() {
return NoopPropagator.INSTANCE;
}

/**
* Creates a composite propagator.
*
* @param propagators the elements that composes the returned propagator.
* @return the composite propagator that will apply the propagators in their given order.
*/
public static Propagator composite(Propagator... propagators) {
if (propagators.length == 0) {
return NoopPropagator.INSTANCE;
} else if (propagators.length == 1) {
return propagators[0];
} else {
return new CompositePropagator(propagators);
}
}

/**
* Registers a propagator for concern.
*
* @param concern The concern to register a propagator for.
* @param propagator The propagator to register.
*/
public static void register(Concern concern, Propagator propagator) {
PROPAGATORS.put(concern, propagator);
defaultPropagatorSet = false;
}

/** Clear all registered propagators. For testing purpose only. */
static void reset() {
PROPAGATORS.clear();
defaultPropagatorSet = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@ParametersAreNonnullByDefault
package datadog.context.propagation;

import javax.annotation.ParametersAreNonnullByDefault;
Loading

0 comments on commit 65ee3e0

Please sign in to comment.