Skip to content

Commit 3a2b1a9

Browse files
Merge pull request #2278 from embrace-io/refactor-clock
Use embrace clock in UI load tracing
2 parents 78a622d + f5b0c7b commit 3a2b1a9

File tree

7 files changed

+34
-42
lines changed

7 files changed

+34
-42
lines changed

embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.embrace.android.embracesdk.internal.injection
22

3+
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
34
import io.embrace.android.embracesdk.internal.config.behavior.SensitiveKeysBehavior
45
import io.embrace.android.embracesdk.internal.otel.config.OtelSdkConfig
56
import io.embrace.android.embracesdk.internal.otel.logs.LogSink
@@ -96,4 +97,6 @@ interface OpenTelemetryModule {
9697
sensitiveKeysBehavior: SensitiveKeysBehavior,
9798
bypassValidation: Boolean,
9899
)
100+
101+
fun deviceStartTimeMs(): Long = openTelemetryClock.run { now() - nanoTime() }.nanosToMillis()
99102
}

embrace-android-features/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ dependencies {
1919
compileOnly(project(":embrace-android-otel"))
2020
compileOnly(platform(libs.opentelemetry.bom))
2121
compileOnly(libs.opentelemetry.api)
22-
compileOnly(libs.opentelemetry.sdk)
22+
compileOnly(libs.opentelemetry.context)
2323
compileOnly(libs.opentelemetry.semconv)
2424
compileOnly(libs.opentelemetry.semconv.incubating)
2525
implementation(libs.lifecycle.process)
@@ -37,7 +37,7 @@ dependencies {
3737
testImplementation(project(":embrace-android-otel"))
3838
testImplementation(platform(libs.opentelemetry.bom))
3939
testImplementation(libs.opentelemetry.api)
40-
testImplementation(libs.opentelemetry.sdk)
40+
testImplementation(libs.opentelemetry.context)
4141
testImplementation(libs.opentelemetry.semconv)
4242
testImplementation(libs.opentelemetry.semconv.incubating)
4343
testImplementation(libs.lifecycle.process)

embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/activity/UiLoadExt.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@ import androidx.annotation.RequiresApi
77
import io.embrace.android.embracesdk.annotation.CustomLoadTracedActivity
88
import io.embrace.android.embracesdk.annotation.LoadTracedActivity
99
import io.embrace.android.embracesdk.annotation.NotTracedActivity
10-
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
10+
import io.embrace.android.embracesdk.internal.clock.Clock
1111
import io.embrace.android.embracesdk.internal.session.lifecycle.ActivityLifecycleListener
1212
import io.embrace.android.embracesdk.internal.ui.DrawEventEmitter
1313
import io.embrace.android.embracesdk.internal.utils.VersionChecker
14-
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
1514
import java.util.concurrent.ConcurrentHashMap
1615

1716
/**
@@ -24,7 +23,7 @@ fun createActivityLoadEventEmitter(
2423
uiLoadEventListener: UiLoadEventListener,
2524
firstDrawDetector: DrawEventEmitter?,
2625
autoTraceEnabled: Boolean,
27-
clock: OtelJavaClock,
26+
clock: Clock,
2827
versionChecker: VersionChecker,
2928
): ActivityLifecycleListener {
3029
val lifecycleEventEmitter = LifecycleEventEmitter(
@@ -120,7 +119,7 @@ private class LifecycleEventEmitter(
120119
private val uiLoadEventListener: UiLoadEventListener,
121120
private val drawEventEmitter: DrawEventEmitter?,
122121
private val autoTraceEnabled: Boolean,
123-
private val clock: OtelJavaClock,
122+
private val clock: Clock,
124123
) {
125124

126125
private val instanceStartTime: MutableMap<Int, Long> = ConcurrentHashMap()
@@ -224,5 +223,5 @@ private class LifecycleEventEmitter(
224223

225224
private fun Activity.isManualEnd(): Boolean = javaClass.isAnnotationPresent(CustomLoadTracedActivity::class.java)
226225

227-
private fun nowMs(): Long = clock.now().nanosToMillis()
226+
private fun nowMs(): Long = clock.now()
228227
}

embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/startup/AppStartupTraceEmitter.kt

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package io.embrace.android.embracesdk.internal.capture.startup
22

33
import android.os.Build.VERSION_CODES
44
import android.os.Process
5-
import io.embrace.android.embracesdk.internal.clock.nanosToMillis
5+
import io.embrace.android.embracesdk.internal.clock.Clock
66
import io.embrace.android.embracesdk.internal.logging.EmbLogger
77
import io.embrace.android.embracesdk.internal.logging.InternalErrorType
88
import io.embrace.android.embracesdk.internal.otel.attrs.embStartupActivityName
@@ -17,7 +17,6 @@ import io.embrace.android.embracesdk.internal.utils.VersionChecker
1717
import io.embrace.android.embracesdk.spans.EmbraceSpan
1818
import io.embrace.android.embracesdk.spans.EmbraceSpanEvent
1919
import io.embrace.android.embracesdk.spans.ErrorCode
20-
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
2120
import java.util.concurrent.ConcurrentHashMap
2221
import java.util.concurrent.ConcurrentLinkedQueue
2322
import java.util.concurrent.atomic.AtomicBoolean
@@ -44,15 +43,19 @@ import java.util.concurrent.atomic.AtomicReference
4443
*
4544
*/
4645
internal class AppStartupTraceEmitter(
47-
private val clock: OtelJavaClock,
46+
private val clock: Clock,
4847
private val startupServiceProvider: Provider<StartupService?>,
4948
private val spanService: SpanService,
5049
private val versionChecker: VersionChecker,
5150
private val logger: EmbLogger,
5251
manualEnd: Boolean,
52+
deviceStartTimestampMs: Long,
53+
private val processCreatedMs: Long? = if (versionChecker.isAtLeast(VERSION_CODES.N)) {
54+
deviceStartTimestampMs + Process.getStartElapsedRealtime()
55+
} else {
56+
null
57+
},
5358
) : AppStartupDataCollector, ProcessStateListener {
54-
private val processCreateRequestedMs: Long?
55-
private val processCreatedMs: Long?
5659
private val additionalTrackedIntervals = ConcurrentLinkedQueue<TrackedInterval>()
5760
private val customAttributes: MutableMap<String, String> = ConcurrentHashMap()
5861
private val trackRender = hasRenderEvent(versionChecker)
@@ -67,20 +70,6 @@ internal class AppStartupTraceEmitter(
6770
TraceEnd.RESUMED
6871
}
6972

70-
init {
71-
val timestampAtDeviceStart = nowMs() - clock.nanoTime().nanosToMillis()
72-
processCreateRequestedMs = if (versionChecker.isAtLeast(VERSION_CODES.TIRAMISU)) {
73-
timestampAtDeviceStart + Process.getStartRequestedElapsedRealtime()
74-
} else {
75-
null
76-
}
77-
processCreatedMs = if (versionChecker.isAtLeast(VERSION_CODES.N)) {
78-
timestampAtDeviceStart + Process.getStartElapsedRealtime()
79-
} else {
80-
null
81-
}
82-
}
83-
8473
@Volatile
8574
private var applicationInitStartMs: Long? = null
8675

@@ -423,7 +412,7 @@ internal class AppStartupTraceEmitter(
423412
private fun applicationActivityCreationGap(sdkInitEndMs: Long): Long? =
424413
duration(applicationInitEndMs ?: sdkInitEndMs, firstActivityInitStartMs)
425414

426-
private fun nowMs(): Long = clock.now().nanosToMillis()
415+
private fun nowMs(): Long = clock.now()
427416

428417
private fun EmbraceSdkSpan.addTraceMetadata() {
429418
addCustomAttributes()

embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/DataCaptureServiceModuleImpl.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
5353

5454
override val appStartupDataCollector: AppStartupDataCollector by singleton {
5555
AppStartupTraceEmitter(
56-
clock = openTelemetryModule.openTelemetryClock,
56+
clock = initModule.clock,
5757
startupServiceProvider = { startupService },
5858
spanService = openTelemetryModule.spanService,
5959
versionChecker = versionChecker,
6060
logger = initModule.logger,
61-
manualEnd = configService.autoDataCaptureBehavior.isEndStartupWithAppReadyEnabled()
61+
manualEnd = configService.autoDataCaptureBehavior.isEndStartupWithAppReadyEnabled(),
62+
deviceStartTimestampMs = openTelemetryModule.deviceStartTimeMs()
6263
)
6364
}
6465

@@ -88,7 +89,7 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor(
8889
uiLoadEventListener = uiLoadEventListener,
8990
firstDrawDetector = createDrawEventEmitter(versionChecker, initModule.logger),
9091
autoTraceEnabled = configService.autoDataCaptureBehavior.isUiLoadTracingTraceAll(),
91-
clock = openTelemetryModule.openTelemetryClock,
92+
clock = initModule.clock,
9293
versionChecker = versionChecker
9394
)
9495
} else {

embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/activity/UiLoadExtTest.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import io.embrace.android.embracesdk.fakes.FakeNotTracedActivity
1111
import io.embrace.android.embracesdk.fakes.FakeTracedActivity
1212
import io.embrace.android.embracesdk.fakes.FakeUiLoadEventListener
1313
import io.embrace.android.embracesdk.fakes.FakeUiLoadEventListener.EventData
14-
import io.embrace.android.embracesdk.fakes.injection.FakeInitModule
1514
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks
1615
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.POST_DURATION
1716
import io.embrace.android.embracesdk.internal.ClockTickingActivityLifecycleCallbacks.Companion.PRE_DURATION
@@ -159,7 +158,7 @@ internal class UiLoadExtTest {
159158
uiLoadEventListener = uiLoadEventListener,
160159
firstDrawDetector = drawEventEmitter,
161160
autoTraceEnabled = autoTraceEnabled,
162-
clock = FakeInitModule(clock = clock).openTelemetryModule.openTelemetryClock,
161+
clock = clock,
163162
versionChecker = BuildVersionChecker
164163
).apply {
165164
RuntimeEnvironment.getApplication().registerActivityLifecycleCallbacks(this)

embrace-android-features/src/test/java/io/embrace/android/embracesdk/internal/capture/startup/AppStartupTraceEmitterTest.kt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import io.embrace.android.embracesdk.internal.ui.hasRenderEvent
3131
import io.embrace.android.embracesdk.internal.ui.supportFrameCommitCallback
3232
import io.embrace.android.embracesdk.internal.utils.BuildVersionChecker
3333
import io.embrace.android.embracesdk.spans.ErrorCode
34-
import io.embrace.opentelemetry.kotlin.aliases.OtelJavaClock
3534
import org.junit.Assert.assertEquals
3635
import org.junit.Assert.assertNotNull
3736
import org.junit.Assert.assertNull
@@ -60,7 +59,6 @@ internal class AppStartupTraceEmitterTest {
6059
private var hasFrameCommitEvent = true
6160

6261
private lateinit var clock: FakeClock
63-
private lateinit var otelClock: OtelJavaClock
6462
private lateinit var spanSink: SpanSink
6563
private lateinit var spanService: SpanService
6664
private lateinit var logger: FakeEmbLogger
@@ -69,7 +67,6 @@ internal class AppStartupTraceEmitterTest {
6967
fun setUp() {
7068
clock = FakeClock(processInitTime)
7169
FakeInitModule(clock = clock).run {
72-
otelClock = openTelemetryModule.openTelemetryClock
7370
spanSink = openTelemetryModule.spanSink
7471
spanService = openTelemetryModule.spanService
7572
}
@@ -202,7 +199,7 @@ internal class AppStartupTraceEmitterTest {
202199
@Config(sdk = [VERSION_CODES.TIRAMISU])
203200
@Test
204201
fun `abandon cold start after before manual end`() {
205-
val emitter = createTraceEmitter(true).apply {
202+
val emitter = createTraceEmitter(manualEnd = true).apply {
206203
initApp(
207204
hasAppInitEvents = true,
208205
isColdStart = true
@@ -251,7 +248,7 @@ internal class AppStartupTraceEmitterTest {
251248
@Config(sdk = [VERSION_CODES.TIRAMISU])
252249
@Test
253250
fun `abandon warm start after before manual end`() {
254-
val emitter = createTraceEmitter(true).apply {
251+
val emitter = createTraceEmitter(manualEnd = true).apply {
255252
initApp(
256253
hasAppInitEvents = true,
257254
isColdStart = false
@@ -605,12 +602,18 @@ internal class AppStartupTraceEmitterTest {
605602

606603
private fun createTraceEmitter(manualEnd: Boolean = false) =
607604
AppStartupTraceEmitter(
608-
clock = otelClock,
605+
clock = clock,
609606
startupServiceProvider = { startupService },
610607
spanService = spanService,
611608
versionChecker = BuildVersionChecker,
612609
logger = logger,
613610
manualEnd = manualEnd,
611+
deviceStartTimestampMs = DEFAULT_FAKE_CURRENT_TIME - 10000000L,
612+
processCreatedMs = if (BuildVersionChecker.isAtLeast(VERSION_CODES.N)) {
613+
DEFAULT_FAKE_CURRENT_TIME
614+
} else {
615+
null
616+
}
614617
)
615618

616619
private fun AppStartupTraceEmitter.simulateAppStartup(
@@ -699,9 +702,7 @@ internal class AppStartupTraceEmitterTest {
699702
expectedCustomAttributes = mapOf("custom-attribute" to "true")
700703
)
701704

702-
if (isColdStart && hasAppInitEvents) {
703-
assertChildSpan(spanMap.processInitSpan(), traceStart, appInitTimestamps.applicationInitEnd)
704-
} else {
705+
if (!isColdStart) {
705706
assertNull(spanMap.processInitSpan())
706707
}
707708

@@ -847,7 +848,7 @@ internal class AppStartupTraceEmitterTest {
847848
}
848849

849850
private fun AppStartupTraceEmitter.fireEndEvent(
850-
activityInitTimestamps: ActivityInitTimestamps
851+
activityInitTimestamps: ActivityInitTimestamps,
851852
) {
852853
startupActivityInitEnd()
853854
activityInitTimestamps.startupActivityEnd = clock.now()

0 commit comments

Comments
 (0)