Skip to content

Commit 695d3a3

Browse files
lblodergetsentry-botromtsn
authored
add origin to span context (#2803)
* add origin to span context * add traceorigin to webflux * add trace origin to spans and transactions * fix tests, start moving trace origin to constants * use constants for trace origin string * add changelog * remove duplicate constant, dump api * CR * remove duplicate trace origin for okhttp integration * remove spy.log, make api * fix changelog * cr, add origin to UIElement to differentiate between old android view system and jetpack compose * Format code * add optional appendix for trace origin to SentryNavigationListener * fix line length * add / adapt tests to verify trace origin * fix changelog after merge * Update CHANGELOG.md --------- Co-authored-by: Sentry Github Bot <[email protected]> Co-authored-by: Roman Zavarnitsyn <[email protected]>
1 parent 101f707 commit 695d3a3

File tree

67 files changed

+271
-24
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+271
-24
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Features
6+
7+
- Add TraceOrigin to Transactions and Spans ([#2803](https://github.com/getsentry/sentry-java/pull/2803))
8+
59
### Fixes
610

711
- Deduplicate events happening in multiple threads simultaneously (e.g. `OutOfMemoryError`) ([#2845](https://github.com/getsentry/sentry-java/pull/2845))

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public final class ActivityLifecycleIntegration
5555
static final String TTID_OP = "ui.load.initial_display";
5656
static final String TTFD_OP = "ui.load.full_display";
5757
static final long TTFD_TIMEOUT_MILLIS = 30000;
58+
private static final String TRACE_ORIGIN = "auto.ui.activity";
5859

5960
private final @NotNull Application application;
6061
private final @NotNull BuildInfoProvider buildInfoProvider;
@@ -231,6 +232,7 @@ private void startTracing(final @NotNull Activity activity) {
231232
hub.startTransaction(
232233
new TransactionContext(activityName, TransactionNameSource.COMPONENT, UI_LOAD_OP),
233234
transactionOptions);
235+
setSpanOrigin(transaction);
234236

235237
// in case appStartTime isn't available, we don't create a span for it.
236238
if (!(firstActivityCreated || appStartTime == null || coldStart == null)) {
@@ -241,6 +243,7 @@ private void startTracing(final @NotNull Activity activity) {
241243
getAppStartDesc(coldStart),
242244
appStartTime,
243245
Instrumenter.SENTRY);
246+
setSpanOrigin(appStartSpan);
244247

245248
// in case there's already an end time (e.g. due to deferred SDK init)
246249
// we can finish the app-start span
@@ -250,11 +253,13 @@ private void startTracing(final @NotNull Activity activity) {
250253
transaction.startChild(
251254
TTID_OP, getTtidDesc(activityName), ttidStartTime, Instrumenter.SENTRY);
252255
ttidSpanMap.put(activity, ttidSpan);
256+
setSpanOrigin(ttidSpan);
253257

254258
if (timeToFullDisplaySpanEnabled && fullyDisplayedReporter != null && options != null) {
255259
final @NotNull ISpan ttfdSpan =
256260
transaction.startChild(
257261
TTFD_OP, getTtfdDesc(activityName), ttidStartTime, Instrumenter.SENTRY);
262+
setSpanOrigin(ttfdSpan);
258263
try {
259264
ttfdSpanMap.put(activity, ttfdSpan);
260265
ttfdAutoCloseFuture =
@@ -283,6 +288,12 @@ private void startTracing(final @NotNull Activity activity) {
283288
}
284289
}
285290

291+
private void setSpanOrigin(ISpan span) {
292+
if (span != null) {
293+
span.getSpanContext().setOrigin(TRACE_ORIGIN);
294+
}
295+
}
296+
286297
@VisibleForTesting
287298
void applyScope(final @NotNull Scope scope, final @NotNull ITransaction transaction) {
288299
scope.withTransaction(

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
@ApiStatus.Internal
1515
public final class AndroidViewGestureTargetLocator implements GestureTargetLocator {
1616

17+
private static final String ORIGIN = "old_view_system";
18+
1719
private final boolean isAndroidXAvailable;
1820
private final int[] coordinates = new int[2];
1921

@@ -46,7 +48,7 @@ private UiElement createUiElement(final @NotNull View targetView) {
4648
if (className == null) {
4749
className = targetView.getClass().getSimpleName();
4850
}
49-
return new UiElement(targetView, className, resourceName, null);
51+
return new UiElement(targetView, className, resourceName, null, ORIGIN);
5052
} catch (Resources.NotFoundException ignored) {
5153
return null;
5254
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
public final class SentryGestureListener implements GestureDetector.OnGestureListener {
3434

3535
static final String UI_ACTION = "ui.action";
36+
private static final String TRACE_ORIGIN = "auto.ui.gesture_listener";
3637

3738
private final @NotNull WeakReference<Activity> activityRef;
3839
private final @NotNull IHub hub;
@@ -243,6 +244,8 @@ private void startTracing(final @NotNull UiElement target, final @NotNull String
243244
hub.startTransaction(
244245
new TransactionContext(name, TransactionNameSource.COMPONENT, op), transactionOptions);
245246

247+
transaction.getSpanContext().setOrigin(TRACE_ORIGIN + "." + target.getOrigin());
248+
246249
hub.configureScope(
247250
scope -> {
248251
applyScope(scope, transaction);

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,13 @@ import io.sentry.IHub
1313
import io.sentry.Scope
1414
import io.sentry.ScopeCallback
1515
import io.sentry.SentryTracer
16+
import io.sentry.SpanContext
17+
import io.sentry.SpanId
1618
import io.sentry.SpanStatus
1719
import io.sentry.TransactionContext
1820
import io.sentry.TransactionOptions
1921
import io.sentry.android.core.SentryAndroidOptions
22+
import io.sentry.protocol.SentryId
2023
import io.sentry.protocol.TransactionNameSource
2124
import org.mockito.kotlin.any
2225
import org.mockito.kotlin.check
@@ -307,6 +310,10 @@ class SentryGestureListenerTracingTest {
307310
val transaction = mock<SentryTracer>()
308311
val sut = fixture.getSut<View>(transaction = transaction)
309312

313+
whenever(transaction.spanContext).thenReturn(
314+
SpanContext(SentryId.EMPTY_ID, SpanId.EMPTY_ID, "op", null, null)
315+
)
316+
310317
sut.onSingleTapUp(fixture.event)
311318

312319
verify(fixture.hub).startTransaction(
@@ -323,6 +330,15 @@ class SentryGestureListenerTracingTest {
323330
verify(fixture.transaction).scheduleFinish()
324331
}
325332

333+
@Test
334+
fun `captures transaction and sets trace origin`() {
335+
val sut = fixture.getSut<View>()
336+
337+
sut.onSingleTapUp(fixture.event)
338+
339+
assertEquals("auto.ui.gesture_listener.old_view_system", fixture.transaction.spanContext.origin)
340+
}
341+
326342
internal open class ScrollableListView : AbsListView(mock()) {
327343
override fun getAdapter(): ListAdapter = mock()
328344
override fun setSelection(position: Int) = Unit

sentry-android-fragment/src/main/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacks.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import io.sentry.SpanStatus
1616
import io.sentry.TypeCheckHint.ANDROID_FRAGMENT
1717
import java.util.WeakHashMap
1818

19+
private const val TRACE_ORIGIN = "auto.ui.fragment"
20+
1921
@Suppress("TooManyFunctions")
2022
class SentryFragmentLifecycleCallbacks(
2123
private val hub: IHub = HubAdapter.getInstance(),
@@ -164,6 +166,7 @@ class SentryFragmentLifecycleCallbacks(
164166

165167
span?.let {
166168
fragmentsWithOngoingTransactions[fragment] = it
169+
it.spanContext.origin = TRACE_ORIGIN
167170
}
168171
}
169172

sentry-android-fragment/src/test/java/io/sentry/android/fragment/SentryFragmentLifecycleCallbacksTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import io.sentry.Scope
1212
import io.sentry.ScopeCallback
1313
import io.sentry.SentryLevel.INFO
1414
import io.sentry.SentryOptions
15+
import io.sentry.SpanContext
16+
import io.sentry.SpanId
1517
import io.sentry.SpanStatus
18+
import io.sentry.protocol.SentryId
1619
import org.mockito.kotlin.any
1720
import org.mockito.kotlin.anyOrNull
1821
import org.mockito.kotlin.check
@@ -47,6 +50,9 @@ class SentryFragmentLifecycleCallbacksTest {
4750
setTracesSampleRate(tracesSampleRate)
4851
}
4952
)
53+
whenever(span.spanContext).thenReturn(
54+
SpanContext(SentryId.EMPTY_ID, SpanId.EMPTY_ID, "op", null, null)
55+
)
5056
whenever(transaction.startChild(any(), any())).thenReturn(span)
5157
whenever(scope.transaction).thenReturn(transaction)
5258
whenever(hub.configureScope(any())).thenAnswer {

sentry-android-navigation/api/sentry-android-navigation.api

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ public final class io/sentry/android/navigation/SentryNavigationListener : andro
1313
public fun <init> (Lio/sentry/IHub;)V
1414
public fun <init> (Lio/sentry/IHub;Z)V
1515
public fun <init> (Lio/sentry/IHub;ZZ)V
16-
public synthetic fun <init> (Lio/sentry/IHub;ZZILkotlin/jvm/internal/DefaultConstructorMarker;)V
16+
public fun <init> (Lio/sentry/IHub;ZZLjava/lang/String;)V
17+
public synthetic fun <init> (Lio/sentry/IHub;ZZLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
1718
public fun onDestinationChanged (Landroidx/navigation/NavController;Landroidx/navigation/NavDestination;Landroid/os/Bundle;)V
1819
}
1920

sentry-android-navigation/src/main/java/io/sentry/android/navigation/SentryNavigationListener.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import io.sentry.protocol.TransactionNameSource
2222
import io.sentry.util.TracingUtils
2323
import java.lang.ref.WeakReference
2424

25+
private const val TRACE_ORIGIN = "auto.navigation"
26+
2527
/**
2628
* A [NavController.OnDestinationChangedListener] that captures a [Breadcrumb] and starts an
2729
* [ITransaction] and sends them to Sentry for each [onDestinationChanged] call.
@@ -34,7 +36,8 @@ import java.lang.ref.WeakReference
3436
class SentryNavigationListener @JvmOverloads constructor(
3537
private val hub: IHub = HubAdapter.getInstance(),
3638
private val enableNavigationBreadcrumbs: Boolean = true,
37-
private val enableNavigationTracing: Boolean = true
39+
private val enableNavigationTracing: Boolean = true,
40+
private val traceOriginAppendix: String? = null
3841
) : NavController.OnDestinationChangedListener, IntegrationName {
3942

4043
private var previousDestinationRef: WeakReference<NavDestination>? = null
@@ -140,6 +143,10 @@ class SentryNavigationListener @JvmOverloads constructor(
140143
transactonOptions
141144
)
142145

146+
transaction.spanContext.origin = traceOriginAppendix?.let {
147+
"$TRACE_ORIGIN.$traceOriginAppendix"
148+
} ?: TRACE_ORIGIN
149+
143150
if (arguments.isNotEmpty()) {
144151
transaction.setData("arguments", arguments)
145152
}

sentry-android-navigation/src/test/java/io/sentry/android/navigation/SentryNavigationListenerTest.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ class SentryNavigationListenerTest {
5757
enableTracing: Boolean = true,
5858
tracesSampleRate: Double? = 1.0,
5959
hasViewIdInRes: Boolean = true,
60-
transaction: SentryTracer? = null
60+
transaction: SentryTracer? = null,
61+
traceOriginAppendix: String? = null
6162
): SentryNavigationListener {
6263
options = SentryOptions().apply {
6364
dsn = "http://key@localhost/proj"
@@ -93,7 +94,7 @@ class SentryNavigationListenerTest {
9394
whenever(context.resources).thenReturn(resources)
9495
whenever(navController.context).thenReturn(context)
9596
whenever(destination.route).thenReturn(toRoute)
96-
return SentryNavigationListener(hub, enableBreadcrumbs, enableTracing)
97+
return SentryNavigationListener(hub, enableBreadcrumbs, enableTracing, traceOriginAppendix)
9798
}
9899
}
99100

@@ -366,4 +367,22 @@ class SentryNavigationListenerTest {
366367
verify(fixture.hub).configureScope(any())
367368
assertNotSame(propagationContextAtStart, scope.propagationContext)
368369
}
370+
371+
@Test
372+
fun `onDestinationChanged sets trace origin`() {
373+
val sut = fixture.getSut()
374+
375+
sut.onDestinationChanged(fixture.navController, fixture.destination, null)
376+
377+
assertEquals("auto.navigation", fixture.transaction.spanContext.origin)
378+
}
379+
380+
@Test
381+
fun `onDestinationChanged sets trace origin with appendix`() {
382+
val sut = fixture.getSut(traceOriginAppendix = "jetpack_compose")
383+
384+
sut.onDestinationChanged(fixture.navController, fixture.destination, null)
385+
386+
assertEquals("auto.navigation.jetpack_compose", fixture.transaction.spanContext.origin)
387+
}
369388
}

0 commit comments

Comments
 (0)