This version is still in development and is not considered stable yet. For the latest stable version, please use Micrometer Context Propagation 1.1.2!

Examples

The examples in this section use the Context Propagation library.

ThreadLocal Population

The following example shows a holder for ThreadLocal values.

ObservationThreadLocalHolder
/**
 * Example of a wrapper around ThreadLocal values.
 */
public class ObservationThreadLocalHolder {

    private static final ThreadLocal<String> holder = new ThreadLocal<>();

    public static void setValue(String value) {
        holder.set(value);
    }

    public static String getValue() {
        return holder.get();
    }

    public static void reset() {
        holder.remove();
    }

}

The following example shows a ThreadLocalAccessor that interacts with the holder.

ObservationThreadLocalAccessor
/**
 * Example {@link ThreadLocalAccessor} implementation.
 */
public class ObservationThreadLocalAccessor implements ThreadLocalAccessor<String> {

    public static final String KEY = "micrometer.observation";

    @Override
    public Object key() {
        return KEY;
    }

    @Override
    public String getValue() {
        return ObservationThreadLocalHolder.getValue();
    }

    @Override
    public void setValue(String value) {
        ObservationThreadLocalHolder.setValue(value);
    }

    @Override
    public void setValue() {
        ObservationThreadLocalHolder.reset();
    }

}

The following example shows one way to store and restore thread local values by using ThreadLocalAccessor, ContextSnapshot, and ContextRegistry.

// Create a new Context Registry (you can use a global too)
ContextRegistry registry = new ContextRegistry();
// Register thread local accessors (you can use SPI too)
registry.registerThreadLocalAccessor(new ObservationThreadLocalAccessor());

// When you set a thread local value...
ObservationThreadLocalHolder.setValue("hello");
// ... we can capture it using ContextSnapshot
ContextSnapshot snapshot = ContextSnapshotFactory.builder().contextRegistry(registry).build().captureAll();

// After capturing if you change the thread local value again ContextSnapshot will
// not see it
ObservationThreadLocalHolder.setValue("hola");
try {
    // We're populating the thread local values with what we had in
    // ContextSnapshot
    try (Scope scope = snapshot.setThreadLocals()) {
        // Within this scope you will see the stored thread local values
        then(ObservationThreadLocalHolder.getValue()).isEqualTo("hello");
    }
    // After the scope is closed we will come back to the previously present
    // values in thread local
    then(ObservationThreadLocalHolder.getValue()).isEqualTo("hola");
}
finally {
    // We're clearing the thread local values so that we don't pollute the thread
    ObservationThreadLocalHolder.reset();
}