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();
}