Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 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
2d26033
Add pushIsolationScope; add fork methods to ISCope
adinauer Apr 12, 2024
bbb6700
Use separate scopes for current, isolation and global scope; rename m…
adinauer Apr 12, 2024
c714b21
Allow controlling which scope configureScope uses
adinauer Apr 12, 2024
a474402
Combine scopes
adinauer Apr 12, 2024
ae93e33
Use new API for CRONS integrations
adinauer Apr 12, 2024
b01298b
Add lifecycle helper
adinauer Apr 12, 2024
b64e688
Change spring integrations to use new API
adinauer Apr 12, 2024
d06fc50
Use new API in servlet integrations
adinauer Apr 12, 2024
f0af5c3
Use new API for kotlin coroutines and wrapers for Supplier/Callable
adinauer Apr 12, 2024
9b200b0
Merge branch '8.x.x' into feat/hsm-26-coroutine-wrapper
adinauer Apr 22, 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 @@ -9,23 +9,19 @@ import kotlin.coroutines.CoroutineContext
/**
* Sentry context element for [CoroutineContext].
*/
@SuppressWarnings("deprecation")
// TODO fork instead
public class SentryContext(private val scopes: IScopes = Sentry.getCurrentScopes().clone()) :
public class SentryContext(private val scopes: IScopes = Sentry.forkedCurrentScope("coroutine")) :
CopyableThreadContextElement<IScopes>, AbstractCoroutineContextElement(Key) {

private companion object Key : CoroutineContext.Key<SentryContext>

@SuppressWarnings("deprecation")
override fun copyForChild(): CopyableThreadContextElement<IScopes> {
// TODO fork instead
return SentryContext(scopes.clone())
return SentryContext(scopes.forkedCurrentScope("coroutine.child"))
}

@SuppressWarnings("deprecation")
override fun mergeForChild(overwritingElement: CoroutineContext.Element): CoroutineContext {
// TODO fork instead?
return overwritingElement[Key] ?: SentryContext(scopes.clone())
return overwritingElement[Key] ?: SentryContext(scopes.forkedCurrentScope("coroutine.child"))
}

override fun updateThreadContext(context: CoroutineContext): IScopes {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.kotlin

import io.sentry.ScopeType
import io.sentry.Sentry
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.joinAll
Expand Down Expand Up @@ -38,11 +39,40 @@ class SentryContextTest {
Sentry.setTag("c2", "c2value")
assertEquals("c2value", getTag("c2"))
assertEquals("parentValue", getTag("parent"))
assertNull(getTag("c1"))
assertNotNull(getTag("c1"))
Copy link
Member

Choose a reason for hiding this comment

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

yes, that's the way it's meant to work. nice!

Copy link
Member Author

Choose a reason for hiding this comment

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

We should discuss how this should work in global hub mode. Since Sentry.getCurrentScopes always returns rootScopes (think mainHub) it behaves differently.

Copy link
Member Author

Choose a reason for hiding this comment

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

Adding a comment for further discussion on a follow up PR.

}
listOf(c1, c2).joinAll()
assertNotNull(getTag("parent"))
assertNotNull(getTag("c1"))
assertNotNull(getTag("c2"))
return@runBlocking
}

@Test
fun testContextIsNotPassedByDefaultBetweenCoroutinesCurrentScope() = runBlocking {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("parent", "parentValue")
}
val c1 = launch(SentryContext()) {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c1", "c1value")
}
assertEquals("c1value", getTag("c1", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
}
val c2 = launch(SentryContext()) {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c2", "c2value")
}
assertEquals("c2value", getTag("c2", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c1", ScopeType.CURRENT))
}
listOf(c1, c2).joinAll()
assertNull(getTag("c1"))
assertNull(getTag("c2"))
assertNotNull(getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c1", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
}

@Test
Expand Down Expand Up @@ -84,7 +114,7 @@ class SentryContextTest {
}

@Test
fun testContextIsClonedWhenPassedToChild() = runBlocking {
fun testContextIsClonedWhenPassedToChildCurrentScope() = runBlocking {
Sentry.setTag("parent", "parentValue")
launch(SentryContext()) {
Sentry.setTag("c1", "c1value")
Expand All @@ -102,10 +132,44 @@ class SentryContextTest {
c2.join()

assertNotNull(getTag("c1"))
assertNull(getTag("c2"))
assertNotNull(getTag("c2"))
}.join()
assertNotNull(getTag("parent"))
assertNotNull(getTag("c1"))
assertNotNull(getTag("c2"))
return@runBlocking
}

@Test
fun testContextIsClonedWhenPassedToChild() = runBlocking {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("parent", "parentValue")
}
assertNull(getTag("c1"))
assertNull(getTag("c2"))
launch(SentryContext()) {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c1", "c1value")
}
assertEquals("c1value", getTag("c1", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))

val c2 = launch() {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c2", "c2value")
}
assertEquals("c2value", getTag("c2", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNotNull(getTag("c1", ScopeType.CURRENT))
}

c2.join()

assertNotNull(getTag("c1", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
}.join()
assertNotNull(getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c1", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
}

@Test
Expand All @@ -120,7 +184,7 @@ class SentryContextTest {
val c2 = launch(
SentryContext(
Sentry.getCurrentScopes().clone().also {
it.setTag("cloned", "clonedValue")
Sentry.setTag("cloned", "clonedValue")
}
)
) {
Expand All @@ -134,12 +198,56 @@ class SentryContextTest {
c2.join()

assertNotNull(getTag("c1"))
assertNull(getTag("c2"))
assertNull(getTag("cloned"))
assertNotNull(getTag("c2"))
assertNotNull(getTag("cloned"))
}.join()

assertNotNull(getTag("c1"))
assertNotNull(getTag("c2"))
assertNotNull(getTag("cloned"))
return@runBlocking
}

@Test
fun testExplicitlyPassedContextOverridesPropagatedContextCurrentScope() = runBlocking {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("parent", "parentValue")
}
launch(SentryContext()) {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c1", "c1value")
}
assertEquals("c1value", getTag("c1", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))

val c2 = launch(
SentryContext(
Sentry.getCurrentScopes().clone().also {
it.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("cloned", "clonedValue")
}
}
)
) {
Sentry.configureScope(ScopeType.CURRENT) { scope ->
scope.setTag("c2", "c2value")
}
assertEquals("c2value", getTag("c2", ScopeType.CURRENT))
assertEquals("parentValue", getTag("parent", ScopeType.CURRENT))
assertNotNull(getTag("c1", ScopeType.CURRENT))
assertNotNull(getTag("cloned", ScopeType.CURRENT))
}

c2.join()

assertNotNull(getTag("c1", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
assertNull(getTag("cloned", ScopeType.CURRENT))
}
assertNull(getTag("c1"))
assertNull(getTag("c2"))
assertNull(getTag("cloned"))
assertNull(getTag("c1", ScopeType.CURRENT))
assertNull(getTag("c2", ScopeType.CURRENT))
assertNull(getTag("cloned", ScopeType.CURRENT))
}

@Test
Expand Down Expand Up @@ -167,9 +275,9 @@ class SentryContextTest {
assertEquals(initialContextElement, mergedContextElement)
}

private fun getTag(tag: String): String? {
private fun getTag(tag: String, scopeType: ScopeType = ScopeType.ISOLATION): String? {
var value: String? = null
Sentry.configureScope {
Sentry.configureScope(scopeType) {
value = it.tags[tag]
}
return value
Expand Down
40 changes: 25 additions & 15 deletions sentry/src/main/java/io/sentry/SentryWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,23 @@ public final class SentryWrapper {
* @return the wrapped {@link Callable}
* @param <U> - the result type of the {@link Callable}
*/
@SuppressWarnings("deprecation")
// TODO adapt javadoc
public static <U> Callable<U> wrapCallable(final @NotNull Callable<U> callable) {
// TODO replace with forking
final IScopes newHub = Sentry.getCurrentScopes().clone();
final IScopes newScopes = Sentry.getCurrentScopes().forkedCurrentScope("wrapCallable");

return () -> {
try (ISentryLifecycleToken ignored = newScopes.makeCurrent()) {
return callable.call();
}
};
}

public static <U> Callable<U> wrapCallableIsolated(final @NotNull Callable<U> callable) {
final IScopes newScopes = Sentry.getCurrentScopes().forkedScopes("wrapCallable");

return () -> {
final IScopes oldState = Sentry.getCurrentScopes();
Sentry.setCurrentScopes(newHub);
try {
try (ISentryLifecycleToken ignored = newScopes.makeCurrent()) {
return callable.call();
} finally {
Sentry.setCurrentScopes(oldState);
}
};
}
Expand All @@ -55,16 +60,21 @@ public static <U> Callable<U> wrapCallable(final @NotNull Callable<U> callable)
*/
@SuppressWarnings("deprecation")
public static <U> Supplier<U> wrapSupplier(final @NotNull Supplier<U> supplier) {
// TODO replace with forking
final IScopes newHub = Sentry.getCurrentScopes().clone();
final IScopes newScopes = Sentry.forkedCurrentScope("wrapSupplier");

return () -> {
try (ISentryLifecycleToken ignore = newScopes.makeCurrent()) {
return supplier.get();
}
};
}

public static <U> Supplier<U> wrapSupplierIsolated(final @NotNull Supplier<U> supplier) {
final IScopes newScopes = Sentry.forkedScopes("wrapSupplier");

return () -> {
final IScopes oldState = Sentry.getCurrentScopes();
Sentry.setCurrentScopes(newHub);
try {
try (ISentryLifecycleToken ignore = newScopes.makeCurrent()) {
return supplier.get();
} finally {
Sentry.setCurrentScopes(oldState);
}
};
}
Expand Down
Loading