Skip to content

Commit d054e63

Browse files
authored
Make observation return its context and immutable access to parent (#3423)
* Make Observation#getContext() return Context * Introduce ObservationView to access parent context immutably To prevent modifying the parent observation, introduces the `ObservationView`, a read only view of the observation. Then, makes `Observation.Context#getParentObservation` to return the `ObservationView` which gives immutable way of referencing the context.
1 parent 484ad98 commit d054e63

File tree

6 files changed

+71
-26
lines changed

6 files changed

+71
-26
lines changed

micrometer-observation-test/src/main/java/io/micrometer/observation/tck/ObservationContextAssert.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.micrometer.common.KeyValue;
1919
import io.micrometer.common.KeyValues;
2020
import io.micrometer.observation.Observation;
21+
import io.micrometer.observation.ObservationView;
2122
import org.assertj.core.api.AbstractAssert;
2223
import org.assertj.core.api.AbstractThrowableAssert;
2324
import org.assertj.core.api.ThrowingConsumer;
@@ -354,9 +355,9 @@ public SELF hasParentObservation() {
354355
return (SELF) this;
355356
}
356357

357-
private Observation checkedParentObservation() {
358+
private ObservationView checkedParentObservation() {
358359
isNotNull();
359-
Observation p = this.actual.getParentObservation();
360+
ObservationView p = this.actual.getParentObservation();
360361
if (p == null) {
361362
failWithMessage("Observation should have a parent");
362363
}
@@ -371,7 +372,7 @@ private Observation checkedParentObservation() {
371372
*/
372373
public SELF hasParentObservationEqualTo(Observation expectedParent) {
373374
isNotNull();
374-
Observation realParent = this.actual.getParentObservation();
375+
ObservationView realParent = this.actual.getParentObservation();
375376
if (realParent == null) {
376377
failWithMessage("Observation should have parent <%s> but has none", expectedParent);
377378
}
@@ -403,9 +404,9 @@ public SELF doesNotHaveParentObservation() {
403404
*/
404405
public SELF hasParentObservationContextSatisfying(
405406
ThrowingConsumer<Observation.ContextView> parentContextViewAssertion) {
406-
Observation p = checkedParentObservation();
407+
ObservationView p = checkedParentObservation();
407408
try {
408-
parentContextViewAssertion.accept(p.getContext());
409+
parentContextViewAssertion.accept(p.getContextView());
409410
}
410411
catch (Throwable e) {
411412
failWithMessage("Parent observation does not satisfy given assertion: " + e.getMessage());
@@ -423,8 +424,8 @@ public SELF hasParentObservationContextSatisfying(
423424
*/
424425
public SELF hasParentObservationContextMatching(
425426
Predicate<? super Observation.ContextView> parentContextViewPredicate) {
426-
Observation p = checkedParentObservation();
427-
if (!parentContextViewPredicate.test(p.getContext())) {
427+
ObservationView p = checkedParentObservation();
428+
if (!parentContextViewPredicate.test(p.getContextView())) {
428429
failWithMessage("Observation should have parent that matches given predicate but <%s> didn't", p);
429430
}
430431
return (SELF) this;
@@ -438,8 +439,8 @@ public SELF hasParentObservationContextMatching(
438439
*/
439440
public SELF hasParentObservationContextMatching(
440441
Predicate<? super Observation.ContextView> parentContextViewPredicate, String description) {
441-
Observation p = checkedParentObservation();
442-
if (!parentContextViewPredicate.test(p.getContext())) {
442+
ObservationView p = checkedParentObservation();
443+
if (!parentContextViewPredicate.test(p.getContextView())) {
443444
failWithMessage("Observation should have parent that matches '%s' predicate but <%s> didn't", description,
444445
p);
445446
}

micrometer-observation/src/main/java/io/micrometer/observation/NoopObservation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ final class NoopObservation implements Observation {
3333
*/
3434
static final NoopObservation INSTANCE = new NoopObservation();
3535

36-
private static final ContextView CONTEXT = new Context();
36+
private static final Context CONTEXT = new Context();
3737

3838
private NoopObservation() {
3939
}
@@ -89,7 +89,7 @@ public Observation start() {
8989
}
9090

9191
@Override
92-
public ContextView getContext() {
92+
public Context getContext() {
9393
return CONTEXT;
9494
}
9595

micrometer-observation/src/main/java/io/micrometer/observation/Observation.java

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
* @author Marcin Grzejszczak
4545
* @since 1.10.0
4646
*/
47-
public interface Observation {
47+
public interface Observation extends ObservationView {
4848

4949
/**
5050
* No-op observation.
@@ -359,7 +359,16 @@ default boolean isNoop() {
359359
* Returns the context attached to this observation.
360360
* @return corresponding context
361361
*/
362-
ContextView getContext();
362+
Context getContext();
363+
364+
/**
365+
* Returns the context attached to this observation as a read only view.
366+
* @return corresponding context
367+
*/
368+
@Override
369+
default ContextView getContextView() {
370+
return this.getContext();
371+
}
363372

364373
/**
365374
* Stop the observation. Remember to call this method, otherwise timing calculations
@@ -674,7 +683,7 @@ class Context implements ContextView {
674683
private Throwable error;
675684

676685
@Nullable
677-
private Observation parentObservation;
686+
private ObservationView parentObservation;
678687

679688
private final Set<KeyValue> lowCardinalityKeyValues = new LinkedHashSet<>();
680689

@@ -716,20 +725,19 @@ public void setContextualName(@Nullable String contextualName) {
716725
}
717726

718727
/**
719-
* Returns the parent {@link Observation}.
728+
* Returns the parent {@link ObservationView}.
720729
* @return parent observation or {@code null} if there was no parent
721730
*/
722-
@Override
723731
@Nullable
724-
public Observation getParentObservation() {
732+
public ObservationView getParentObservation() {
725733
return parentObservation;
726734
}
727735

728736
/**
729737
* Sets the parent {@link Observation}.
730738
* @param parentObservation parent observation to set
731739
*/
732-
public void setParentObservation(@Nullable Observation parentObservation) {
740+
public void setParentObservation(@Nullable ObservationView parentObservation) {
733741
this.parentObservation = parentObservation;
734742
}
735743

@@ -1011,11 +1019,11 @@ interface ContextView {
10111019
String getContextualName();
10121020

10131021
/**
1014-
* Returns the parent {@link Observation}.
1022+
* Returns the parent {@link ObservationView}.
10151023
* @return parent observation or {@code null} if there was no parent
10161024
*/
10171025
@Nullable
1018-
Observation getParentObservation();
1026+
ObservationView getParentObservation();
10191027

10201028
/**
10211029
* Optional error that occurred while processing the {@link Observation}.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2022 VMware, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.micrometer.observation;
17+
18+
import io.micrometer.observation.Observation.ContextView;
19+
20+
/**
21+
* Read only view on the {@link Observation}.
22+
*
23+
* @since 1.10.0
24+
*/
25+
public interface ObservationView {
26+
27+
/**
28+
* Returns the {@link ContextView} attached to this observation.
29+
* @return corresponding context
30+
*/
31+
ContextView getContextView();
32+
33+
}

micrometer-observation/src/main/java/io/micrometer/observation/SimpleObservation.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ public Observation start() {
145145
}
146146

147147
@Override
148-
public ContextView getContext() {
148+
public Context getContext() {
149149
return this.context;
150150
}
151151

@@ -232,13 +232,13 @@ static class SimpleScope implements Scope {
232232
private final Observation.Scope previousObservationScope;
233233

234234
@Nullable
235-
private final Observation previousParentObservation;
235+
private final ObservationView previousParentObservationView;
236236

237237
SimpleScope(ObservationRegistry registry, SimpleObservation current) {
238238
this.registry = registry;
239239
this.currentObservation = current;
240240
this.previousObservationScope = registry.getCurrentObservationScope();
241-
this.previousParentObservation = current.context.getParentObservation();
241+
this.previousParentObservationView = current.context.getParentObservation();
242242
if (this.previousObservationScope != null) {
243243
current.context.setParentObservation(this.previousObservationScope.getCurrentObservation());
244244
}
@@ -254,7 +254,7 @@ public Observation getCurrentObservation() {
254254
public void close() {
255255
this.registry.setCurrentObservationScope(previousObservationScope);
256256
this.currentObservation.notifyOnScopeClosed();
257-
this.currentObservation.context.setParentObservation(this.previousParentObservation);
257+
this.currentObservation.context.setParentObservation(this.previousParentObservationView);
258258
}
259259

260260
}

micrometer-observation/src/test/java/io/micrometer/observation/ObservationTests.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,10 @@ void settingParentObservationMakesAReferenceOnParentContext() {
9292
parent.stop();
9393
child.stop();
9494

95-
assertThat(childContext.getParentObservation().getContext()).isSameAs(parentContext);
95+
assertThat(child.getContextView()).isSameAs(childContext);
96+
assertThat(parent.getContextView()).isSameAs(parentContext);
97+
98+
assertThat(childContext.getParentObservation().getContextView()).isSameAs(parentContext);
9699
}
97100

98101
@Test
@@ -105,7 +108,7 @@ void settingScopeMakesAReferenceOnParentContext() {
105108
parent.scoped(() -> {
106109
assertThat(childContext.getParentObservation()).isNull();
107110
Observation.createNotStarted("child", childContext, registry).observe(() -> {
108-
assertThat(childContext.getParentObservation().getContext()).isSameAs(parentContext);
111+
assertThat(childContext.getParentObservation().getContextView()).isSameAs(parentContext);
109112
});
110113
assertThat(childContext.getParentObservation()).isNull();
111114
});

0 commit comments

Comments
 (0)