Skip to content

Commit

Permalink
Merge branch '1.11.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
marcingrzejszczak committed Jul 20, 2023
2 parents 52ab89b + e00eb43 commit 8a129bc
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@
*/
public interface ObservationView {

/**
* Returns the {@link ObservationRegistry} attached to this observation.
* @return corresponding observation registry
* @since 1.10.10
*/
default ObservationRegistry getObservationRegistry() {
return ObservationRegistry.NOOP;
}

/**
* Returns the {@link ContextView} attached to this observation.
* @return corresponding context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ void notifyOnObservationStopped(Context context) {
this.handlers.descendingIterator().forEachRemaining(handler -> handler.onStop(context));
}

@Override
public ObservationRegistry getObservationRegistry() {
return this.registry;
}

static class SimpleScope implements Scope {

private static final InternalLogger log = InternalLoggerFactory.getInstance(SimpleScope.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ public class ObservationThreadLocalAccessor implements ThreadLocalAccessor<Obser
*/
public ObservationThreadLocalAccessor() {
instance = this;
log.debug("Remember to set the ObservationRegistry on this accessor!");
}

/**
Expand Down Expand Up @@ -111,11 +110,16 @@ public void setValue(Observation value) {

@Override
public void setValue() {
Observation currentObservation = observationRegistry.getCurrentObservation();
if (currentObservation == null) {
return;
}
ObservationRegistry registry = currentObservation.getObservationRegistry();
// Not closing a scope (we're not resetting)
// Creating a new one with empty context and opens a new scope
// This scope will remember the previously created one to
// which we will revert once "null scope" is closed
new NullObservation(observationRegistry).start().openScope();
new NullObservation(registry).start().openScope();
}

private void closeCurrentScope() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,34 +15,53 @@
*/
package io.micrometer.observation.contextpropagation;

import io.micrometer.context.ContextAccessor;
import io.micrometer.context.ContextExecutorService;
import io.micrometer.context.ContextRegistry;
import io.micrometer.context.ContextSnapshot;
import io.micrometer.context.ContextSnapshotFactory;
import io.micrometer.observation.NullObservation;
import io.micrometer.observation.Observation;
import io.micrometer.observation.Observation.Context;
import io.micrometer.observation.ObservationHandler;
import io.micrometer.observation.ObservationRegistry;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.Closeable;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;

import static org.assertj.core.api.BDDAssertions.then;
import static org.assertj.core.api.BDDAssertions.thenNoException;

class ObservationThreadLocalAccessorTests {

static ObservationRegistry globalObservationRegistry = ObservationRegistry.create();

static MapContextAccessor mapContextAccessor = new MapContextAccessor();

ExecutorService executorService = Executors.newSingleThreadExecutor();

ObservationRegistry observationRegistry = ObservationRegistry.create();

ObservationRegistry observationRegistry2 = ObservationRegistry.create();

ContextRegistry registry = new ContextRegistry();

@BeforeAll
static void beforeAll() {
ContextRegistry.getInstance().registerContextAccessor(mapContextAccessor);
}

@BeforeEach
void setup() {
observationRegistry.observationConfig().observationHandler(new TracingHandler());
registry.registerThreadLocalAccessor(new ObservationThreadLocalAccessor(observationRegistry));
registry.registerThreadLocalAccessor(new ObservationThreadLocalAccessor());
}

@AfterEach
Expand All @@ -53,6 +72,7 @@ void clean() {
@Test
void capturedThreadLocalValuesShouldBeCapturedRestoredAndCleared()
throws InterruptedException, ExecutionException, TimeoutException {
observationRegistry.observationConfig().observationHandler(new TracingHandler());

// given
Observation parent = Observation.start("parent", observationRegistry);
Expand Down Expand Up @@ -113,6 +133,17 @@ void capturedThreadLocalValuesShouldBeCapturedRestoredAndCleared()
}).get(5, TimeUnit.SECONDS);

then(scopeParent(inSecondScope)).isSameAs(inScope);

// when we're going through the null scope when there was a previous value
// in TL
ContextSnapshot withClearing = ContextSnapshotFactory.builder()
.clearMissing(true)
.build()
.captureFrom(new HashMap<>());
withClearing.wrap(this::thenCurrentObservationIsNullObservation).run();

then(child.getEnclosingScope()).isNotNull();
thenCurrentObservationHasParent(parent, child);
}
then(scopeParent(inScope)).isSameAs(null);
}
Expand All @@ -122,16 +153,69 @@ void capturedThreadLocalValuesShouldBeCapturedRestoredAndCleared()
then(child.getEnclosingScope()).isNull();
then(parent.getEnclosingScope()).isNull();

// when we're going through the null scope when there was no previous value in TL
ContextSnapshot withClearing = ContextSnapshotFactory.builder()
.clearMissing(true)
.build()
.captureFrom(new HashMap<>());
withClearing.wrap(this::thenCurrentObservationIsNull).run();

then(child.getEnclosingScope()).isNull();
then(parent.getEnclosingScope()).isNull();

child.stop();
parent.stop();

then(child.getEnclosingScope()).isNull();
then(parent.getEnclosingScope()).isNull();
}

@Test
void uses2DifferentObservationRegistries() {
AtomicReference<String> calledHandler = new AtomicReference<>("");

TestHandler testHandlerForOR1 = new TestHandler("handler 1", calledHandler);
observationRegistry.observationConfig().observationHandler(testHandlerForOR1);
TestHandler testHandlerForOR2 = new TestHandler("handler 2", calledHandler);
observationRegistry2.observationConfig().observationHandler(testHandlerForOR2);

// given
Observation parent = Observation.start("parent", observationRegistry);
Observation child = Observation.createNotStarted("child2", observationRegistry)
.parentObservation(parent)
.start();
thenCurrentObservationIsNull();

Observation parent2 = Observation.start("parent2", observationRegistry2);
Observation child2 = Observation.createNotStarted("child2", observationRegistry2)
.parentObservation(parent2)
.start();
thenCurrentObservationIsNull();

try (Observation.Scope scope = child.openScope()) {
try (Observation.Scope scope2 = child2.openScope()) {
thenCurrentObservationHasParent(parent2, child2);
}
then(calledHandler.get()).isEqualTo("handler 2");
}
then(calledHandler.get()).isEqualTo("handler 1");

then(child.getEnclosingScope()).isNull();
thenCurrentObservationIsNull();

child.stop();
child2.stop();
parent.stop();
parent2.stop();

thenCurrentObservationIsNull();
}

@Test
void acceptsANullCurrentScopeOnRestore() {
thenNoException().isThrownBy(() -> new ObservationThreadLocalAccessor(observationRegistry) {
observationRegistry.observationConfig().observationHandler(new TracingHandler());

thenNoException().isThrownBy(() -> new ObservationThreadLocalAccessor() {
@Override
void assertFalse(String message) {

Expand All @@ -140,8 +224,9 @@ void assertFalse(String message) {
}

private void thenCurrentObservationHasParent(Observation parent, Observation observation) {
then(observationRegistry.getCurrentObservation()).isSameAs(observation);
then(observationRegistry.getCurrentObservation().getContextView().getParentObservation()).isSameAs(parent);
then(globalObservationRegistry.getCurrentObservation()).isSameAs(observation);
then(globalObservationRegistry.getCurrentObservation().getContextView().getParentObservation())
.isSameAs(parent);
}

private Scope thenCurrentScopeHasParent(Scope first) {
Expand All @@ -151,10 +236,16 @@ private Scope thenCurrentScopeHasParent(Scope first) {
}

private void thenCurrentObservationIsNull() {
then(observationRegistry.getCurrentObservation()).isNull();
then(ObservationRegistry.create().getCurrentObservation()).isNull();
then(TracingHandler.value.get()).isSameAs(null);
}

private void thenCurrentObservationIsNullObservation() {
then(globalObservationRegistry.getCurrentObservation()).isInstanceOf(NullObservation.class);
then(TracingHandler.value.get()).isNotNull();
then(TracingHandler.value.get().observationName).isEqualTo("null");
}

private Scope scopeParent(Scope scope) {
return scope.parent();
}
Expand Down Expand Up @@ -202,6 +293,29 @@ public boolean supportsContext(Observation.Context context) {

}

static class TestHandler implements ObservationHandler<Observation.Context> {

final String name;

final AtomicReference<String> reference;

TestHandler(String name, AtomicReference<String> reference) {
this.name = name;
this.reference = reference;
}

@Override
public void onScopeClosed(Context context) {
this.reference.set(name);
}

@Override
public boolean supportsContext(Context context) {
return true;
}

}

static class Scope implements Closeable {

private final Scope previous;
Expand Down Expand Up @@ -230,4 +344,34 @@ public String toString() {

}

static class MapContextAccessor implements ContextAccessor<Map, Map> {

@Override
public Class<? extends Map> readableType() {
return Map.class;
}

@Override
public void readValues(Map sourceContext, Predicate<Object> keyPredicate, Map<Object, Object> readValues) {

}

@Override
public <T> T readValue(Map sourceContext, Object key) {
return (T) sourceContext.get(key);
}

@Override
public Class<? extends Map> writeableType() {
return Map.class;
}

@Override
public Map writeValues(Map<Object, Object> valuesToWrite, Map targetContext) {
targetContext.putAll(valuesToWrite);
return targetContext;
}

}

}

0 comments on commit 8a129bc

Please sign in to comment.