Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

### Bugfixes

* Make closing scope idempotent and non-operational when corresponding context is not current.
[(#5061)](https://github.com/open-telemetry/opentelemetry-java/pull/5061)
*
## Version 1.21.0 (2022-12-09)

### API
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

enum ThreadLocalContextStorage implements ContextStorage {
Expand All @@ -30,14 +31,30 @@ public Scope attach(Context toAttach) {

THREAD_LOCAL_STORAGE.set(toAttach);

return () -> {
if (current() != toAttach) {
return new ScopeImpl(beforeAttach, toAttach);
}

private class ScopeImpl implements Scope {
@Nullable private final Context beforeAttach;
private final Context toAttach;
private boolean closed;

private ScopeImpl(@Nullable Context beforeAttach, @Nonnull Context toAttach) {
Comment thread
lmolkova marked this conversation as resolved.
Outdated
this.beforeAttach = beforeAttach;
this.toAttach = toAttach;
}

@Override
public void close() {
if (!closed && current() == toAttach) {
Comment thread
lmolkova marked this conversation as resolved.
closed = true;
THREAD_LOCAL_STORAGE.set(beforeAttach);
} else {
logger.log(
Level.FINE,
"Context in storage not the expected context, Scope.close was not called correctly");
" Trying to close scope which does not represent current context. Ignoring the call.");
}
THREAD_LOCAL_STORAGE.set(beforeAttach);
};
}
}

@Override
Expand Down
25 changes: 23 additions & 2 deletions context/src/test/java/io/opentelemetry/context/ContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,21 +118,42 @@ void newThreadStartsWithRoot() throws Exception {
}

@Test
public void closingScopeWhenNotActiveIsLogged() {
public void closingScopeWhenNotActiveIsNoopAndLogged() {
Context initial = Context.current();
Context context = initial.with(ANIMAL, "cat");
try (Scope scope = context.makeCurrent()) {
Context context2 = context.with(ANIMAL, "dog");
try (Scope ignored = context2.makeCurrent()) {
assertThat(Context.current().get(ANIMAL)).isEqualTo("dog");
scope.close();
assertThat(Context.current().get(ANIMAL)).isEqualTo("dog");
}
}
assertThat(Context.current()).isEqualTo(initial);
LoggingEvent log = logs.assertContains("Context in storage not the expected context");
LoggingEvent log =
logs.assertContains("Trying to close scope which does not represent current context");
assertThat(log.getLevel()).isEqualTo(Level.DEBUG);
}

@SuppressWarnings("MustBeClosedChecker")
@Test
public void closeScopeIsIdempotent() {
Context initial = Context.current();
Context context1 = Context.root().with(ANIMAL, "cat");
Scope scope1 = context1.makeCurrent();
Context context2 = context1.with(ANIMAL, "dog");
Scope scope2 = context2.makeCurrent();

scope2.close();
assertThat(Context.current()).isEqualTo(context1);

scope1.close();
assertThat(Context.current()).isEqualTo(initial);

scope2.close();
assertThat(Context.current()).isEqualTo(initial);
}

@Test
void withValues() {
Context context1 = Context.current().with(ANIMAL, "cat");
Expand Down