Skip to content

Commit

Permalink
Hook up Activity Open tracing component
Browse files Browse the repository at this point in the history
  • Loading branch information
bidetofevil committed Nov 28, 2024
1 parent e6d6485 commit af16658
Show file tree
Hide file tree
Showing 18 changed files with 488 additions and 124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ interface AutoDataCaptureBehavior : ConfigBehavior<EnabledFeatureConfig, RemoteC
*/
fun isV2StorageEnabled(): Boolean

/**
* Whether the SDK is configured to capture traces for the performance of the opening of Activities.
*/
fun isUiLoadPerfCaptureEnabled(): Boolean

/**
* Gates whether the SDK should use OkHttp or fallback to UrlConnection.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class AutoDataCaptureBehaviorImpl(

override fun isNativeCrashCaptureEnabled(): Boolean = local.isNativeCrashCaptureEnabled()
override fun isDiskUsageCaptureEnabled(): Boolean = local.isDiskUsageCaptureEnabled()
override fun isUiLoadPerfCaptureEnabled(): Boolean = local.isUiLoadPerfCaptureEnabled()

private val v2StorageImpl by lazy {
thresholdCheck.isBehaviorEnabled(remote?.killSwitchConfig?.v2StoragePct) ?: V2_STORAGE_ENABLED_DEFAULT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ internal class AutoDataCaptureBehaviorImplTest {
assertFalse(isNativeCrashCaptureEnabled())
assertTrue(isDiskUsageCaptureEnabled())
assertTrue(isThermalStatusCaptureEnabled())
assertFalse(isUiLoadPerfCaptureEnabled())
assertTrue(isThermalStatusCaptureEnabled())
assertTrue(isV2StorageEnabled())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ internal class EmbraceSpanBuilderTest {

assertTrue(perfSpanBuilder.getFixedAttributes().toSet().contains(KeySpan))

val activityOpenSpanBuilder = EmbraceSpanBuilder(
val uiLoadSpanBuilder = EmbraceSpanBuilder(
tracer = tracer,
name = "test",
telemetryType = EmbType.Performance.UiLoad,
Expand All @@ -177,7 +177,7 @@ internal class EmbraceSpanBuilderTest {
parentSpan = null,
)

assertTrue(activityOpenSpanBuilder.getFixedAttributes().toSet().contains(KeySpan))
assertTrue(uiLoadSpanBuilder.getFixedAttributes().toSet().contains(KeySpan))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import android.view.Window
import io.embrace.android.embracesdk.annotation.StartupActivity
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.logging.InternalErrorType
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.utils.VersionChecker

/**
Expand All @@ -38,6 +39,7 @@ import io.embrace.android.embracesdk.internal.utils.VersionChecker
*/
class StartupTracker(
private val appStartupDataCollector: AppStartupDataCollector,
private val uiLoadEventEmitter: ActivityLifecycleListener?,
private val logger: EmbLogger,
private val versionChecker: VersionChecker,
) : Application.ActivityLifecycleCallbacks {
Expand Down Expand Up @@ -123,6 +125,9 @@ class StartupTracker(
private fun startupComplete(application: Application) {
if (!startupDataCollectionComplete) {
application.unregisterActivityLifecycleCallbacks(this)
uiLoadEventEmitter?.apply {
application.registerActivityLifecycleCallbacks(this)
}
startupDataCollectionComplete = true
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.embrace.android.embracesdk.internal.injection

import io.embrace.android.embracesdk.internal.capture.activity.UiLoadEventEmitter
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadEvents
import io.embrace.android.embracesdk.internal.capture.crumbs.ActivityBreadcrumbTracker
import io.embrace.android.embracesdk.internal.capture.crumbs.PushNotificationCaptureService
import io.embrace.android.embracesdk.internal.capture.startup.AppStartupDataCollector
Expand Down Expand Up @@ -35,7 +37,11 @@ interface DataCaptureServiceModule {
*/
val startupService: StartupService

val appStartupDataCollector: AppStartupDataCollector

val startupTracker: StartupTracker

val appStartupDataCollector: AppStartupDataCollector
val uiLoadEvents: UiLoadEvents

val uiLoadEventEmitter: UiLoadEventEmitter?
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.embrace.android.embracesdk.internal.injection

import io.embrace.android.embracesdk.internal.Systrace
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadEventEmitter
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadEvents
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadTraceEmitter
import io.embrace.android.embracesdk.internal.capture.crumbs.ActivityBreadcrumbTracker
import io.embrace.android.embracesdk.internal.capture.crumbs.PushNotificationCaptureService
import io.embrace.android.embracesdk.internal.capture.startup.AppStartupDataCollector
Expand Down Expand Up @@ -62,8 +65,28 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
override val startupTracker: StartupTracker by singleton {
StartupTracker(
appStartupDataCollector = appStartupDataCollector,
uiLoadEventEmitter = uiLoadEventEmitter,
logger = initModule.logger,
versionChecker = versionChecker,
)
}

override val uiLoadEvents: UiLoadEvents by singleton {
UiLoadTraceEmitter(
spanService = openTelemetryModule.spanService,
versionChecker = versionChecker,
)
}

override val uiLoadEventEmitter: UiLoadEventEmitter? by singleton {
if (configService.autoDataCaptureBehavior.isUiLoadPerfCaptureEnabled()) {
UiLoadEventEmitter(
uiLoadEvents = uiLoadEvents,
clock = openTelemetryModule.openTelemetryClock,
versionChecker = versionChecker,
)
} else {
null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import android.os.Build
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeObservedActivity
import io.embrace.android.embracesdk.fakes.FakeUiLoadEvents
import io.embrace.android.embracesdk.fakes.FakeUiLoadEvents.EventData
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.POST_DURATION
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.PRE_DURATION
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.STATE_DURATION
import io.embrace.android.embracesdk.internal.capture.activity.UiLoadEventEmitterTest.FakeOpenEvents.EventData
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import org.junit.Assert.assertEquals
import org.junit.Before
Expand All @@ -25,7 +26,7 @@ import kotlin.reflect.KClass
@RunWith(AndroidJUnit4::class)
internal class UiLoadEventEmitterTest {
private lateinit var clock: FakeClock
private lateinit var openEvents: FakeOpenEvents
private lateinit var openEvents: FakeUiLoadEvents
private lateinit var eventEmitter: UiLoadEventEmitter
private lateinit var activityController: ActivityController<*>
private var startTimeMs: Long = 0L
Expand All @@ -37,7 +38,7 @@ internal class UiLoadEventEmitterTest {
clock = FakeClock()
val initModule = FakeInitModule(clock = clock)
clock.tick(100L)
openEvents = FakeOpenEvents()
openEvents = FakeUiLoadEvents()
eventEmitter = UiLoadEventEmitter(
uiLoadEvents = openEvents,
clock = initModule.openTelemetryModule.openTelemetryClock,
Expand Down Expand Up @@ -262,120 +263,4 @@ internal class UiLoadEventEmitterTest {
activityName = activityName,
timestampMs = timestampMs
)

class FakeOpenEvents : UiLoadEvents {
val events = mutableListOf<EventData>()

override fun abandon(instanceId: Int, activityName: String, timestampMs: Long) {
events.add(
EventData(
stage = "abandon",
instanceId = instanceId,
activityName = activityName,
timestampMs = timestampMs
)
)
}

override fun reset(instanceId: Int) {
events.add(
EventData(
stage = "reset",
instanceId = instanceId,
)
)
}

override fun create(instanceId: Int, activityName: String, timestampMs: Long) {
events.add(
EventData(
stage = "create",
instanceId = instanceId,
activityName = activityName,
timestampMs = timestampMs
)
)
}

override fun createEnd(instanceId: Int, timestampMs: Long) {
events.add(
EventData(
stage = "createEnd",
instanceId = instanceId,
activityName = null,
timestampMs = timestampMs
)
)
}

override fun start(instanceId: Int, activityName: String, timestampMs: Long) {
events.add(
EventData(
stage = "start",
instanceId = instanceId,
activityName = activityName,
timestampMs = timestampMs
)
)
}

override fun startEnd(instanceId: Int, timestampMs: Long) {
events.add(
EventData(
stage = "startEnd",
instanceId = instanceId,
timestampMs = timestampMs
)
)
}

override fun resume(instanceId: Int, activityName: String, timestampMs: Long) {
events.add(
EventData(
stage = "resume",
instanceId = instanceId,
activityName = activityName,
timestampMs = timestampMs
)
)
}

override fun resumeEnd(instanceId: Int, timestampMs: Long) {
events.add(
EventData(
stage = "resumeEnd",
instanceId = instanceId,
timestampMs = timestampMs
)
)
}

override fun render(instanceId: Int, activityName: String, timestampMs: Long) {
events.add(
EventData(
stage = "render",
instanceId = instanceId,
activityName = activityName,
timestampMs = timestampMs
)
)
}

override fun renderEnd(instanceId: Int, timestampMs: Long) {
events.add(
EventData(
stage = "renderEnd",
instanceId = instanceId,
timestampMs = timestampMs
)
)
}

data class EventData(
val stage: String,
val instanceId: Int,
val activityName: String? = null,
val timestampMs: Long? = null,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.embrace.android.embracesdk.fakes.FakeClock
import io.embrace.android.embracesdk.fakes.FakeEmbLogger
import io.embrace.android.embracesdk.fakes.FakeSplashScreenActivity
import io.embrace.android.embracesdk.internal.logging.EmbLogger
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
Expand Down Expand Up @@ -38,6 +39,7 @@ internal class StartupTrackerTest {
dataCollector = FakeAppStartupDataCollector(clock = clock)
startupTracker = StartupTracker(
appStartupDataCollector = dataCollector,
uiLoadEventEmitter = object : ActivityLifecycleListener { },
logger = logger,
versionChecker = BuildVersionChecker
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package io.embrace.android.embracesdk.internal.injection
import io.embrace.android.embracesdk.fakes.FakeConfigService
import io.embrace.android.embracesdk.fakes.FakeFeatureModule
import io.embrace.android.embracesdk.fakes.FakeVersionChecker
import io.embrace.android.embracesdk.fakes.behavior.FakeAutoDataCaptureBehavior
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
import io.embrace.android.embracesdk.fakes.injection.FakeWorkerThreadModule
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test

internal class DataCaptureServiceModuleImplTest {
Expand All @@ -29,5 +31,23 @@ internal class DataCaptureServiceModuleImplTest {
assertNotNull(module.appStartupDataCollector)
assertNotNull(module.pushNotificationService)
assertNotNull(module.startupService)
assertNull(module.uiLoadEventEmitter)
}

@Test
fun `enable ui load performance capture`() {
val module = DataCaptureServiceModuleImpl(
initModule,
openTelemetryModule,
FakeConfigService(
autoDataCaptureBehavior = FakeAutoDataCaptureBehavior(uiLoadPerfCaptureEnabled = true)
),
FakeWorkerThreadModule(),
FakeVersionChecker(false),
FakeFeatureModule()
)

assertNotNull(module.uiLoadEvents)
assertNotNull(module.uiLoadEventEmitter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,11 @@ interface EnabledFeatureConfig {
* sdk_config.networking.enable_network_span_forwarding
*/
fun isNetworkSpanForwardingEnabled(): Boolean = false

/**
* Gates whether the SDK will capture traces for the performance of the opening of Activities.
*
* sdk_config.automatic_data_capture.ui_load_perf_info
*/
fun isUiLoadPerfCaptureEnabled(): Boolean = false
}
Loading

0 comments on commit af16658

Please sign in to comment.