diff --git a/embrace-android-api/api/embrace-android-api.api b/embrace-android-api/api/embrace-android-api.api index 939f77ef84..a86b75522a 100644 --- a/embrace-android-api/api/embrace-android-api.api +++ b/embrace-android-api/api/embrace-android-api.api @@ -83,11 +83,11 @@ public abstract interface class io/embrace/android/embracesdk/internal/api/SdkAp public final class io/embrace/android/embracesdk/internal/api/SdkApi$DefaultImpls { public static fun createSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJ)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;)Z public static fun recordSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static fun recordSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static fun recordSpan (Lio/embrace/android/embracesdk/internal/api/SdkApi;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; @@ -289,12 +289,12 @@ public abstract interface class io/embrace/android/embracesdk/spans/TracingApi { public abstract fun createSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; public abstract fun createSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; public abstract fun getSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJ)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;)Z public abstract fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public abstract fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public abstract fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; @@ -308,17 +308,11 @@ public final class io/embrace/android/embracesdk/spans/TracingApi$DefaultImpls { public static fun createSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; public static synthetic fun createSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; public static synthetic fun createSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;ILjava/lang/Object;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJ)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public static fun recordCompletedSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;)Z public static fun recordSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static fun recordSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public static fun recordSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; diff --git a/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt b/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt index e136ca8d88..ae07541c3d 100644 --- a/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt +++ b/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt @@ -125,7 +125,6 @@ public interface TracingApi { name: String, startTimeMs: Long, endTimeMs: Long, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean = recordCompletedSpan( name = name, @@ -147,7 +146,6 @@ public interface TracingApi { startTimeMs: Long, endTimeMs: Long, errorCode: ErrorCode?, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean = recordCompletedSpan( name = name, @@ -168,7 +166,6 @@ public interface TracingApi { startTimeMs: Long, endTimeMs: Long, parent: EmbraceSpan?, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean = recordCompletedSpan( name = name, @@ -191,7 +188,6 @@ public interface TracingApi { endTimeMs: Long, errorCode: ErrorCode?, parent: EmbraceSpan?, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean = recordCompletedSpan( name = name, startTimeMs = startTimeMs, @@ -213,7 +209,6 @@ public interface TracingApi { endTimeMs: Long, attributes: Map?, events: List?, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean = recordCompletedSpan( name = name, startTimeMs = startTimeMs, @@ -239,7 +234,6 @@ public interface TracingApi { parent: EmbraceSpan?, attributes: Map?, events: List?, - autoTerminationMode: AutoTerminationMode = AutoTerminationMode.NONE, ): Boolean /** diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImpl.kt index 46ac6085d4..4779d74269 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImpl.kt @@ -2,11 +2,13 @@ package io.embrace.android.embracesdk.internal.envelope.session import io.embrace.android.embracesdk.internal.arch.schema.AppTerminationCause import io.embrace.android.embracesdk.internal.arch.schema.EmbType +import io.embrace.android.embracesdk.internal.clock.Clock import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.payload.SessionPayload import io.embrace.android.embracesdk.internal.payload.Span import io.embrace.android.embracesdk.internal.payload.toNewPayload import io.embrace.android.embracesdk.internal.session.captureDataSafely +import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService import io.embrace.android.embracesdk.internal.session.orchestrator.SessionSnapshotType import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData @@ -19,6 +21,8 @@ internal class SessionPayloadSourceImpl( private val currentSessionSpan: CurrentSessionSpan, private val spanRepository: SpanRepository, private val otelPayloadMapper: OtelPayloadMapper, + private val processStateService: ProcessStateService, + private val clock: Clock, private val logger: EmbLogger, ) : SessionPayloadSource { @@ -31,6 +35,10 @@ internal class SessionPayloadSourceImpl( val isCacheAttempt = endType == SessionSnapshotType.PERIODIC_CACHE val includeSnapshots = endType != SessionSnapshotType.JVM_CRASH + if (!endType.forceQuit && processStateService.isInBackground) { + spanRepository.autoTerminateSpans(clock.now()) + } + // Snapshots should only be included if the process is expected to last beyond the current session val snapshots: List? = if (includeSnapshots) { retrieveSpanSnapshots(isCacheAttempt) diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImpl.kt index d7b714772d..eeb648f83e 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/PayloadSourceModuleImpl.kt @@ -56,6 +56,8 @@ internal class PayloadSourceModuleImpl( otelModule.currentSessionSpan, otelModule.spanRepository, otelPayloadMapperProvider(), + essentialServiceModule.processStateService, + initModule.clock, initModule.logger ) } diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt index ba9c2c44c0..43b69eef46 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt @@ -67,7 +67,6 @@ class EmbraceTracer( parent: EmbraceSpan?, attributes: Map?, events: List?, - autoTerminationMode: AutoTerminationMode, ): Boolean = spanService.recordCompletedSpan( name = name, startTimeMs = startTimeMs.normalizeTimestampAsMillis(), @@ -77,7 +76,6 @@ class EmbraceTracer( private = false, attributes = attributes ?: emptyMap(), events = events ?: emptyList(), - autoTerminationMode = autoTerminationMode, errorCode = errorCode ) diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt index d63623fb02..7d2d89a6eb 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt @@ -2,6 +2,7 @@ package io.embrace.android.embracesdk.internal.spans import io.embrace.android.embracesdk.internal.arch.schema.EmbType import io.embrace.android.embracesdk.internal.utils.lockAndRun +import io.embrace.android.embracesdk.spans.AutoTerminationMode import io.embrace.android.embracesdk.spans.EmbraceSpan import io.embrace.android.embracesdk.spans.ErrorCode import java.util.concurrent.ConcurrentHashMap @@ -100,5 +101,23 @@ class SpanRepository { spanUpdateNotifier?.invoke() } + /** + * Automatically terminates root spans + */ + fun autoTerminateSpans(now: Long) { // TODO: move out of collection + // TODO: pass consistent endTimeMs + activeSpans.forEach { entry -> + val span = entry.value + if (span.parent == null && entry.value.autoTerminationMode == AutoTerminationMode.ON_BACKGROUND) { + span.stop(endTimeMs = now) + +// span.pare + // TODO: obtain the span children + + entry.value + } + } + } + private fun notTracked(spanId: String): Boolean = activeSpans[spanId] == null && completedSpans[spanId] == null } diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImplTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImplTest.kt index 93cdb03c30..762f105390 100644 --- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImplTest.kt +++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/envelope/session/SessionPayloadSourceImplTest.kt @@ -1,7 +1,9 @@ package io.embrace.android.embracesdk.internal.envelope.session +import io.embrace.android.embracesdk.fakes.FakeClock import io.embrace.android.embracesdk.fakes.FakeCurrentSessionSpan import io.embrace.android.embracesdk.fakes.FakePersistableEmbraceSpan +import io.embrace.android.embracesdk.fakes.FakeProcessStateService import io.embrace.android.embracesdk.fakes.FakeSpanData import io.embrace.android.embracesdk.internal.arch.schema.EmbType import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl @@ -49,6 +51,8 @@ internal class SessionPayloadSourceImplTest { crashId: String?, ): List = emptyList() }, + FakeProcessStateService(), + FakeClock(), EmbLoggerImpl() ) } diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt index 39568539ab..12be35b2f9 100644 --- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt +++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/PayloadFactoryBaTest.kt @@ -130,6 +130,8 @@ internal class PayloadFactoryBaTest { currentSessionSpan, spanRepository, FakeOtelPayloadMapper(), + FakeProcessStateService(), + FakeClock(), logger ) ) diff --git a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionHandlerTest.kt b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionHandlerTest.kt index 4aa7214a3d..a89592b294 100644 --- a/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionHandlerTest.kt +++ b/embrace-android-core/src/test/java/io/embrace/android/embracesdk/internal/session/SessionHandlerTest.kt @@ -12,6 +12,7 @@ import io.embrace.android.embracesdk.fakes.FakeMemoryCleanerService import io.embrace.android.embracesdk.fakes.FakeMetadataService import io.embrace.android.embracesdk.fakes.FakeOtelPayloadMapper import io.embrace.android.embracesdk.fakes.FakePreferenceService +import io.embrace.android.embracesdk.fakes.FakeProcessStateService import io.embrace.android.embracesdk.fakes.FakeSessionIdTracker import io.embrace.android.embracesdk.fakes.FakeSessionPropertiesService import io.embrace.android.embracesdk.fakes.FakeUserService @@ -97,6 +98,8 @@ internal class SessionHandlerTest { currentSessionSpan, spanRepository, FakeOtelPayloadMapper(), + FakeProcessStateService(), + FakeClock(), logger ) val payloadSourceModule = FakePayloadSourceModule( diff --git a/embrace-android-sdk/api/embrace-android-sdk.api b/embrace-android-sdk/api/embrace-android-sdk.api index 053c27918b..4a30b9b471 100644 --- a/embrace-android-sdk/api/embrace-android-sdk.api +++ b/embrace-android-sdk/api/embrace-android-sdk.api @@ -38,12 +38,12 @@ public final class io/embrace/android/embracesdk/Embrace : io/embrace/android/em public fun logPushNotification (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/Boolean;Ljava/lang/Boolean;)V public fun logWarning (Ljava/lang/String;)V public fun logWebView (Ljava/lang/String;)V - public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z - public fun recordCompletedSpan (Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;)Z + public fun recordCompletedSpan (Ljava/lang/String;JJ)Z + public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;)Z + public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Z + public fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/util/Map;Ljava/util/List;)Z + public fun recordCompletedSpan (Ljava/lang/String;JJLjava/util/Map;Ljava/util/List;)Z public fun recordNetworkRequest (Lio/embrace/android/embracesdk/network/EmbraceNetworkRequest;)V public fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; public fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lio/embrace/android/embracesdk/spans/AutoTerminationMode;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SpanAutoTerminationTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SpanAutoTerminationTest.kt new file mode 100644 index 0000000000..9049bbf508 --- /dev/null +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/features/SpanAutoTerminationTest.kt @@ -0,0 +1,131 @@ +package io.embrace.android.embracesdk.testcases.features + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.embrace.android.embracesdk.assertions.findSpanByName +import io.embrace.android.embracesdk.internal.payload.Envelope +import io.embrace.android.embracesdk.internal.payload.SessionPayload +import io.embrace.android.embracesdk.spans.AutoTerminationMode +import io.embrace.android.embracesdk.spans.EmbraceSpan +import io.embrace.android.embracesdk.testframework.IntegrationTestRule +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +internal class SpanAutoTerminationTest { + + private companion object { + private const val ROOT_HANGING_SPAN = "root_a" + private const val ROOT_START_SPAN = "root_b" + private const val CHILD_START_SPAN_A = "child_a" + private const val CHILD_START_SPAN_B = "child_b" + private const val CHILD_START_SPAN_C = "child_c" + private const val ROOT_CREATE_SPAN = "root_c" + private const val ROOT_RECORD_SPAN = "root_d" + private const val ROOT_RECORD_COMPLETED_SPAN = "root_e" + private const val ROOT_STOPPED_SPAN = "root_f" + } + + @Rule + @JvmField + val testRule: IntegrationTestRule = IntegrationTestRule() + + @Test + fun `auto termination feature`() { + testRule.runTest( + testCaseAction = { + var hangingSpan: EmbraceSpan? = null + recordSession { + // start a span without auto termination + hangingSpan = embrace.startSpan(ROOT_HANGING_SPAN, autoTerminationMode = AutoTerminationMode.NONE) + + // start a span with children and auto termination + val parent = embrace.startSpan(ROOT_START_SPAN, autoTerminationMode = AutoTerminationMode.ON_BACKGROUND) + embrace.startSpan( + CHILD_START_SPAN_A, + parent = parent, + autoTerminationMode = AutoTerminationMode.ON_BACKGROUND + ) + val childB = embrace.startSpan(CHILD_START_SPAN_B, parent = parent) + embrace.startSpan(CHILD_START_SPAN_C, parent = childB) + + // create a span with auto termination + embrace.createSpan(ROOT_CREATE_SPAN, autoTerminationMode = AutoTerminationMode.ON_BACKGROUND)?.start() + + // record a span + embrace.recordSpan(ROOT_RECORD_SPAN) { + embrace.addBreadcrumb("Hello, world!") + } + + // record a completed span + embrace.recordCompletedSpan(ROOT_RECORD_COMPLETED_SPAN, clock.now() - 1000, clock.now()) + + // stop a span with auto termination + embrace.createSpan(ROOT_STOPPED_SPAN, autoTerminationMode = AutoTerminationMode.ON_BACKGROUND)?.apply { + start() + stop() + } + } + + recordSession { + // stop a span without auto termination + hangingSpan?.stop() + } + }, + assertAction = { + val message = getSessionEnvelopes(2) + assertFirstSpans(message[0]) + assertSecondSpans(message[1]) + } + ) + } + + private fun assertFirstSpans(first: Envelope) { + val expectedEnd = 0 + + // startSpan() with children + val rootb = first.findSpanByName(ROOT_START_SPAN) + assertEquals(expectedEnd, rootb.endTimeNanos) + + val childa = first.findSpanByName(CHILD_START_SPAN_A) + assertEquals(expectedEnd, childa.endTimeNanos) + + val childb = first.findSpanByName(CHILD_START_SPAN_B) + assertEquals(expectedEnd, childb.endTimeNanos) + + val childc = first.findSpanByName(CHILD_START_SPAN_C) + assertEquals(expectedEnd, childc.endTimeNanos) + + // createSpan() + val rootc = first.findSpanByName(ROOT_CREATE_SPAN) + assertEquals(expectedEnd, rootc.endTimeNanos) + + // recordSpan() + val rootd = first.findSpanByName(ROOT_RECORD_SPAN) + assertEquals(expectedEnd, rootd.endTimeNanos) + + // recordCompletedSpan() + val roote = first.findSpanByName(ROOT_RECORD_COMPLETED_SPAN) + assertEquals(expectedEnd, roote.endTimeNanos) + + // stopped span + val rootf = first.findSpanByName(ROOT_STOPPED_SPAN) + assertEquals(expectedEnd, rootf.endTimeNanos) + + // non-terminated span + val hangingSpan = checkNotNull(first.data.spanSnapshots?.single { it.name == ROOT_HANGING_SPAN }) + assertNull(hangingSpan.endTimeNanos) + + // TODO: add assertions + } + + private fun assertSecondSpans(second: Envelope) { + val spans = second.data.spans + val snapshots = second.data.spanSnapshots + spans.toString() + snapshots.toString() + TODO("Not yet implemented") + } +} diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/Embrace.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/Embrace.kt index 9ee672bdf2..590a13c881 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/Embrace.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/Embrace.kt @@ -214,7 +214,7 @@ public class Embrace private constructor( name: String, autoTerminationMode: AutoTerminationMode, ): EmbraceSpan? { - return impl.createSpan(name) + return impl.createSpan(name, autoTerminationMode) } override fun createSpan( @@ -222,14 +222,14 @@ public class Embrace private constructor( parent: EmbraceSpan?, autoTerminationMode: AutoTerminationMode, ): EmbraceSpan? { - return impl.createSpan(name, parent) + return impl.createSpan(name, parent, autoTerminationMode) } override fun startSpan( name: String, autoTerminationMode: AutoTerminationMode, ): EmbraceSpan? { - return impl.startSpan(name) + return impl.startSpan(name, autoTerminationMode) } override fun startSpan( @@ -237,7 +237,7 @@ public class Embrace private constructor( parent: EmbraceSpan?, autoTerminationMode: AutoTerminationMode, ): EmbraceSpan? { - return impl.startSpan(name, parent) + return impl.startSpan(name, parent, autoTerminationMode) } override fun startSpan( @@ -246,7 +246,7 @@ public class Embrace private constructor( startTimeMs: Long?, autoTerminationMode: AutoTerminationMode, ): EmbraceSpan? { - return impl.startSpan(name, parent, startTimeMs) + return impl.startSpan(name, parent, startTimeMs, autoTerminationMode) } override fun recordSpan( @@ -295,7 +295,6 @@ public class Embrace private constructor( parent: EmbraceSpan?, attributes: Map?, events: List?, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan( name, @@ -312,7 +311,6 @@ public class Embrace private constructor( name: String, startTimeMs: Long, endTimeMs: Long, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan(name, startTimeMs, endTimeMs) } @@ -322,7 +320,6 @@ public class Embrace private constructor( startTimeMs: Long, endTimeMs: Long, errorCode: ErrorCode?, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan(name, startTimeMs, endTimeMs, errorCode) } @@ -332,7 +329,6 @@ public class Embrace private constructor( startTimeMs: Long, endTimeMs: Long, parent: EmbraceSpan?, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan(name, startTimeMs, endTimeMs, parent) } @@ -343,7 +339,6 @@ public class Embrace private constructor( endTimeMs: Long, errorCode: ErrorCode?, parent: EmbraceSpan?, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan(name, startTimeMs, endTimeMs, errorCode, parent) } @@ -354,7 +349,6 @@ public class Embrace private constructor( endTimeMs: Long, attributes: Map?, events: List?, - autoTerminationMode: AutoTerminationMode, ): Boolean { return impl.recordCompletedSpan(name, startTimeMs, endTimeMs, attributes, events) }