Skip to content

Commit 675fc87

Browse files
adinauermarandanetoromtsngetsentry-bot
authored
Tracing without Performance (#2788)
Co-authored-by: Manoel Aranda Neto <[email protected]> Co-authored-by: Roman Zavarnitsyn <[email protected]> Co-authored-by: Sentry Github Bot <[email protected]>
1 parent dc67004 commit 675fc87

File tree

55 files changed

+2177
-669
lines changed

Some content is hidden

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

55 files changed

+2177
-669
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Features
66

77
- Add manifest `AutoInit` to integrations list ([#2795](https://github.com/getsentry/sentry-java/pull/2795))
8+
- Tracing headers (`sentry-trace` and `baggage`) are now attached and passed through even if performance is disabled ([#2788](https://github.com/getsentry/sentry-java/pull/2788))
89

910
### Dependencies
1011

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

Lines changed: 159 additions & 149 deletions
Large diffs are not rendered by default.

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import io.sentry.android.core.SentryAndroidOptions;
2121
import io.sentry.internal.gestures.UiElement;
2222
import io.sentry.protocol.TransactionNameSource;
23+
import io.sentry.util.TracingUtils;
2324
import java.lang.ref.WeakReference;
2425
import java.util.Collections;
2526
import java.util.Map;
@@ -185,7 +186,13 @@ private void addBreadcrumb(
185186
}
186187

187188
private void startTracing(final @NotNull UiElement target, final @NotNull String eventType) {
189+
final UiElement uiElement = activeUiElement;
188190
if (!(options.isTracingEnabled() && options.isEnableUserInteractionTracing())) {
191+
if (!(target.equals(uiElement) && eventType.equals(activeEventType))) {
192+
TracingUtils.startNewTrace(hub);
193+
activeUiElement = target;
194+
activeEventType = eventType;
195+
}
189196
return;
190197
}
191198

@@ -196,7 +203,6 @@ private void startTracing(final @NotNull UiElement target, final @NotNull String
196203
}
197204

198205
final @Nullable String viewIdentifier = target.getIdentifier();
199-
final UiElement uiElement = activeUiElement;
200206

201207
if (activeTransaction != null) {
202208
if (target.equals(uiElement)

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

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import io.sentry.FullyDisplayedReporter
1616
import io.sentry.Hub
1717
import io.sentry.ISentryExecutorService
1818
import io.sentry.Scope
19+
import io.sentry.ScopeCallback
1920
import io.sentry.Sentry
2021
import io.sentry.SentryDate
2122
import io.sentry.SentryLevel
@@ -32,10 +33,12 @@ import io.sentry.protocol.MeasurementValue
3233
import io.sentry.protocol.TransactionNameSource
3334
import io.sentry.test.getProperty
3435
import org.junit.runner.RunWith
36+
import org.mockito.ArgumentCaptor
3537
import org.mockito.kotlin.any
3638
import org.mockito.kotlin.anyOrNull
3739
import org.mockito.kotlin.argumentCaptor
3840
import org.mockito.kotlin.check
41+
import org.mockito.kotlin.clearInvocations
3942
import org.mockito.kotlin.eq
4043
import org.mockito.kotlin.mock
4144
import org.mockito.kotlin.never
@@ -54,6 +57,7 @@ import kotlin.test.assertEquals
5457
import kotlin.test.assertFalse
5558
import kotlin.test.assertNotEquals
5659
import kotlin.test.assertNotNull
60+
import kotlin.test.assertNotSame
5761
import kotlin.test.assertNull
5862
import kotlin.test.assertSame
5963
import kotlin.test.assertTrue
@@ -141,13 +145,13 @@ class ActivityLifecycleIntegrationTest {
141145
}
142146

143147
@Test
144-
fun `When activity lifecycle breadcrumb and tracing are disabled, it doesn't register callback`() {
148+
fun `When activity lifecycle breadcrumb and tracing are disabled, it still registers callback`() {
145149
val sut = fixture.getSut()
146150
fixture.options.isEnableActivityLifecycleBreadcrumbs = false
147151

148152
sut.register(fixture.hub, fixture.options)
149153

150-
verify(fixture.application, never()).registerActivityLifecycleCallbacks(any())
154+
verify(fixture.application).registerActivityLifecycleCallbacks(any())
151155
}
152156

153157
@Test
@@ -162,15 +166,15 @@ class ActivityLifecycleIntegrationTest {
162166
}
163167

164168
@Test
165-
fun `When activity lifecycle breadcrumb is disabled and tracesSampleRate is set but tracing is disabled, it does not register callback`() {
169+
fun `When activity lifecycle breadcrumb is disabled and tracesSampleRate is set but tracing is disabled, it still registers callback`() {
166170
val sut = fixture.getSut()
167171
fixture.options.isEnableActivityLifecycleBreadcrumbs = false
168172
fixture.options.tracesSampleRate = 1.0
169173
fixture.options.enableTracing = false
170174

171175
sut.register(fixture.hub, fixture.options)
172176

173-
verify(fixture.application, never()).registerActivityLifecycleCallbacks(any())
177+
verify(fixture.application).registerActivityLifecycleCallbacks(any())
174178
}
175179

176180
@Test
@@ -196,7 +200,7 @@ class ActivityLifecycleIntegrationTest {
196200
}
197201

198202
@Test
199-
fun `When activity lifecycle breadcrumb and tracing activity flag are disabled, it doesn't register callback`() {
203+
fun `When activity lifecycle breadcrumb and tracing activity flag are disabled, its still registers callback`() {
200204
val sut = fixture.getSut()
201205
fixture.options.isEnableActivityLifecycleBreadcrumbs = false
202206
fixture.options.tracesSampleRate = 1.0
@@ -205,7 +209,7 @@ class ActivityLifecycleIntegrationTest {
205209

206210
sut.register(fixture.hub, fixture.options)
207211

208-
verify(fixture.application, never()).registerActivityLifecycleCallbacks(any())
212+
verify(fixture.application).registerActivityLifecycleCallbacks(any())
209213
}
210214

211215
@Test
@@ -1384,6 +1388,60 @@ class ActivityLifecycleIntegrationTest {
13841388
assertFalse(ttfdSpan2.isFinished)
13851389
}
13861390

1391+
@Test
1392+
fun `starts new trace if performance is disabled`() {
1393+
val sut = fixture.getSut()
1394+
val activity = mock<Activity>()
1395+
fixture.options.enableTracing = false
1396+
1397+
val argumentCaptor: ArgumentCaptor<ScopeCallback> = ArgumentCaptor.forClass(ScopeCallback::class.java)
1398+
val scope = Scope(fixture.options)
1399+
val propagationContextAtStart = scope.propagationContext
1400+
whenever(fixture.hub.configureScope(argumentCaptor.capture())).thenAnswer {
1401+
argumentCaptor.value.run(scope)
1402+
}
1403+
1404+
sut.register(fixture.hub, fixture.options)
1405+
sut.onActivityCreated(activity, fixture.bundle)
1406+
1407+
verify(fixture.hub).configureScope(any())
1408+
assertNotSame(propagationContextAtStart, scope.propagationContext)
1409+
}
1410+
1411+
@Test
1412+
fun `does not start another new trace if one has already been started but does after activity was destroyed`() {
1413+
val sut = fixture.getSut()
1414+
val activity = mock<Activity>()
1415+
fixture.options.enableTracing = false
1416+
1417+
val argumentCaptor: ArgumentCaptor<ScopeCallback> = ArgumentCaptor.forClass(ScopeCallback::class.java)
1418+
val scope = Scope(fixture.options)
1419+
val propagationContextAtStart = scope.propagationContext
1420+
whenever(fixture.hub.configureScope(argumentCaptor.capture())).thenAnswer {
1421+
argumentCaptor.value.run(scope)
1422+
}
1423+
1424+
sut.register(fixture.hub, fixture.options)
1425+
sut.onActivityCreated(activity, fixture.bundle)
1426+
1427+
verify(fixture.hub).configureScope(any())
1428+
val propagationContextAfterNewTrace = scope.propagationContext
1429+
assertNotSame(propagationContextAtStart, propagationContextAfterNewTrace)
1430+
1431+
clearInvocations(fixture.hub)
1432+
sut.onActivityCreated(activity, fixture.bundle)
1433+
1434+
verify(fixture.hub, never()).configureScope(any())
1435+
assertSame(propagationContextAfterNewTrace, scope.propagationContext)
1436+
1437+
sut.onActivityDestroyed(activity)
1438+
1439+
clearInvocations(fixture.hub)
1440+
sut.onActivityCreated(activity, fixture.bundle)
1441+
verify(fixture.hub).configureScope(any())
1442+
assertNotSame(propagationContextAfterNewTrace, scope.propagationContext)
1443+
}
1444+
13871445
private fun runFirstDraw(view: View) {
13881446
// Removes OnDrawListener in the next OnGlobalLayout after onDraw
13891447
view.viewTreeObserver.dispatchOnDraw()

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ import android.widget.CheckBox
1111
import android.widget.RadioButton
1212
import io.sentry.Breadcrumb
1313
import io.sentry.IHub
14+
import io.sentry.PropagationContext
15+
import io.sentry.Scope
16+
import io.sentry.Scope.IWithPropagationContext
17+
import io.sentry.ScopeCallback
1418
import io.sentry.SentryLevel.INFO
1519
import io.sentry.android.core.SentryAndroidOptions
1620
import org.mockito.kotlin.any
1721
import org.mockito.kotlin.anyOrNull
1822
import org.mockito.kotlin.check
23+
import org.mockito.kotlin.doAnswer
1924
import org.mockito.kotlin.mock
2025
import org.mockito.kotlin.never
2126
import org.mockito.kotlin.verify
@@ -36,6 +41,8 @@ class SentryGestureListenerClickTest {
3641
dsn = "https://[email protected]/proj"
3742
}
3843
val hub = mock<IHub>()
44+
val scope = mock<Scope>()
45+
val propagationContext = PropagationContext()
3946
lateinit var target: View
4047
lateinit var invalidTarget: View
4148

@@ -79,6 +86,8 @@ class SentryGestureListenerClickTest {
7986
whenever(context.resources).thenReturn(resources)
8087
whenever(this.target.context).thenReturn(context)
8188
whenever(activity.window).thenReturn(window)
89+
doAnswer { (it.arguments[0] as ScopeCallback).run(scope) }.whenever(hub).configureScope(any())
90+
doAnswer { (it.arguments[0] as IWithPropagationContext).accept(propagationContext); propagationContext; }.whenever(scope).withPropagationContext(any())
8291
return SentryGestureListener(
8392
activity,
8493
hub,
@@ -228,4 +237,20 @@ class SentryGestureListenerClickTest {
228237
anyOrNull()
229238
)
230239
}
240+
241+
@Test
242+
fun `creates new trace on click`() {
243+
class LocalView(context: Context) : View(context)
244+
245+
val event = mock<MotionEvent>()
246+
val sut = fixture.getSut<LocalView>(event, attachViewsToRoot = false)
247+
fixture.window.mockDecorView<ViewGroup>(event = event, touchWithinBounds = false) {
248+
whenever(it.childCount).thenReturn(1)
249+
whenever(it.getChildAt(0)).thenReturn(fixture.target)
250+
}
251+
252+
sut.onSingleTapUp(event)
253+
254+
verify(fixture.scope).propagationContext = any()
255+
}
231256
}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@ import android.widget.ListAdapter
1212
import androidx.core.view.ScrollingView
1313
import io.sentry.Breadcrumb
1414
import io.sentry.IHub
15+
import io.sentry.PropagationContext
16+
import io.sentry.Scope
17+
import io.sentry.ScopeCallback
1518
import io.sentry.SentryLevel.INFO
1619
import io.sentry.android.core.SentryAndroidOptions
1720
import org.mockito.kotlin.any
1821
import org.mockito.kotlin.anyOrNull
1922
import org.mockito.kotlin.check
23+
import org.mockito.kotlin.clearInvocations
24+
import org.mockito.kotlin.doAnswer
2025
import org.mockito.kotlin.inOrder
2126
import org.mockito.kotlin.mock
2227
import org.mockito.kotlin.never
28+
import org.mockito.kotlin.times
2329
import org.mockito.kotlin.verify
2430
import org.mockito.kotlin.verifyNoMoreInteractions
2531
import org.mockito.kotlin.whenever
@@ -39,6 +45,8 @@ class SentryGestureListenerScrollTest {
3945
gestureTargetLocators = listOf(AndroidViewGestureTargetLocator(true))
4046
}
4147
val hub = mock<IHub>()
48+
val scope = mock<Scope>()
49+
val propagationContext = PropagationContext()
4250

4351
val firstEvent = mock<MotionEvent>()
4452
val eventsInBetween = listOf(mock<MotionEvent>(), mock(), mock())
@@ -69,6 +77,8 @@ class SentryGestureListenerScrollTest {
6977
endEvent.mockDirection(firstEvent, direction)
7078
}
7179
whenever(activity.window).thenReturn(window)
80+
doAnswer { (it.arguments[0] as ScopeCallback).run(scope) }.whenever(hub).configureScope(any())
81+
doAnswer { (it.arguments[0] as Scope.IWithPropagationContext).accept(propagationContext); propagationContext }.whenever(scope).withPropagationContext(any())
7282
return SentryGestureListener(
7383
activity,
7484
hub,
@@ -145,6 +155,7 @@ class SentryGestureListenerScrollTest {
145155
},
146156
anyOrNull()
147157
)
158+
verify(fixture.hub).configureScope(anyOrNull())
148159
verify(fixture.hub).addBreadcrumb(
149160
check<Breadcrumb> {
150161
assertEquals("ui.swipe", it.category)
@@ -182,6 +193,50 @@ class SentryGestureListenerScrollTest {
182193
verify(fixture.hub, never()).addBreadcrumb(any<Breadcrumb>())
183194
}
184195

196+
@Test
197+
fun `starts a new trace on scroll`() {
198+
val sut = fixture.getSut<ScrollableListView>(direction = "left")
199+
200+
sut.onDown(fixture.firstEvent)
201+
fixture.eventsInBetween.forEach {
202+
sut.onScroll(fixture.firstEvent, it, 10.0f, 0f)
203+
}
204+
sut.onUp(fixture.endEvent)
205+
206+
verify(fixture.scope).propagationContext = any()
207+
}
208+
209+
@Test
210+
fun `does not start a new trace on repeated scroll but does for a different event`() {
211+
val sut = fixture.getSut<ScrollableListView>(direction = "left")
212+
213+
sut.onDown(fixture.firstEvent)
214+
fixture.eventsInBetween.forEach {
215+
sut.onScroll(fixture.firstEvent, it, 10.0f, 0f)
216+
}
217+
sut.onUp(fixture.endEvent)
218+
219+
verify(fixture.scope).propagationContext = any()
220+
221+
clearInvocations(fixture.scope)
222+
223+
sut.onDown(fixture.firstEvent)
224+
fixture.eventsInBetween.forEach {
225+
sut.onScroll(fixture.firstEvent, it, 10.0f, 0f)
226+
}
227+
sut.onUp(fixture.endEvent)
228+
verify(fixture.scope, never()).propagationContext = any()
229+
230+
clearInvocations(fixture.scope)
231+
232+
sut.onDown(fixture.firstEvent)
233+
fixture.eventsInBetween.forEach { sut.onScroll(fixture.firstEvent, it, 0f, 30.0f) }
234+
sut.onFling(fixture.firstEvent, fixture.endEvent, 1.0f, 1.0f)
235+
sut.onUp(fixture.endEvent)
236+
237+
verify(fixture.scope).propagationContext = any()
238+
}
239+
185240
internal class ScrollableView : View(mock()), ScrollingView {
186241
override fun computeVerticalScrollOffset(): Int = 0
187242
override fun computeVerticalScrollExtent(): Int = 0

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import android.widget.AbsListView
1111
import android.widget.ListAdapter
1212
import io.sentry.IHub
1313
import io.sentry.Scope
14+
import io.sentry.ScopeCallback
1415
import io.sentry.SentryTracer
1516
import io.sentry.SpanStatus
1617
import io.sentry.TransactionContext
@@ -20,6 +21,7 @@ import io.sentry.protocol.TransactionNameSource
2021
import org.mockito.kotlin.any
2122
import org.mockito.kotlin.check
2223
import org.mockito.kotlin.clearInvocations
24+
import org.mockito.kotlin.doAnswer
2325
import org.mockito.kotlin.mock
2426
import org.mockito.kotlin.never
2527
import org.mockito.kotlin.verify
@@ -40,6 +42,7 @@ class SentryGestureListenerTracingTest {
4042
}
4143
val hub = mock<IHub>()
4244
val event = mock<MotionEvent>()
45+
val scope = mock<Scope>()
4346
lateinit var target: View
4447
lateinit var transaction: SentryTracer
4548

@@ -79,6 +82,7 @@ class SentryGestureListenerTracingTest {
7982

8083
whenever(hub.startTransaction(any(), any<TransactionOptions>()))
8184
.thenReturn(this.transaction)
85+
doAnswer { (it.arguments[0] as ScopeCallback).run(scope) }.whenever(hub).configureScope(any())
8286

8387
return SentryGestureListener(
8488
activity,

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import io.sentry.TransactionContext
1919
import io.sentry.TransactionOptions
2020
import io.sentry.TypeCheckHint
2121
import io.sentry.protocol.TransactionNameSource
22+
import io.sentry.util.TracingUtils
2223
import java.lang.ref.WeakReference
2324

2425
/**
@@ -96,6 +97,7 @@ class SentryNavigationListener @JvmOverloads constructor(
9697
arguments: Map<String, Any?>
9798
) {
9899
if (!isPerformanceEnabled) {
100+
TracingUtils.startNewTrace(hub)
99101
return
100102
}
101103

0 commit comments

Comments
 (0)