Skip to content

Commit e5e95de

Browse files
authored
feat: Added enableTraceIdGeneration option (#4188)
1 parent c87d429 commit e5e95de

File tree

8 files changed

+88
-4
lines changed

8 files changed

+88
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- The `ignoredErrors` option is now configurable via the manifest property `io.sentry.traces.ignored-errors` ([#4178](https://github.com/getsentry/sentry-java/pull/4178))
88
- A list of active Spring profiles is attached to payloads sent to Sentry (errors, traces, etc.) and displayed in the UI when using our Spring or Spring Boot integrations ([#4147](https://github.com/getsentry/sentry-java/pull/4147))
99
- This consists of an empty list when only the default profile is active
10+
- Added `enableTraceIdGeneration` to the AndroidOptions. This allows Hybrid SDKs to "freeze" and control the trace and connect errors on different layers of the application ([4188](https://github.com/getsentry/sentry-java/pull/4188))
1011
- Move to a single NetworkCallback listener to reduce number of IPC calls on Android ([#4164](https://github.com/getsentry/sentry-java/pull/4164))
1112
- Add GraphQL Apollo Kotlin 4 integration ([#4166](https://github.com/getsentry/sentry-java/pull/4166))
1213

sentry-android-core/api/sentry-android-core.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
292292
public fun isEnableAppComponentBreadcrumbs ()Z
293293
public fun isEnableAppLifecycleBreadcrumbs ()Z
294294
public fun isEnableAutoActivityLifecycleTracing ()Z
295+
public fun isEnableAutoTraceIdGeneration ()Z
295296
public fun isEnableFramesTracking ()Z
296297
public fun isEnableNdk ()Z
297298
public fun isEnableNetworkEventBreadcrumbs ()Z
@@ -315,6 +316,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
315316
public fun setEnableAppComponentBreadcrumbs (Z)V
316317
public fun setEnableAppLifecycleBreadcrumbs (Z)V
317318
public fun setEnableAutoActivityLifecycleTracing (Z)V
319+
public fun setEnableAutoTraceIdGeneration (Z)V
318320
public fun setEnableFramesTracking (Z)V
319321
public fun setEnableNdk (Z)V
320322
public fun setEnableNetworkEventBreadcrumbs (Z)V

sentry-android-core/src/main/java/io/sentry/android/core/ActivityLifecycleIntegration.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,9 @@ private void startTracing(final @NotNull Activity activity) {
161161
if (scopes != null && !isRunningTransactionOrTrace(activity)) {
162162
if (!performanceEnabled) {
163163
activitiesWithOngoingTransactions.put(activity, NoOpTransaction.getInstance());
164-
TracingUtils.startNewTrace(scopes);
164+
if (options.isEnableAutoTraceIdGeneration()) {
165+
TracingUtils.startNewTrace(scopes);
166+
}
165167
} else {
166168
// as we allow a single transaction running on the bound Scope, we finish the previous ones
167169
stopPreviousTransactions();

sentry-android-core/src/main/java/io/sentry/android/core/ManifestMetadataReader.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ final class ManifestMetadataReader {
107107

108108
static final String IGNORED_ERRORS = "io.sentry.ignored-errors";
109109

110+
static final String ENABLE_AUTO_TRACE_ID_GENERATION =
111+
"io.sentry.traces.enable-auto-id-generation";
112+
110113
/** ManifestMetadataReader ctor */
111114
private ManifestMetadataReader() {}
112115

@@ -380,6 +383,13 @@ static void applyMetadata(
380383
readBool(
381384
metadata, logger, ENABLE_SCOPE_PERSISTENCE, options.isEnableScopePersistence()));
382385

386+
options.setEnableAutoTraceIdGeneration(
387+
readBool(
388+
metadata,
389+
logger,
390+
ENABLE_AUTO_TRACE_ID_GENERATION,
391+
options.isEnableAutoTraceIdGeneration()));
392+
383393
if (options.getSessionReplay().getSessionSampleRate() == null) {
384394
final Double sessionSampleRate =
385395
readDouble(metadata, logger, REPLAYS_SESSION_SAMPLE_RATE);

sentry-android-core/src/main/java/io/sentry/android/core/SentryAndroidOptions.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,12 @@ public final class SentryAndroidOptions extends SentryOptions {
166166
*/
167167
private boolean enableScopeSync = true;
168168

169+
/**
170+
* Whether to enable automatic trace ID generation. This is mainly used by the Hybrid SDKs to
171+
* control the trace ID generation from the outside.
172+
*/
173+
private boolean enableAutoTraceIdGeneration = true;
174+
169175
public interface BeforeCaptureCallback {
170176

171177
/**
@@ -594,4 +600,12 @@ public void setFrameMetricsCollector(
594600
final @Nullable SentryFrameMetricsCollector frameMetricsCollector) {
595601
this.frameMetricsCollector = frameMetricsCollector;
596602
}
603+
604+
public boolean isEnableAutoTraceIdGeneration() {
605+
return enableAutoTraceIdGeneration;
606+
}
607+
608+
public void setEnableAutoTraceIdGeneration(final boolean enableAutoTraceIdGeneration) {
609+
this.enableAutoTraceIdGeneration = enableAutoTraceIdGeneration;
610+
}
597611
}

sentry-android-core/src/main/java/io/sentry/android/core/internal/gestures/SentryGestureListener.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,9 @@ private void startTracing(final @NotNull UiElement target, final @NotNull Gestur
202202

203203
if (!(options.isTracingEnabled() && options.isEnableUserInteractionTracing())) {
204204
if (isNewInteraction) {
205-
TracingUtils.startNewTrace(scopes);
205+
if (options.isEnableAutoTraceIdGeneration()) {
206+
TracingUtils.startNewTrace(scopes);
207+
}
206208
activeUiElement = target;
207209
activeEventType = eventType;
208210
}

sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,10 +1385,11 @@ class ActivityLifecycleIntegrationTest {
13851385
}
13861386

13871387
@Test
1388-
fun `starts new trace if performance is disabled`() {
1388+
fun `starts new trace if performance is disabled and trace ID generation is enabled`() {
13891389
val sut = fixture.getSut()
13901390
val activity = mock<Activity>()
13911391
fixture.options.tracesSampleRate = null
1392+
fixture.options.isEnableAutoTraceIdGeneration = true
13921393

13931394
val argumentCaptor: ArgumentCaptor<ScopeCallback> = ArgumentCaptor.forClass(ScopeCallback::class.java)
13941395
val scope = Scope(fixture.options)
@@ -1405,6 +1406,28 @@ class ActivityLifecycleIntegrationTest {
14051406
assertNotSame(propagationContextAtStart, scope.propagationContext)
14061407
}
14071408

1409+
@Test
1410+
fun `does not start a new trace if performance is disabled and trace ID generation is disabled`() {
1411+
val sut = fixture.getSut()
1412+
val activity = mock<Activity>()
1413+
fixture.options.tracesSampleRate = null
1414+
fixture.options.isEnableAutoTraceIdGeneration = false
1415+
1416+
val argumentCaptor: ArgumentCaptor<ScopeCallback> = ArgumentCaptor.forClass(ScopeCallback::class.java)
1417+
val scope = Scope(fixture.options)
1418+
val propagationContextAtStart = scope.propagationContext
1419+
whenever(fixture.scopes.configureScope(argumentCaptor.capture())).thenAnswer {
1420+
argumentCaptor.value.run(scope)
1421+
}
1422+
1423+
sut.register(fixture.scopes, fixture.options)
1424+
sut.onActivityCreated(activity, fixture.bundle)
1425+
1426+
// once for the screen
1427+
verify(fixture.scopes).configureScope(any())
1428+
assertSame(propagationContextAtStart, scope.propagationContext)
1429+
}
1430+
14081431
@Test
14091432
fun `sets the activity as the current screen`() {
14101433
val sut = fixture.getSut()

sentry-android-core/src/test/java/io/sentry/android/core/internal/gestures/SentryGestureListenerTracingTest.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.mockito.kotlin.verify
3535
import org.mockito.kotlin.whenever
3636
import kotlin.test.Test
3737
import kotlin.test.assertEquals
38+
import kotlin.test.assertNotEquals
3839
import kotlin.test.assertNotNull
3940
import kotlin.test.assertNull
4041

@@ -59,12 +60,14 @@ class SentryGestureListenerTracingTest {
5960
hasViewIdInRes: Boolean = true,
6061
tracesSampleRate: Double? = 1.0,
6162
isEnableUserInteractionTracing: Boolean = true,
62-
transaction: SentryTracer? = null
63+
transaction: SentryTracer? = null,
64+
isEnableAutoTraceIdGeneration: Boolean = true
6365
): SentryGestureListener {
6466
options.tracesSampleRate = tracesSampleRate
6567
options.isEnableUserInteractionTracing = isEnableUserInteractionTracing
6668
options.isEnableUserInteractionBreadcrumbs = true
6769
options.gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(true))
70+
options.isEnableAutoTraceIdGeneration = isEnableAutoTraceIdGeneration
6871

6972
whenever(scopes.options).thenReturn(options)
7073

@@ -370,6 +373,33 @@ class SentryGestureListenerTracingTest {
370373
assertEquals(OUT_OF_RANGE, fixture.transaction.status)
371374
}
372375

376+
@Test
377+
fun `when tracing is disabled and auto trace id generation is disabled, does not start a new trace`() {
378+
val sut = fixture.getSut<View>(tracesSampleRate = null, isEnableAutoTraceIdGeneration = false)
379+
380+
sut.onSingleTapUp(fixture.event)
381+
382+
verify(fixture.scopes, never()).configureScope(any())
383+
}
384+
385+
@Test
386+
fun `when tracing is disabled and auto trace id generation is enabled, starts a new trace`() {
387+
val sut = fixture.getSut<View>(tracesSampleRate = null, isEnableAutoTraceIdGeneration = true)
388+
val scope = Scope(fixture.options)
389+
val initialPropagationContext = scope.propagationContext
390+
391+
sut.onSingleTapUp(fixture.event)
392+
393+
verify(fixture.scopes).configureScope(
394+
check { callback ->
395+
callback.run(scope)
396+
// Verify that a new propagation context was set and it's different from the initial one
397+
assertNotNull(scope.propagationContext)
398+
assertNotEquals(initialPropagationContext, scope.propagationContext)
399+
}
400+
)
401+
}
402+
373403
internal open class ScrollableListView : AbsListView(mock()) {
374404
override fun getAdapter(): ListAdapter = mock()
375405
override fun setSelection(position: Int) = Unit

0 commit comments

Comments
 (0)