Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
305baf5
replace hub with scopes
adinauer Mar 27, 2024
95f5e1b
Add Scopes
adinauer Apr 2, 2024
27f2398
Introduce `IScopes` interface.
adinauer Apr 2, 2024
ce3c14f
Replace `IHub` with `IScopes` in core
adinauer Apr 2, 2024
ce615f4
Replace `IHub` with `IScopes` in android core
adinauer Apr 2, 2024
22ddc00
Replace `IHub` with `IScopes` in android integrations
adinauer Apr 2, 2024
305c217
Replace `IHub` with `IScopes` in apollo integrations
adinauer Apr 2, 2024
da927bc
Replace `IHub` with `IScopes` in okhttp integration
adinauer Apr 2, 2024
8279276
Replace `IHub` with `IScopes` in graphql integration
adinauer Apr 2, 2024
9bfc086
Replace `IHub` with `IScopes` in logging integrations
adinauer Apr 2, 2024
b998e50
Replace `IHub` with `IScopes` in more integrations
adinauer Apr 2, 2024
739827a
Replace `IHub` with `IScopes` in OTel integration
adinauer Apr 2, 2024
69f2d63
Replace `IHub` with `IScopes` in Spring 5 / Spring Boot 2 integrations
adinauer Apr 2, 2024
792d482
Replace `IHub` with `IScopes` in Spring 6 / Spring Boot 3 integrations
adinauer Apr 2, 2024
9bcbce6
Replace `IHub` with `IScopes` in samples
adinauer Apr 2, 2024
3f25a4b
Merge branch 'feat/hsm-13-replacements-in-samples' into feat/hubs-sco…
adinauer Apr 2, 2024
d6fb40a
gitscopes -> github
adinauer Apr 2, 2024
7752bcc
Replace ThreadLocal with ScopesStorage
adinauer Apr 4, 2024
1e329c5
Move client and throwable to span map to scope
adinauer Apr 4, 2024
b0d89ae
Add global scope
adinauer Apr 4, 2024
cdd414a
use global scope in Scopes
adinauer Apr 4, 2024
98da9ff
Implement pushScope popScope and withScope for Scopes
adinauer Apr 4, 2024
698a693
Merge branch '8.x.x' into feat/hsm-18-push-scope-etc
adinauer Apr 19, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,10 @@ class SentryWebFluxTracingFilterTest {
verify(fixture.scopes, times(3)).isEnabled
verify(fixture.scopes, times(2)).options
verify(fixture.scopes).continueTrace(anyOrNull(), anyOrNull())
verify(fixture.scopes).pushScope()
verify(fixture.scopes).pushScope() // TODO don't
verify(fixture.scopes).addBreadcrumb(any<Breadcrumb>(), any<Hint>())
verify(fixture.scopes).configureScope(any<ScopeCallback>())
verify(fixture.scopes).popScope()
verify(fixture.scopes).popScope() // TODO don't
verifyNoMoreInteractions(fixture.scopes)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ isTracingEnabled && shouldTraceRequest(requestHub, request)
if (transaction != null) {
finishTransaction(serverWebExchange, transaction);
}
requestHub.popScope();
requestHub.popScope(); // TODO don't
// TODO token based cleanup instead?
Sentry.setCurrentScopes(NoOpScopes.getInstance());
})
Expand All @@ -96,7 +96,7 @@ isTracingEnabled && shouldTraceRequest(requestHub, request)
() -> {
serverWebExchange.getAttributes().put(SENTRY_SCOPES_KEY, requestHub);
Sentry.setCurrentScopes(requestHub);
requestHub.pushScope();
requestHub.pushScope(); // TODO don't
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushScope by itself here wouldn't be problematic, however combining this with e.g. setting request on the requestHub reference, leads to unexpected results where e.g. request isn't set on captured messages.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of pushScope, maybe we could simply call requestHub.forkedCurrentScopes() and then call .makeCurrent() on that. Then from there on only use the reference, returned by the fork call.

Copy link
Member Author

@adinauer adinauer Apr 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking tho we don't even need to call pushScope here since we're forking Scopes anyways.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could look into Mono.using() to do the cleanup for us in a follow up PR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's test first and then follow up with a separate PR if it actually works / helps

final ServerHttpResponse response = serverWebExchange.getResponse();

final Hint hint = new Hint();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,10 @@ class SentryWebFluxTracingFilterTest {
verify(fixture.scopes).isEnabled
verify(fixture.scopes, times(2)).options
verify(fixture.scopes).continueTrace(anyOrNull(), anyOrNull())
verify(fixture.scopes).pushScope()
verify(fixture.scopes).pushScope() // TODO don't
verify(fixture.scopes).addBreadcrumb(any<Breadcrumb>(), any<Hint>())
verify(fixture.scopes).configureScope(any<ScopeCallback>())
verify(fixture.scopes).popScope()
verify(fixture.scopes).popScope() // TODO don't
verifyNoMoreInteractions(fixture.scopes)
}
}
Expand Down
72 changes: 63 additions & 9 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ public final class io/sentry/Hub : io/sentry/IHub, io/sentry/metrics/MetricsApi$
public fun isHealthy ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -510,7 +510,60 @@ public final class io/sentry/HubAdapter : io/sentry/IHub {
public fun isHealthy ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
public fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public fun setFingerprint (Ljava/util/List;)V
public fun setLevel (Lio/sentry/SentryLevel;)V
public fun setSpanContext (Ljava/lang/Throwable;Lio/sentry/ISpan;Ljava/lang/String;)V
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
public fun setTransaction (Ljava/lang/String;)V
public fun setUser (Lio/sentry/protocol/User;)V
public fun startSession ()V
public fun startTransaction (Lio/sentry/TransactionContext;Lio/sentry/TransactionOptions;)Lio/sentry/ITransaction;
public fun traceHeaders ()Lio/sentry/SentryTraceHeader;
public fun withScope (Lio/sentry/ScopeCallback;)V
}

public final class io/sentry/HubScopesWrapper : io/sentry/IHub {
public fun <init> (Lio/sentry/IScopes;)V
public fun addBreadcrumb (Lio/sentry/Breadcrumb;)V
public fun addBreadcrumb (Lio/sentry/Breadcrumb;Lio/sentry/Hint;)V
public fun bindClient (Lio/sentry/ISentryClient;)V
public fun captureCheckIn (Lio/sentry/CheckIn;)Lio/sentry/protocol/SentryId;
public fun captureEnvelope (Lio/sentry/SentryEnvelope;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;)Lio/sentry/protocol/SentryId;
public fun captureException (Ljava/lang/Throwable;Lio/sentry/Hint;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId;
public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/ScopeCallback;)Lio/sentry/protocol/SentryId;
public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/TraceContext;Lio/sentry/Hint;Lio/sentry/ProfilingTraceData;)Lio/sentry/protocol/SentryId;
public fun captureUserFeedback (Lio/sentry/UserFeedback;)V
public fun clearBreadcrumbs ()V
public fun clone ()Lio/sentry/IHub;
public synthetic fun clone ()Ljava/lang/Object;
public fun close ()V
public fun close (Z)V
public fun configureScope (Lio/sentry/ScopeCallback;)V
public fun continueTrace (Ljava/lang/String;Ljava/util/List;)Lio/sentry/TransactionContext;
public fun endSession ()V
public fun flush (J)V
public fun getBaggage ()Lio/sentry/BaggageHeader;
public fun getLastEventId ()Lio/sentry/protocol/SentryId;
public fun getOptions ()Lio/sentry/SentryOptions;
public fun getRateLimiter ()Lio/sentry/transport/RateLimiter;
public fun getSpan ()Lio/sentry/ISpan;
public fun getTraceparent ()Lio/sentry/SentryTraceHeader;
public fun getTransaction ()Lio/sentry/ITransaction;
public fun isCrashedLastRun ()Ljava/lang/Boolean;
public fun isEnabled ()Z
public fun isHealthy ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -781,7 +834,7 @@ public abstract interface class io/sentry/IScopes {
public fun isNoOp ()Z
public abstract fun metrics ()Lio/sentry/metrics/MetricsApi;
public abstract fun popScope ()V
public abstract fun pushScope ()V
public abstract fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public abstract fun removeExtra (Ljava/lang/String;)V
public abstract fun removeTag (Ljava/lang/String;)V
public fun reportFullDisplayed ()V
Expand Down Expand Up @@ -1271,7 +1324,7 @@ public final class io/sentry/NoOpHub : io/sentry/IHub {
public fun isNoOp ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -1396,7 +1449,7 @@ public final class io/sentry/NoOpScopes : io/sentry/IScopes {
public fun isNoOp ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -1869,9 +1922,10 @@ public final class io/sentry/Scopes : io/sentry/IScopes, io/sentry/metrics/Metri
public fun isCrashedLastRun ()Ljava/lang/Boolean;
public fun isEnabled ()Z
public fun isHealthy ()Z
public fun makeCurrent ()Lio/sentry/ISentryLifecycleToken;
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -1925,7 +1979,7 @@ public final class io/sentry/ScopesAdapter : io/sentry/IScopes {
public fun isHealthy ()Z
public fun metrics ()Lio/sentry/metrics/MetricsApi;
public fun popScope ()V
public fun pushScope ()V
public fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public fun removeExtra (Ljava/lang/String;)V
public fun removeTag (Ljava/lang/String;)V
public fun reportFullyDisplayed ()V
Expand Down Expand Up @@ -2020,13 +2074,13 @@ public final class io/sentry/Sentry {
public static fun isHealthy ()Z
public static fun metrics ()Lio/sentry/metrics/MetricsApi;
public static fun popScope ()V
public static fun pushScope ()V
public static fun pushScope ()Lio/sentry/ISentryLifecycleToken;
public static fun removeExtra (Ljava/lang/String;)V
public static fun removeTag (Ljava/lang/String;)V
public static fun reportFullDisplayed ()V
public static fun reportFullyDisplayed ()V
public static fun setCurrentHub (Lio/sentry/IHub;)V
public static fun setCurrentScopes (Lio/sentry/IScopes;)V
public static fun setCurrentScopes (Lio/sentry/IScopes;)Lio/sentry/ISentryLifecycleToken;
public static fun setExtra (Ljava/lang/String;Ljava/lang/String;)V
public static fun setFingerprint (Ljava/util/List;)V
public static fun setLevel (Lio/sentry/SentryLevel;)V
Expand Down
3 changes: 2 additions & 1 deletion sentry/src/main/java/io/sentry/Hub.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ public void removeExtra(final @NotNull String key) {
}

@Override
public void pushScope() {
public @NotNull ISentryLifecycleToken pushScope() {
if (!isEnabled()) {
options
.getLogger()
Expand All @@ -536,6 +536,7 @@ public void pushScope() {
final StackItem newItem = new StackItem(options, item.getClient(), item.getScope().clone());
stack.push(newItem);
}
return NoOpScopesStorage.NoOpScopesLifecycleToken.getInstance();
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions sentry/src/main/java/io/sentry/HubAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ public void removeExtra(@NotNull String key) {
}

@Override
public void pushScope() {
Sentry.pushScope();
public @NotNull ISentryLifecycleToken pushScope() {
return Sentry.pushScope();
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions sentry/src/main/java/io/sentry/HubScopesWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ public void removeExtra(@NotNull String key) {
}

@Override
public void pushScope() {
scopes.pushScope();
public @NotNull ISentryLifecycleToken pushScope() {
return scopes.pushScope();
}

@Override
Expand Down
3 changes: 2 additions & 1 deletion sentry/src/main/java/io/sentry/IScopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,8 @@ default void addBreadcrumb(@NotNull String message, @NotNull String category) {
SentryId getLastEventId();

/** Pushes a new scope while inheriting the current scope's data. */
void pushScope();
@NotNull
ISentryLifecycleToken pushScope();

/** Removes the first scope */
void popScope();
Expand Down
4 changes: 3 additions & 1 deletion sentry/src/main/java/io/sentry/NoOpHub.java
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ public void removeExtra(@NotNull String key) {}
}

@Override
public void pushScope() {}
public @NotNull ISentryLifecycleToken pushScope() {
return NoOpScopesStorage.NoOpScopesLifecycleToken.getInstance();
}

@Override
public void popScope() {}
Expand Down
4 changes: 3 additions & 1 deletion sentry/src/main/java/io/sentry/NoOpScopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ public void removeExtra(@NotNull String key) {}
}

@Override
public void pushScope() {}
public @NotNull ISentryLifecycleToken pushScope() {
return NoOpScopesStorage.NoOpScopesLifecycleToken.getInstance();
}

@Override
public void popScope() {}
Expand Down
25 changes: 15 additions & 10 deletions sentry/src/main/java/io/sentry/Scopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -595,20 +595,21 @@ private void updateLastEventId(final @NotNull SentryId lastEventId) {
// TODO needs to be deprecated because there's no more stack
// TODO needs to return a lifecycle token
@Override
public void pushScope() {
public ISentryLifecycleToken pushScope() {
if (!isEnabled()) {
options
.getLogger()
.log(SentryLevel.WARNING, "Instance is disabled and this 'pushScope' call is a no-op.");
return NoOpScopesStorage.NoOpScopesLifecycleToken.getInstance();
} else {
// Scopes scopes = this.forkedScopes("pushScope");
// return scopes.makeCurrent();
Scopes scopes = this.forkedCurrentScope("pushScope");
return scopes.makeCurrent();
}
}

// public SentryLifecycleToken makeCurrent() {
// // TODO store.set(this);
// }
public ISentryLifecycleToken makeCurrent() {
return Sentry.setCurrentScopes(this);
}

// TODO needs to be deprecated because there's no more stack
@Override
Expand All @@ -618,8 +619,11 @@ public void popScope() {
.getLogger()
.log(SentryLevel.WARNING, "Instance is disabled and this 'popScope' call is a no-op.");
} else {
// TODO how to remove fork?
// TODO getParentScopes().makeCurrent()?
final @Nullable Scopes parent = getParent();
if (parent != null) {
// TODO this is never closed
parent.makeCurrent();
Copy link
Member Author

@adinauer adinauer Apr 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're handed back a lifecycle token here which we never call close on. Popping scopes this way is kinda hacky. I haven't come up with a better approach yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I read it right makeCurrent() returns the token for the previous scope. Since this is legacy push/pop API, wouldn't it make sense to automatically close the previous scope?

Suggested change
parent.makeCurrent();
final @NotNull ISentryLifecycleToken previousScopes = parent.makeCurrent();
previousScopes.close();

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous Scopes should be restored, when the current one is closed, so we can't close it when creating a new (child) scope.

Take a piece of nested code:

// outermost scopes (scopes1)
Sentry.withScope(scope -> {
	// inner scopes (scopes2)
	try { ... = scope.forkedCurrentScopes("...").makeCurrent()) {
		// innermost scopes (scopes3)
	}
}

When leaving the try block, we're closing scopes3 and restoring scopes2. When leaving the withScope lambda, we're closing scopes2 and restoring scopes1.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied this pattern from OpenTelemetry, as we'll have to call their io.opentelemetry.context.Scope.close() inside our OTEL flavor lifecycle token. See https://github.com/getsentry/sentry-java/pull/3285/files#diff-ce5e1c852e10adfae80110c82615eaa9571a7eeb5ed8bb79512c08dc388c4bc0R43

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think of this chain of lifecycle tokens as a replacement for the stack. We're keeping scopes from being garbage collected by holding a reference to each parent scopes instance.

}
}
}

Expand All @@ -634,7 +638,7 @@ public void withScope(final @NotNull ScopeCallback callback) {
}

} else {
Scopes forkedScopes = forkedScopes("withScope");
Scopes forkedScopes = forkedCurrentScope("withScope");
// TODO should forkedScopes be made current inside callback?
// TODO forkedScopes.makeCurrent()?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Depending on the behaviour we want to achieve, it might make sense to make them the currentScopes. IIRC Hub does this by pushing/popping scope around the callback.

We could just add the makeCurrent call to the the try/catch block here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in #3375

try {
Expand Down Expand Up @@ -705,7 +709,8 @@ public void flush(long timeoutMillis) {
if (!isEnabled()) {
options.getLogger().log(SentryLevel.WARNING, "Disabled Hub cloned.");
}
return new HubScopesWrapper(forkedScopes("scopes clone"));
// TODO should this fork isolation scope as well?
return new HubScopesWrapper(forkedCurrentScope("scopes clone"));
}

@ApiStatus.Internal
Expand Down
4 changes: 2 additions & 2 deletions sentry/src/main/java/io/sentry/ScopesAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ public void removeExtra(@NotNull String key) {
}

@Override
public void pushScope() {
Sentry.pushScope();
public @NotNull ISentryLifecycleToken pushScope() {
return Sentry.pushScope();
}

@Override
Expand Down
5 changes: 3 additions & 2 deletions sentry/src/main/java/io/sentry/Sentry.java
Original file line number Diff line number Diff line change
Expand Up @@ -813,12 +813,13 @@ public static void removeExtra(final @NotNull String key) {
}

/** Pushes a new scope while inheriting the current scope's data. */
public static void pushScope() {
public static @NotNull ISentryLifecycleToken pushScope() {
// pushScope is no-op in global hub mode
if (!globalHubMode) {
// TODO this might have to behave differently from Scopes.pushScope
getCurrentScopes().pushScope();
return getCurrentScopes().pushScope();
}
return NoOpScopesStorage.NoOpScopesLifecycleToken.getInstance();
}

/** Removes the first scope */
Expand Down
4 changes: 3 additions & 1 deletion sentry/src/test/java/io/sentry/NoOpHubTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ class NoOpHubTest {
}

@Test
fun `pushScope is no op`() = sut.pushScope()
fun `pushScope is no op`() {
sut.pushScope()
}

@Test
fun `popScope is no op`() = sut.popScope()
Expand Down