From 2f37751e1bf3562c128d9a27b0e1973d9adaf604 Mon Sep 17 00:00:00 2001 From: Jamie Lynch Date: Fri, 26 Jul 2024 11:15:07 +0100 Subject: [PATCH 1/3] refactor: move init module to core --- .../embracesdk/internal/IdGenerator.kt | 12 ++++---- .../android/embracesdk/internal/SystemInfo.kt | 20 ++++++++++++- .../internal/clock/NormalizedIntervalClock.kt | 2 +- .../embracesdk/internal/clock/SystemClock.kt | 2 +- .../internal/injection/InitModule.kt | 23 ++++++--------- .../internal/injection/InitModuleImpl.kt | 9 ++---- .../internal/logging/EmbLoggerImpl.kt | 2 +- .../embracesdk/internal/spans/EmbraceExt.kt | 18 ++++++++++++ .../telemetry/EmbraceTelemetryService.kt | 6 ++-- .../telemetry/OkHttpReflectionFacade.kt | 0 .../internal/telemetry/TelemetryService.kt | 8 +++--- .../errors/EmbraceInternalErrorService.kt | 0 .../errors/InternalErrorDataSource.kt | 2 +- .../errors/InternalErrorDataSourceImpl.kt | 2 +- .../telemetry/errors/InternalErrorService.kt | 4 +-- .../serialization/AppFrameworkAdapter.kt | 6 ++-- .../serialization/EmbraceSerializer.kt | 15 ++++------ .../serialization/PlatformSerializer.kt | 27 ++++++++++++++++++ .../internal/anr/ndk/NativeAnrOtelMapper.kt | 4 +-- .../capture/crash/CrashDataSourceImpl.kt | 4 +-- .../capture/envelope/resource/Device.kt | 22 ++------------- .../capture/webview/EmbraceWebViewService.kt | 4 +-- .../capture/webview/WebViewDataSource.kt | 4 +-- .../internal/comms/api/ApiRequest.kt | 6 ++-- .../internal/comms/api/ApiRequestMapper.kt | 11 +++----- .../internal/comms/api/ApiRequestUrl.kt | 11 ++++++++ .../internal/comms/api/ApiResponseCache.kt | 4 +-- .../internal/comms/api/EmbraceApiService.kt | 9 +++--- .../delivery/EmbracePendingApiCallsSender.kt | 4 ++- .../comms/delivery/PendingApiCalls.kt | 4 ++- .../internal/config/LocalConfigParser.kt | 6 ++-- .../injection/AndroidServicesModuleImpl.kt | 2 +- .../injection/DataCaptureServiceModuleImpl.kt | 2 +- .../internal/injection/OpenTelemetryModule.kt | 5 ++++ .../injection/OpenTelemetryModuleImpl.kt | 14 ++++++---- .../internal/logs/EmbraceLogService.kt | 4 +-- .../internal/ndk/EmbraceNdkService.kt | 10 +++---- .../internal/ndk/NativeCrashDataSource.kt | 4 +-- .../logging/EmbraceNetworkCaptureService.kt | 4 +-- .../prefs/EmbracePreferencesService.kt | 4 +-- .../serialization/EmbraceUrlAdapter.kt | 28 ------------------- .../serialization/PlatformSerializer.kt | 28 ------------------- .../internal/spans/EmbraceExtensions.kt | 17 ----------- .../embracesdk/EmbraceCacheServiceTest.kt | 8 +++--- .../EmbraceDeliveryCacheManagerTest.kt | 18 ++++++------ .../startup/AppStartupTraceEmitterTest.kt | 2 +- .../embracesdk/comms/api/ApiClientImplTest.kt | 17 ++++------- .../comms/api/ApiRequestMapperTest.kt | 4 +-- .../embracesdk/comms/api/ApiRequestTest.kt | 8 +++--- .../comms/api/EmbraceApiServiceTest.kt | 6 ++-- .../EmbracePendingApiCallsSenderTest.kt | 9 +++--- .../comms/delivery/PendingApiCallsTest.kt | 18 ++++++------ .../fakes/FakeOpenTelemetryModule.kt | 3 ++ .../fakes/injection/FakeInitModule.kt | 7 +---- .../injection/InitModuleImplTest.kt | 6 +--- .../serialization/EmbraceUrlAdapterTest.kt | 18 ------------ .../spans/EmbraceSpanFactoryImplTest.kt | 2 +- .../internal/spans/EmbraceSpanImplTest.kt | 2 +- .../internal/spans/SpanServiceImplTest.kt | 2 +- .../embracesdk/opentelemetry/EmbSpanTest.kt | 2 +- 60 files changed, 229 insertions(+), 276 deletions(-) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/IdGenerator.kt (72%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/SystemInfo.kt (69%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt (88%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/clock/SystemClock.kt (78%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/injection/InitModule.kt (70%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt (84%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt (98%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt (92%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/OkHttpReflectionFacade.kt (100%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt (73%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/errors/EmbraceInternalErrorService.kt (100%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt (72%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt (96%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt (72%) rename {embrace-android-sdk/src/main/java => embrace-android-payload/src/main/kotlin}/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt (54%) rename {embrace-android-sdk/src/main/java => embrace-android-payload/src/main/kotlin}/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt (84%) create mode 100644 embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt create mode 100644 embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestUrl.kt delete mode 100644 embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapter.kt delete mode 100644 embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt delete mode 100644 embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapterTest.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/IdGenerator.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/IdGenerator.kt similarity index 72% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/IdGenerator.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/IdGenerator.kt index 4d71d10b51..a7499f4bfe 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/IdGenerator.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/IdGenerator.kt @@ -4,7 +4,7 @@ import io.opentelemetry.api.trace.SpanId import io.opentelemetry.api.trace.TraceId import kotlin.random.Random -internal class IdGenerator( +public class IdGenerator( private val random: Random = Random.Default ) { /** @@ -12,10 +12,10 @@ internal class IdGenerator( * * Note: because Embrace may be recording a span on our side for the given traceparent, we have set the "sampled" flag to indicate that. */ - fun generateTraceparent(): String = + public fun generateTraceparent(): String = "00-" + TraceId.fromLongs(validRandomLong(), validRandomLong()) + "-" + SpanId.fromLong(validRandomLong()) + "-01" - fun generateUUID(): String = SpanId.fromLong(validRandomLong()) + public fun generateUUID(): String = SpanId.fromLong(validRandomLong()) private fun validRandomLong(): Long { var value: Long @@ -25,12 +25,12 @@ internal class IdGenerator( return value } - companion object { + public companion object { private val INSTANCE = IdGenerator() @JvmStatic - fun generateW3CTraceparent() = INSTANCE.generateTraceparent() + public fun generateW3CTraceparent(): String = INSTANCE.generateTraceparent() - fun generateLaunchInstanceId() = INSTANCE.generateUUID() + public fun generateLaunchInstanceId(): String = INSTANCE.generateUUID() } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/SystemInfo.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/SystemInfo.kt similarity index 69% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/SystemInfo.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/SystemInfo.kt index 4010ed942b..1467fec5a6 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/SystemInfo.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/SystemInfo.kt @@ -5,7 +5,7 @@ import android.os.Build /** * Information about the the device or OS that can be retrieved without disk or platform API access */ -internal data class SystemInfo( +public data class SystemInfo( /** * Name of the operating system of the device. To use the Android SDK, this has to be Android, so this is always "android" */ @@ -81,3 +81,21 @@ internal fun getDeviceModel(): String { "" } } + +/** + * Tries to determine whether the device is an emulator by looking for known models and + * manufacturers which correspond to emulators. + * + * @return true if the device is detected to be an emulator, false otherwise + */ +public fun SystemInfo.isEmulator(): Boolean = + Build.FINGERPRINT.startsWith("generic") || + Build.FINGERPRINT.startsWith("unknown") || + Build.FINGERPRINT.contains("emulator") || + deviceModel.contains("google_sdk") || + deviceModel.contains("sdk_gphone64") || + deviceModel.contains("Emulator") || + deviceModel.contains("Android SDK built for") || + deviceManufacturer.contains("Genymotion") || + Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic") || + Build.PRODUCT.equals("google_sdk") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt similarity index 88% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt index 711ba1671f..df8ec40dac 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/NormalizedIntervalClock.kt @@ -7,7 +7,7 @@ package io.embrace.android.embracesdk.internal.clock * This is useful when it is necessary to perform interval timing but the results must be * sent to the API in a way that matches the device time. */ -internal class NormalizedIntervalClock(systemClock: SystemClock) : Clock { +public class NormalizedIntervalClock(systemClock: SystemClock) : Clock { private val baseline: Long init { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/SystemClock.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/SystemClock.kt similarity index 78% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/SystemClock.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/SystemClock.kt index 036d78a606..1d5b026e3d 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/clock/SystemClock.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/clock/SystemClock.kt @@ -1,6 +1,6 @@ package io.embrace.android.embracesdk.internal.clock -internal class SystemClock : Clock { +public class SystemClock : Clock { override fun now(): Long { return System.currentTimeMillis() } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt similarity index 70% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModule.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt index f765caa8a5..28f3b121d8 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModule.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModule.kt @@ -2,53 +2,48 @@ package io.embrace.android.embracesdk.internal.injection import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.logging.EmbLogger -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.telemetry.TelemetryService import io.embrace.android.embracesdk.internal.telemetry.errors.InternalErrorService /** * A module of components and services required at [EmbraceImpl] instantiation time, i.e. before the SDK evens starts */ -internal interface InitModule { +public interface InitModule { /** * Clock instance locked to the time of creation used by the SDK throughout its lifetime */ - val clock: io.embrace.android.embracesdk.internal.clock.Clock - - /** - * OpenTelemetry SDK compatible clock based on [clock] - */ - val openTelemetryClock: io.opentelemetry.sdk.common.Clock + public val clock: io.embrace.android.embracesdk.internal.clock.Clock /** * Service to track usage of public APIs and other internal metrics */ - val telemetryService: TelemetryService + public val telemetryService: TelemetryService /** * Logger used by the SDK */ - val logger: EmbLogger + public val logger: EmbLogger /** * Info about the system available at startup time without expensive disk or API calls */ - val systemInfo: SystemInfo + public val systemInfo: SystemInfo /** * Unique ID generated for an instance of the app process and not related to the actual process ID assigned by the OS. * This allows us to explicitly relate all the sessions associated with a particular app launch rather than having the backend figure * this out by proximity for stitched sessions. */ - val processIdentifier: String + public val processIdentifier: String /** * Tracks internal errors */ - val internalErrorService: InternalErrorService + public val internalErrorService: InternalErrorService /** * Returns the serializer used to serialize data to JSON */ - val jsonSerializer: EmbraceSerializer + public val jsonSerializer: PlatformSerializer } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt similarity index 84% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt index 98f1c5282a..5e6377c3cd 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/InitModuleImpl.kt @@ -1,24 +1,21 @@ package io.embrace.android.embracesdk.internal.injection import io.embrace.android.embracesdk.internal.IdGenerator -import io.embrace.android.embracesdk.internal.OpenTelemetryClock import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock import io.embrace.android.embracesdk.internal.clock.SystemClock import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.telemetry.EmbraceTelemetryService import io.embrace.android.embracesdk.internal.telemetry.TelemetryService import io.embrace.android.embracesdk.internal.telemetry.errors.EmbraceInternalErrorService import io.embrace.android.embracesdk.internal.telemetry.errors.InternalErrorService -internal class InitModuleImpl( +public class InitModuleImpl( override val clock: io.embrace.android.embracesdk.internal.clock.Clock = NormalizedIntervalClock(systemClock = SystemClock()), - override val openTelemetryClock: io.opentelemetry.sdk.common.Clock = OpenTelemetryClock( - embraceClock = clock - ), override val logger: EmbLogger = EmbLoggerImpl(), override val systemInfo: SystemInfo = SystemInfo() ) : InitModule { @@ -37,7 +34,7 @@ internal class InitModuleImpl( override val processIdentifier: String = IdGenerator.generateLaunchInstanceId() - override val jsonSerializer: EmbraceSerializer by singleton { + override val jsonSerializer: PlatformSerializer by singleton { EmbraceSerializer() } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt similarity index 98% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt index 6857bbfc4a..8828abab90 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logging/EmbLoggerImpl.kt @@ -8,7 +8,7 @@ internal const val EMBRACE_TAG = "[Embrace]" * Implementation of [EmbLogger] that logs to Android logcat & also allows tracking of internal * errors for our telemetry. */ -internal class EmbLoggerImpl : EmbLogger { +public class EmbLoggerImpl : EmbLogger { override var internalErrorService: InternalErrorHandler? = null diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt index 0e49127e21..aafc02aeeb 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt @@ -1,11 +1,29 @@ package io.embrace.android.embracesdk.internal.spans +import io.opentelemetry.api.logs.Severity + /** * Prefix added to OTel signal object names recorded by the SDK */ private const val EMBRACE_OBJECT_NAME_PREFIX = "emb-" +/** + * Prefix added to all attribute keys for all usage attributes added by the SDK + */ +private const val EMBRACE_USAGE_ATTRIBUTE_NAME_PREFIX = "emb.usage." + /** * Return the appropriate name used for telemetry created by Embrace given the current value */ public fun String.toEmbraceObjectName(): String = EMBRACE_OBJECT_NAME_PREFIX + this + +public fun io.embrace.android.embracesdk.Severity.toOtelSeverity(): Severity = when (this) { + io.embrace.android.embracesdk.Severity.INFO -> Severity.INFO + io.embrace.android.embracesdk.Severity.WARNING -> Severity.WARN + io.embrace.android.embracesdk.Severity.ERROR -> Severity.ERROR +} + +/** + * Return the appropriate internal Embrace attribute usage name given the current string + */ +internal fun String.toEmbraceUsageAttributeName(): String = EMBRACE_USAGE_ATTRIBUTE_NAME_PREFIX + this diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt similarity index 92% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt index c4d9cde699..024315b1c9 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/EmbraceTelemetryService.kt @@ -2,14 +2,14 @@ package io.embrace.android.embracesdk.internal.telemetry import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.arch.schema.toEmbraceAttributeName -import io.embrace.android.embracesdk.internal.capture.envelope.resource.isEmulator +import io.embrace.android.embracesdk.internal.isEmulator import io.embrace.android.embracesdk.internal.spans.toEmbraceUsageAttributeName import java.util.concurrent.ConcurrentHashMap /** * Service for tracking usage of public APIs, and different internal metrics about the app. */ -internal class EmbraceTelemetryService( +public class EmbraceTelemetryService( private val systemInfo: SystemInfo ) : TelemetryService { @@ -67,7 +67,7 @@ internal class EmbraceTelemetryService( runCatching { KotlinVersion.CURRENT.toString() }.getOrDefault("unknown") appAttributesMap["is_emulator".toEmbraceAttributeName()] = - runCatching { isEmulator(systemInfo).toString() }.getOrDefault("unknown") + runCatching { systemInfo.isEmulator().toString() }.getOrDefault("unknown") return appAttributesMap } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/OkHttpReflectionFacade.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/OkHttpReflectionFacade.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/OkHttpReflectionFacade.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/OkHttpReflectionFacade.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt similarity index 73% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt index 856fc8d053..c911bab809 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/TelemetryService.kt @@ -1,22 +1,22 @@ package io.embrace.android.embracesdk.internal.telemetry -internal interface TelemetryService { +public interface TelemetryService { /** * Tracks the usage of a public API by name. We only track public APIs that are called when the SDK is initialized. * Name should be snake_case, e.g. "start_session". */ - fun onPublicApiCalled(name: String) + public fun onPublicApiCalled(name: String) /** * Tracks the storage being used, in bytes. storageTelemetry is a map of storage telemetry names and their values in bytes, * such as: emb.storage.usage -> "1234" */ - fun logStorageTelemetry(storageTelemetry: Map) + public fun logStorageTelemetry(storageTelemetry: Map) /** * Returns a map with every telemetry value. This is called when the session ends. * We clear the usage count map so we don't count the same usages in the next session. */ - fun getAndClearTelemetryAttributes(): Map + public fun getAndClearTelemetryAttributes(): Map } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/EmbraceInternalErrorService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/EmbraceInternalErrorService.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/EmbraceInternalErrorService.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/EmbraceInternalErrorService.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt similarity index 72% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt index 25e0b0dccf..52b67000a9 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSource.kt @@ -3,4 +3,4 @@ package io.embrace.android.embracesdk.internal.telemetry.errors import io.embrace.android.embracesdk.internal.arch.datasource.LogDataSource import io.embrace.android.embracesdk.internal.logging.InternalErrorHandler -internal interface InternalErrorDataSource : LogDataSource, InternalErrorHandler +public interface InternalErrorDataSource : LogDataSource, InternalErrorHandler diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt similarity index 96% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt index 68b5e40b93..56225beed1 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorDataSourceImpl.kt @@ -12,7 +12,7 @@ import io.embrace.android.embracesdk.internal.spans.toOtelSeverity /** * Tracks internal errors & sends them as OTel logs. */ -internal class InternalErrorDataSourceImpl( +public class InternalErrorDataSourceImpl( logWriter: LogWriter, logger: EmbLogger, ) : InternalErrorDataSource, diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt similarity index 72% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt index 52a0069a2b..0308dabb0b 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/telemetry/errors/InternalErrorService.kt @@ -7,6 +7,6 @@ import io.embrace.android.embracesdk.internal.utils.Provider * Reports an internal error to Embrace. An internal error is defined as an exception that was * caught within Embrace code & logged to [EmbLogger]. */ -internal interface InternalErrorService : InternalErrorHandler { - var internalErrorDataSource: Provider +public interface InternalErrorService : InternalErrorHandler { + public var internalErrorDataSource: Provider } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt similarity index 54% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt index 060279fb3c..a194e6c2ca 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/AppFrameworkAdapter.kt @@ -4,10 +4,10 @@ import com.squareup.moshi.FromJson import com.squareup.moshi.ToJson import io.embrace.android.embracesdk.internal.payload.AppFramework -internal class AppFrameworkAdapter { +public class AppFrameworkAdapter { @ToJson - fun toJson(appFramework: AppFramework) = appFramework.value + public fun toJson(appFramework: AppFramework): Int = appFramework.value @FromJson - fun fromJson(value: Int) = AppFramework.fromInt(value) + public fun fromJson(value: Int): AppFramework? = AppFramework.fromInt(value) } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt similarity index 84% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt index 26eda2cb48..cad01dbef7 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/EmbraceSerializer.kt @@ -1,7 +1,6 @@ package io.embrace.android.embracesdk.internal.serialization import com.squareup.moshi.Moshi -import io.embrace.android.embracesdk.internal.utils.threadLocal import okio.buffer import okio.sink import okio.source @@ -12,15 +11,16 @@ import java.lang.reflect.Type /** * A wrapper around the JSON library to allow for thread-safe serialization. */ -internal class EmbraceSerializer : PlatformSerializer { +public class EmbraceSerializer : PlatformSerializer { - private val impl by threadLocal { - Moshi.Builder() - .add(EmbraceUrlAdapter()) + private val ref = object : ThreadLocal() { + override fun initialValue(): Moshi = Moshi.Builder() .add(AppFrameworkAdapter()) .build() } + private val impl by lazy { checkNotNull(ref.get()) } + override fun toJson(src: T): String { val clz = checkNotNull(src)::class.java val adapter = impl.adapter(clz) @@ -74,9 +74,4 @@ internal class EmbraceSerializer : PlatformSerializer { adapter.fromJson(it) ?: error("JSON conversion failed.") } } - - inline fun fromJsonWithTypeToken(json: String): T { - val adapter = impl.adapter(T::class.java) - return adapter.fromJson(json) ?: error("JSON conversion failed.") - } } diff --git a/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt new file mode 100644 index 0000000000..bcf7aadd5f --- /dev/null +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt @@ -0,0 +1,27 @@ +package io.embrace.android.embracesdk.internal.serialization + +import java.io.InputStream +import java.io.OutputStream +import java.lang.reflect.Type + +/** + * Interface for JSON serializer wrapper than can then be wrapped for testing purposes + */ +public interface PlatformSerializer { + public fun toJson(src: T): String + public fun toJson(src: T, clz: Class): String + public fun toJson(src: T, type: Type): String + public fun toJson(any: T, clazz: Class, outputStream: OutputStream) + public fun toJson(any: T, type: Type, outputStream: OutputStream) + public fun fromJson(json: String, clz: Class): T + public fun fromJson(json: String, type: Type): T + public fun fromJson(inputStream: InputStream, clz: Class): T + public fun fromJson(inputStream: InputStream, type: Type): T +} + +/** + * Return the first 200 elements of [elements] as a JSON-encoded string + */ +public fun PlatformSerializer.truncatedStacktrace( + elements: Array +): String = toJson(elements.take(200).map(StackTraceElement::toString).toList(), List::class.java) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/anr/ndk/NativeAnrOtelMapper.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/anr/ndk/NativeAnrOtelMapper.kt index 3deb6d534f..0ea67299f2 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/anr/ndk/NativeAnrOtelMapper.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/anr/ndk/NativeAnrOtelMapper.kt @@ -11,7 +11,7 @@ import io.embrace.android.embracesdk.internal.payload.NativeThreadAnrInterval import io.embrace.android.embracesdk.internal.payload.NativeThreadAnrSample import io.embrace.android.embracesdk.internal.payload.Span import io.embrace.android.embracesdk.internal.payload.SpanEvent -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.opentelemetry.api.trace.SpanId import io.opentelemetry.sdk.trace.IdGenerator import io.opentelemetry.semconv.ExceptionAttributes @@ -20,7 +20,7 @@ import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes internal class NativeAnrOtelMapper( private val nativeThreadSamplerService: NativeThreadSamplerService?, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val clock: Clock ) : DataCaptureServiceOtelConverter { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/crash/CrashDataSourceImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/crash/CrashDataSourceImpl.kt index 64e616346a..ba904a0703 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/crash/CrashDataSourceImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/crash/CrashDataSourceImpl.kt @@ -20,7 +20,7 @@ import io.embrace.android.embracesdk.internal.payload.JsException import io.embrace.android.embracesdk.internal.payload.LegacyExceptionInfo import io.embrace.android.embracesdk.internal.payload.ThreadInfo import io.embrace.android.embracesdk.internal.prefs.PreferencesService -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.orchestrator.SessionOrchestrator import io.embrace.android.embracesdk.internal.session.properties.EmbraceSessionProperties import io.embrace.android.embracesdk.internal.spans.toOtelSeverity @@ -42,7 +42,7 @@ internal class CrashDataSourceImpl( private val crashMarker: CrashFileMarker, private val logWriter: LogWriter, private val configService: ConfigService, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val logger: EmbLogger, ) : CrashDataSource, LogDataSourceImpl( diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/envelope/resource/Device.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/envelope/resource/Device.kt index 853cb26f0b..ae985bdc6f 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/envelope/resource/Device.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/envelope/resource/Device.kt @@ -1,12 +1,12 @@ package io.embrace.android.embracesdk.internal.capture.envelope.resource -import android.os.Build import android.os.Environment import android.os.StatFs import android.util.DisplayMetrics import android.view.WindowManager import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.capture.cpu.CpuInfoDelegate +import io.embrace.android.embracesdk.internal.isEmulator import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.logging.InternalErrorType import io.embrace.android.embracesdk.internal.prefs.PreferencesService @@ -153,7 +153,7 @@ internal class DeviceImpl( * @return true if the device is jailbroken and not an emulator, false otherwise */ private fun checkIfIsJailbroken(): Boolean { - if (isEmulator(systemInfo)) { + if (systemInfo.isEmulator()) { return false } for (location in jailbreakLocations) { @@ -183,21 +183,3 @@ internal class DeviceImpl( override val eglInfo: String? = cpuInfoDelegate.getEgl() } - -/** - * Tries to determine whether the device is an emulator by looking for known models and - * manufacturers which correspond to emulators. - * - * @return true if the device is detected to be an emulator, false otherwise - */ -internal fun isEmulator(systemInfo: SystemInfo): Boolean = - Build.FINGERPRINT.startsWith("generic") || - Build.FINGERPRINT.startsWith("unknown") || - Build.FINGERPRINT.contains("emulator") || - systemInfo.deviceModel.contains("google_sdk") || - systemInfo.deviceModel.contains("sdk_gphone64") || - systemInfo.deviceModel.contains("Emulator") || - systemInfo.deviceModel.contains("Android SDK built for") || - systemInfo.deviceManufacturer.contains("Genymotion") || - Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic") || - Build.PRODUCT.equals("google_sdk") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/EmbraceWebViewService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/EmbraceWebViewService.kt index 352eb8c978..86f8a50cc6 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/EmbraceWebViewService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/EmbraceWebViewService.kt @@ -6,14 +6,14 @@ import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.logging.InternalErrorType import io.embrace.android.embracesdk.internal.payload.WebViewInfo import io.embrace.android.embracesdk.internal.payload.WebVitalType -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.MemoryCleanerListener import io.embrace.android.embracesdk.internal.utils.Provider import java.util.EnumMap internal class EmbraceWebViewService( val configService: ConfigService, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val logger: EmbLogger, private val dataSourceModuleProvider: Provider, ) : WebViewService, MemoryCleanerListener { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/WebViewDataSource.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/WebViewDataSource.kt index 44617ed428..b01acf7d3d 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/WebViewDataSource.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/capture/webview/WebViewDataSource.kt @@ -9,7 +9,7 @@ import io.embrace.android.embracesdk.internal.arch.schema.SchemaType import io.embrace.android.embracesdk.internal.config.behavior.WebViewVitalsBehavior import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.payload.WebViewInfo -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.utils.toUTF8String /** @@ -19,7 +19,7 @@ internal class WebViewDataSource( private val webViewVitalsBehavior: WebViewVitalsBehavior, private val writer: SessionSpanWriter, private val logger: EmbLogger, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, ) : DataSourceImpl( destination = writer, logger = logger, diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequest.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequest.kt index 8cac51b5c2..e9f7e41828 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequest.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequest.kt @@ -25,7 +25,7 @@ internal data class ApiRequest( val logId: String? = null, - val url: EmbraceUrl, + val url: ApiRequestUrl, val httpMethod: HttpMethod = HttpMethod.POST, @@ -50,7 +50,7 @@ internal data class ApiRequest( fun toConnection(): EmbraceConnection { try { - val connection = url.openConnection() + val connection = EmbraceUrl.create(url.url).openConnection() getHeaders().forEach { connection.setRequestProperty(it.key, it.value) @@ -69,5 +69,5 @@ internal data class ApiRequest( * Returns true if the request is a session request. This heuristic should not be widely used * - it is only used to prioritise session requests over other requests. */ - fun isSessionRequest(): Boolean = url.toString().endsWith("spans") + fun isSessionRequest(): Boolean = url.url.endsWith("spans") } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt index abd65e4c6c..62530f97f3 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestMapper.kt @@ -19,14 +19,11 @@ internal class ApiRequestMapper( urlBuilder.getEmbraceUrlWithSuffix(it.version, it.path) } - private fun Endpoint.asEmbraceUrl(): EmbraceUrl { - val urlString: String = checkNotNull(apiUrlBuilders[this]) - return EmbraceUrl.create(urlString) - } + private fun Endpoint.asEmbraceUrl(): String = checkNotNull(apiUrlBuilders[this]) - private fun requestBuilder(url: EmbraceUrl): ApiRequest { + private fun requestBuilder(url: String): ApiRequest { return ApiRequest( - url = url, + url = ApiRequestUrl(url), httpMethod = HttpMethod.POST, appId = appId, deviceId = lazyDeviceId.value, @@ -38,7 +35,7 @@ internal class ApiRequestMapper( contentType = "application/json", userAgent = "Embrace/a/" + BuildConfig.VERSION_NAME, accept = "application/json", - url = EmbraceUrl.create(url), + url = ApiRequestUrl(url), httpMethod = HttpMethod.GET, ) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestUrl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestUrl.kt new file mode 100644 index 0000000000..cb16616db9 --- /dev/null +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiRequestUrl.kt @@ -0,0 +1,11 @@ +package io.embrace.android.embracesdk.internal.comms.api + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class ApiRequestUrl( + + @Json(name = "url") + val url: String +) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt index bb15222863..a8870463c3 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/ApiResponseCache.kt @@ -3,7 +3,7 @@ package io.embrace.android.embracesdk.internal.comms.api import android.net.http.HttpResponseCache import io.embrace.android.embracesdk.internal.config.remote.RemoteConfig import io.embrace.android.embracesdk.internal.logging.EmbLogger -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.storage.StorageService import java.io.Closeable import java.io.IOException @@ -20,7 +20,7 @@ import java.net.URI * & on the server. */ internal class ApiResponseCache( - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val storageService: StorageService, private val logger: EmbLogger ) : Closeable { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt index 1a4ba9f8a7..2ab7e38786 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/api/EmbraceApiService.kt @@ -15,7 +15,7 @@ import io.embrace.android.embracesdk.internal.payload.Envelope import io.embrace.android.embracesdk.internal.payload.EventMessage import io.embrace.android.embracesdk.internal.payload.LogPayload import io.embrace.android.embracesdk.internal.payload.NetworkEvent -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.utils.SerializationAction import io.embrace.android.embracesdk.internal.worker.BackgroundWorker import io.embrace.android.embracesdk.internal.worker.TaskPriority @@ -25,7 +25,7 @@ import java.util.concurrent.Future internal class EmbraceApiService( private val apiClient: ApiClient, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val cachedConfigProvider: (url: String, request: ApiRequest) -> CachedConfig, private val logger: EmbLogger, private val backgroundWorker: BackgroundWorker, @@ -111,7 +111,7 @@ internal class EmbraceApiService( contentType = "application/json", userAgent = "Embrace/a/" + BuildConfig.VERSION_NAME, accept = "application/json", - url = EmbraceUrl.create(url), + url = ApiRequestUrl(url), httpMethod = HttpMethod.GET, ) @@ -205,7 +205,8 @@ internal class EmbraceApiService( * Otherwise, the API call is saved to be sent later. */ private fun handleApiRequest(request: ApiRequest, action: SerializationAction): Boolean { - val endpoint = request.url.endpoint() + val url = EmbraceUrl.create(request.url.url) + val endpoint = url.endpoint() if (lastNetworkStatus.isReachable && !endpoint.isRateLimited) { // Execute the request if the device is online and the endpoint is not rate limited. diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSender.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSender.kt index a0933a0a05..5bf47f2e14 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSender.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/EmbracePendingApiCallsSender.kt @@ -5,6 +5,7 @@ import io.embrace.android.embracesdk.internal.capture.connectivity.NetworkConnec import io.embrace.android.embracesdk.internal.clock.Clock import io.embrace.android.embracesdk.internal.comms.api.ApiRequest import io.embrace.android.embracesdk.internal.comms.api.ApiResponse +import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl import io.embrace.android.embracesdk.internal.comms.api.Endpoint import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.utils.SerializationAction @@ -144,7 +145,8 @@ internal class EmbracePendingApiCallsSender( val pendingApiCall = pendingApiCalls.pollNextPendingApiCall() ?: break val response = sendPendingApiCall(pendingApiCall) response?.let { - clearRateLimitIfApplies(pendingApiCall.apiRequest.url.endpoint(), response) + val url = EmbraceUrl.create(pendingApiCall.apiRequest.url.url) + clearRateLimitIfApplies(url.endpoint(), response) if (response.shouldRetry) { when (response) { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCalls.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCalls.kt index 7ec3b6e9ad..095d95d169 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCalls.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/comms/delivery/PendingApiCalls.kt @@ -2,6 +2,7 @@ package io.embrace.android.embracesdk.internal.comms.delivery import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl import io.embrace.android.embracesdk.internal.comms.api.Endpoint import java.util.concurrent.ConcurrentHashMap @@ -21,7 +22,8 @@ internal class PendingApiCalls( * the new one is added. */ fun add(pendingApiCall: PendingApiCall) { - val endpoint = pendingApiCall.apiRequest.url.endpoint() + val url = EmbraceUrl.create(pendingApiCall.apiRequest.url.url) + val endpoint = url.endpoint() val pendingApiCallsForEndpoint = pendingApiCallsMap.getOrPut(endpoint, ::mutableListOf) synchronized(pendingApiCallsForEndpoint) { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/config/LocalConfigParser.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/config/LocalConfigParser.kt index 58e0148719..2a22330bdf 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/config/LocalConfigParser.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/config/LocalConfigParser.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.internal.config.local.LocalConfig import io.embrace.android.embracesdk.internal.config.local.SdkLocalConfig import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.opentelemetry.OpenTelemetryConfiguration -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer internal object LocalConfigParser { @@ -42,7 +42,7 @@ internal object LocalConfigParser { resources: AndroidResourcesService, packageName: String, customAppId: String?, - serializer: EmbraceSerializer, + serializer: PlatformSerializer, openTelemetryCfg: OpenTelemetryConfiguration, logger: EmbLogger ): LocalConfig { @@ -98,7 +98,7 @@ internal object LocalConfigParser { appId: String?, ndkEnabled: Boolean, sdkConfigs: String?, - serializer: EmbraceSerializer, + serializer: PlatformSerializer, openTelemetryCfg: OpenTelemetryConfiguration, logger: EmbLogger ): LocalConfig { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt index b816af80f1..4fc0ea8903 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/AndroidServicesModuleImpl.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.internal.worker.WorkerName import io.embrace.android.embracesdk.internal.worker.WorkerThreadModule internal class AndroidServicesModuleImpl( - initModule: io.embrace.android.embracesdk.internal.injection.InitModule, + initModule: InitModule, coreModule: CoreModule, workerThreadModule: WorkerThreadModule, ) : io.embrace.android.embracesdk.internal.injection.AndroidServicesModule { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataCaptureServiceModuleImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataCaptureServiceModuleImpl.kt index 508265788c..4f60e51004 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataCaptureServiceModuleImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataCaptureServiceModuleImpl.kt @@ -60,7 +60,7 @@ internal class DataCaptureServiceModuleImpl @JvmOverloads constructor( override val appStartupDataCollector: AppStartupDataCollector by singleton { AppStartupTraceEmitter( - clock = initModule.openTelemetryClock, + clock = openTelemetryModule.openTelemetryClock, startupServiceProvider = { startupService }, spanService = openTelemetryModule.spanService, backgroundWorker = workerThreadModule.backgroundWorker(WorkerName.BACKGROUND_REGISTRATION), diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt index 7f9c81e1cb..62032970de 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt @@ -79,4 +79,9 @@ internal interface OpenTelemetryModule { * Provides [Tracer] instances for instrumentation external to the Embrace SDK to create spans */ val externalTracerProvider: TracerProvider + + /** + * OpenTelemetry SDK compatible clock based on [clock] + */ + val openTelemetryClock: io.opentelemetry.sdk.common.Clock } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModuleImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModuleImpl.kt index 36945578fd..b03a42fe93 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModuleImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModuleImpl.kt @@ -1,5 +1,6 @@ package io.embrace.android.embracesdk.internal.injection +import io.embrace.android.embracesdk.internal.OpenTelemetryClock import io.embrace.android.embracesdk.internal.Systrace import io.embrace.android.embracesdk.internal.logs.LogSink import io.embrace.android.embracesdk.internal.logs.LogSinkImpl @@ -23,7 +24,10 @@ import io.opentelemetry.api.logs.Logger import io.opentelemetry.api.trace.Tracer internal class OpenTelemetryModuleImpl( - private val initModule: InitModule + private val initModule: InitModule, + override val openTelemetryClock: io.opentelemetry.sdk.common.Clock = OpenTelemetryClock( + embraceClock = initModule.clock + ), ) : OpenTelemetryModule { override val spanRepository: SpanRepository by lazy { @@ -47,7 +51,7 @@ internal class OpenTelemetryModuleImpl( Systrace.traceSynchronous("otel-sdk-wrapper-init") { try { OpenTelemetrySdk( - openTelemetryClock = initModule.openTelemetryClock, + openTelemetryClock = openTelemetryClock, configuration = openTelemetryConfiguration ) } catch (exc: NoClassDefFoundError) { @@ -68,14 +72,14 @@ internal class OpenTelemetryModuleImpl( private val embraceSpanFactory: EmbraceSpanFactory by singleton { EmbraceSpanFactoryImpl( tracer = sdkTracer, - openTelemetryClock = initModule.openTelemetryClock, + openTelemetryClock = openTelemetryClock, spanRepository = spanRepository ) } override val currentSessionSpan: CurrentSessionSpan by lazy { CurrentSessionSpanImpl( - openTelemetryClock = initModule.openTelemetryClock, + openTelemetryClock = openTelemetryClock, telemetryService = initModule.telemetryService, spanRepository = spanRepository, spanSink = spanSink, @@ -122,7 +126,7 @@ internal class OpenTelemetryModuleImpl( EmbTracerProvider( sdkTracerProvider = openTelemetrySdk.sdkTracerProvider, spanService = spanService, - clock = initModule.openTelemetryClock, + clock = openTelemetryClock, ) } } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt index af8e136022..62b2cd5674 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogService.kt @@ -18,7 +18,7 @@ import io.embrace.android.embracesdk.internal.config.behavior.LogMessageBehavior import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.opentelemetry.embExceptionHandling import io.embrace.android.embracesdk.internal.payload.AppFramework -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.serialization.truncatedStacktrace import io.embrace.android.embracesdk.internal.session.properties.EmbraceSessionProperties import io.embrace.android.embracesdk.internal.spans.toOtelSeverity @@ -40,7 +40,7 @@ internal class EmbraceLogService( private val backgroundWorker: BackgroundWorker, private val logger: EmbLogger, clock: Clock, - private val serializer: EmbraceSerializer + private val serializer: PlatformSerializer ) : LogService { private val logCounters = mapOf( diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/EmbraceNdkService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/EmbraceNdkService.kt index 92d877a37f..b0ce2ec237 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/EmbraceNdkService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/EmbraceNdkService.kt @@ -6,6 +6,7 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.util.Base64 +import com.squareup.moshi.Types import io.embrace.android.embracesdk.internal.DeviceArchitecture import io.embrace.android.embracesdk.internal.EventType import io.embrace.android.embracesdk.internal.SharedObjectLoader @@ -26,7 +27,7 @@ import io.embrace.android.embracesdk.internal.payload.NativeCrashDataError import io.embrace.android.embracesdk.internal.payload.NativeCrashMetadata import io.embrace.android.embracesdk.internal.payload.NativeSymbols import io.embrace.android.embracesdk.internal.prefs.PreferencesService -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateListener import io.embrace.android.embracesdk.internal.session.lifecycle.ProcessStateService import io.embrace.android.embracesdk.internal.session.properties.EmbraceSessionProperties @@ -63,7 +64,7 @@ internal class EmbraceNdkService( * The device architecture. */ private val deviceArchitecture: DeviceArchitecture, - private val serializer: EmbraceSerializer + private val serializer: PlatformSerializer ) : NdkService, ProcessStateListener { /** * Synchronization lock. @@ -256,9 +257,8 @@ internal class EmbraceNdkService( val errorsRaw = delegate._getErrors(absolutePath) if (errorsRaw != null) { try { - return serializer.fromJsonWithTypeToken>( - errorsRaw - ) + val type = Types.newParameterizedType(List::class.java, NativeCrashDataError::class.java) + return serializer.fromJson(errorsRaw, type) } catch (e: Exception) { logger.logError( "Failed to parse native crash error file {crashId=" + nativeCrash.nativeCrashId + diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/NativeCrashDataSource.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/NativeCrashDataSource.kt index dc22bcf59a..cd1bdb2a74 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/NativeCrashDataSource.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/ndk/NativeCrashDataSource.kt @@ -18,7 +18,7 @@ import io.embrace.android.embracesdk.internal.opentelemetry.embCrashNumber import io.embrace.android.embracesdk.internal.payload.NativeCrashData import io.embrace.android.embracesdk.internal.payload.NativeCrashDataError import io.embrace.android.embracesdk.internal.prefs.PreferencesService -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.properties.EmbraceSessionProperties import io.embrace.android.embracesdk.internal.spans.toOtelSeverity import io.embrace.android.embracesdk.internal.utils.toUTF8String @@ -32,7 +32,7 @@ internal class NativeCrashDataSourceImpl( private val preferencesService: PreferencesService, private val logWriter: LogWriter, private val configService: ConfigService, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, logger: EmbLogger, ) : NativeCrashDataSource, LogDataSourceImpl( destination = logWriter, diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt index c9fdc39ae2..2f81fff6a4 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/network/logging/EmbraceNetworkCaptureService.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.internal.logging.EmbLogger import io.embrace.android.embracesdk.internal.network.http.NetworkCaptureData import io.embrace.android.embracesdk.internal.payload.NetworkCapturedCall import io.embrace.android.embracesdk.internal.prefs.PreferencesService -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.id.SessionIdTracker import io.embrace.android.embracesdk.internal.utils.Provider import kotlin.math.max @@ -21,7 +21,7 @@ internal class EmbraceNetworkCaptureService( private val preferencesService: PreferencesService, private val networkCaptureDataSource: Provider, private val configService: ConfigService, - private val serializer: EmbraceSerializer, + private val serializer: PlatformSerializer, private val logger: EmbLogger ) : NetworkCaptureService { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt index 0a372dddf0..628b844ab4 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/prefs/EmbracePreferencesService.kt @@ -3,7 +3,7 @@ package io.embrace.android.embracesdk.internal.prefs import android.content.SharedPreferences import io.embrace.android.embracesdk.internal.Systrace import io.embrace.android.embracesdk.internal.clock.Clock -import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer +import io.embrace.android.embracesdk.internal.serialization.PlatformSerializer import io.embrace.android.embracesdk.internal.session.lifecycle.StartupListener import io.embrace.android.embracesdk.internal.utils.Uuid.getEmbUuid import io.embrace.android.embracesdk.internal.worker.BackgroundWorker @@ -15,7 +15,7 @@ internal class EmbracePreferencesService( private val backgroundWorker: BackgroundWorker, lazyPrefs: Lazy, private val clock: Clock, - private val serializer: EmbraceSerializer + private val serializer: PlatformSerializer ) : PreferencesService, StartupListener { private val preferences: Future diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapter.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapter.kt deleted file mode 100644 index a78088666a..0000000000 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapter.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.embrace.android.embracesdk.internal.serialization - -import com.squareup.moshi.FromJson -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass -import com.squareup.moshi.ToJson -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl - -@JsonClass(generateAdapter = true) -internal data class EmbraceUrlJson( - @Json(name = "url") - val url: String? = null -) - -internal class EmbraceUrlAdapter { - - @FromJson - fun fromJson(json: EmbraceUrlJson): EmbraceUrl? { - val url = json.url ?: return null - return EmbraceUrl.create(url) - } - - @ToJson - fun toJson(embraceUrl: EmbraceUrl?): EmbraceUrlJson? { - val url = embraceUrl?.toString() ?: return null - return EmbraceUrlJson(url) - } -} diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt deleted file mode 100644 index 84dd11abaf..0000000000 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/serialization/PlatformSerializer.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.embrace.android.embracesdk.internal.serialization - -import io.embrace.android.embracesdk.internal.utils.truncate -import java.io.InputStream -import java.io.OutputStream -import java.lang.reflect.Type - -/** - * Interface for JSON serializer wrapper than can then be wrapped for testing purposes - */ -internal interface PlatformSerializer { - fun toJson(src: T): String - fun toJson(src: T, clz: Class): String - fun toJson(src: T, type: Type): String - fun toJson(any: T, clazz: Class, outputStream: OutputStream) - fun toJson(any: T, type: Type, outputStream: OutputStream) - fun fromJson(json: String, clz: Class): T - fun fromJson(json: String, type: Type): T - fun fromJson(inputStream: InputStream, clz: Class): T - fun fromJson(inputStream: InputStream, type: Type): T -} - -/** - * Return the first 200 elements of [elements] as a JSON-encoded string - */ -internal fun PlatformSerializer.truncatedStacktrace( - elements: Array -) = toJson(elements.truncate(), List::class.java) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt index 20027b3075..01b63de0bb 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt @@ -12,7 +12,6 @@ import io.opentelemetry.api.common.AttributeKey import io.opentelemetry.api.common.Attributes import io.opentelemetry.api.common.AttributesBuilder import io.opentelemetry.api.logs.LogRecordBuilder -import io.opentelemetry.api.logs.Severity import io.opentelemetry.api.trace.Span import io.opentelemetry.api.trace.SpanBuilder import io.opentelemetry.api.trace.StatusCode @@ -27,11 +26,6 @@ import io.opentelemetry.semconv.ExceptionAttributes * Note: there's no explicit tests for these extensions as their functionality will be validated as part of other tests. */ -/** - * Prefix added to all attribute keys for all usage attributes added by the SDK - */ -private const val EMBRACE_USAGE_ATTRIBUTE_NAME_PREFIX = "emb.usage." - /** * Creates a new [SpanBuilder] that marks the resulting span as private if [internal] is true */ @@ -79,11 +73,6 @@ internal fun AttributesBuilder.fromMap(attributes: Map): Attribu return this } -/** - * Return the appropriate internal Embrace attribute usage name given the current string - */ -internal fun String.toEmbraceUsageAttributeName(): String = EMBRACE_USAGE_ATTRIBUTE_NAME_PREFIX + this - internal fun SpanData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = attributes.asMap()[fixedAttribute.key.attributeKey] == fixedAttribute.value @@ -127,12 +116,6 @@ internal fun Map.getAttribute(key: AttributeKey): String internal fun Map.getAttribute(key: EmbraceAttributeKey): String? = getAttribute(key.attributeKey) -internal fun io.embrace.android.embracesdk.Severity.toOtelSeverity(): Severity = when (this) { - io.embrace.android.embracesdk.Severity.INFO -> Severity.INFO - io.embrace.android.embracesdk.Severity.WARNING -> Severity.WARN - io.embrace.android.embracesdk.Severity.ERROR -> Severity.ERROR -} - internal fun String.isValidLongValueAttribute() = longValueAttributes.contains(this) internal val longValueAttributes = setOf(ExceptionAttributes.EXCEPTION_STACKTRACE.key) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt index 89e9a69273..8271d00483 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceCacheServiceTest.kt @@ -8,7 +8,7 @@ import io.embrace.android.embracesdk.fixtures.testSessionEnvelope import io.embrace.android.embracesdk.fixtures.testSessionEnvelope2 import io.embrace.android.embracesdk.fixtures.testSessionEnvelopeOneMinuteLater import io.embrace.android.embracesdk.internal.comms.api.ApiRequest -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.internal.comms.delivery.CacheService import io.embrace.android.embracesdk.internal.comms.delivery.CachedSession import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceCacheService @@ -155,7 +155,7 @@ internal class EmbraceCacheServiceTest { fun `test PendingApiCalls can be cached`() { val apiRequest = ApiRequest( httpMethod = HttpMethod.GET, - url = EmbraceUrl.create("http://fake.url/sessions") + url = ApiRequestUrl("http://fake.url/sessions") ) val pendingApiCalls = PendingApiCalls() pendingApiCalls.add(PendingApiCall(apiRequest, "payload_id")) @@ -299,14 +299,14 @@ internal class EmbraceCacheServiceTest { PendingApiCall( ApiRequest( httpMethod = HttpMethod.POST, - url = EmbraceUrl.create("http://fake.url/sessions") + url = ApiRequestUrl("http://fake.url/sessions") ), "payload_id_1" ), PendingApiCall( ApiRequest( httpMethod = HttpMethod.POST, - url = EmbraceUrl.create("http://fake.url/sessions") + url = ApiRequestUrl("http://fake.url/sessions") ), "payload_id_2" ) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt index f710c7da4b..4c48c371d7 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/EmbraceDeliveryCacheManagerTest.kt @@ -8,7 +8,7 @@ import io.embrace.android.embracesdk.fakes.fakeSessionEnvelope import io.embrace.android.embracesdk.fixtures.testSessionEnvelope import io.embrace.android.embracesdk.fixtures.testSessionEnvelopeOneMinuteLater import io.embrace.android.embracesdk.internal.comms.api.ApiRequest -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.internal.comms.delivery.CachedSession import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceCacheService import io.embrace.android.embracesdk.internal.comms.delivery.EmbraceDeliveryCacheManager @@ -280,7 +280,7 @@ internal class EmbraceDeliveryCacheManagerTest { fun `save and load pending api calls`() { val pendingApiCalls = PendingApiCalls() val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/sessions"), + url = ApiRequestUrl("http://test.url/sessions"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -291,7 +291,7 @@ internal class EmbraceDeliveryCacheManagerTest { pendingApiCalls.add(pendingApiCall1) val request2 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id", deviceId = "test_device_id", @@ -303,7 +303,7 @@ internal class EmbraceDeliveryCacheManagerTest { pendingApiCalls.add(pendingApiCall2) val request3 = ApiRequest( - url = EmbraceUrl.create("http://test.url/logging"), + url = ApiRequestUrl("http://test.url/logging"), httpMethod = HttpMethod.POST, appId = "test_app_id", deviceId = "test_device_id", @@ -334,7 +334,7 @@ internal class EmbraceDeliveryCacheManagerTest { val pendingApiCalls = PendingApiCalls() val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/sessions"), + url = ApiRequestUrl("http://test.url/sessions"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -345,7 +345,7 @@ internal class EmbraceDeliveryCacheManagerTest { pendingApiCalls.add(pendingApiCall1) val request2 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id", deviceId = "test_device_id", @@ -357,7 +357,7 @@ internal class EmbraceDeliveryCacheManagerTest { pendingApiCalls.add(pendingApiCall2) val request3 = ApiRequest( - url = EmbraceUrl.create("http://test.url/logging"), + url = ApiRequestUrl("http://test.url/logging"), httpMethod = HttpMethod.POST, appId = "test_app_id", deviceId = "test_device_id", @@ -391,7 +391,7 @@ internal class EmbraceDeliveryCacheManagerTest { fun `load old version of pending api calls file as new version when load cache returns null`() { val pendingApiCallsQueue = mutableListOf() val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/sessions"), + url = ApiRequestUrl("http://test.url/sessions"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -402,7 +402,7 @@ internal class EmbraceDeliveryCacheManagerTest { pendingApiCallsQueue.add(pendingApiCall1) val request2 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id", deviceId = "test_device_id", diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt index 1ec875a1f2..ffd03e2876 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/capture/startup/AppStartupTraceEmitterTest.kt @@ -64,7 +64,7 @@ internal class AppStartupTraceEmitterTest { fakeInternalErrorService = FakeInternalErrorService() logger = EmbLoggerImpl().apply { internalErrorService = fakeInternalErrorService } appStartupTraceEmitter = AppStartupTraceEmitter( - clock = initModule.openTelemetryClock, + clock = initModule.openTelemetryModule.openTelemetryClock, startupServiceProvider = { startupService }, spanService = spanService, backgroundWorker = backgroundWorker, diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt index 51233c4429..287d2c755f 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiClientImplTest.kt @@ -2,8 +2,8 @@ package io.embrace.android.embracesdk.comms.api import io.embrace.android.embracesdk.internal.comms.api.ApiClientImpl import io.embrace.android.embracesdk.internal.comms.api.ApiRequest +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.internal.comms.api.ApiResponse -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl import io.embrace.android.embracesdk.internal.compression.ConditionalGzipOutputStream import io.embrace.android.embracesdk.internal.logging.EmbLoggerImpl import io.embrace.android.embracesdk.internal.payload.Attribute @@ -11,8 +11,6 @@ import io.embrace.android.embracesdk.internal.payload.SessionPayload import io.embrace.android.embracesdk.internal.payload.Span import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer import io.embrace.android.embracesdk.network.http.HttpMethod -import io.mockk.every -import io.mockk.mockk import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer import okhttp3.mockwebserver.RecordedRequest @@ -21,7 +19,6 @@ import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test -import java.net.SocketException import java.util.concurrent.Executors import java.util.concurrent.TimeUnit import java.util.zip.GZIPInputStream @@ -53,7 +50,7 @@ internal class ApiClientImplTest { @Test fun testUnreachableHost() { // attempt some unreachable port - val request = ApiRequest(url = EmbraceUrl.create("http://localhost:1565")) + val request = ApiRequest(url = ApiRequestUrl("http://localhost:1565")) val response = apiClient.executePost(request) { it.write("Hello world".toByteArray()) } @@ -182,7 +179,7 @@ internal class ApiClientImplTest { "test_did", "test_eid", "test_lid", - EmbraceUrl.create(baseUrl) + ApiRequestUrl(baseUrl) ) server.enqueue(response200) apiClient.executePost(postRequest) { @@ -214,7 +211,7 @@ internal class ApiClientImplTest { private fun runGetRequest(): ApiResponse = apiClient.executeGet( ApiRequest( - url = EmbraceUrl.create(baseUrl), + url = ApiRequestUrl(baseUrl), httpMethod = HttpMethod.GET ) ) @@ -224,7 +221,7 @@ internal class ApiClientImplTest { ): ApiResponse = apiClient.executePost( ApiRequest( - url = EmbraceUrl.create(baseUrl), + url = ApiRequestUrl(baseUrl), httpMethod = HttpMethod.POST ) ) { @@ -234,9 +231,7 @@ internal class ApiClientImplTest { } private fun createThrowingRequest(): ApiRequest { - val mockEmbraceUrl: EmbraceUrl = mockk(relaxed = true) - every { mockEmbraceUrl.openConnection() } answers { throw SocketException() } - return ApiRequest(url = mockEmbraceUrl) + return ApiRequest(url = ApiRequestUrl("my bad req")) } private fun RecordedRequest.readCompressedRequestBody(): String { diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestMapperTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestMapperTest.kt index 596513ca95..ee98c4fb1a 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestMapperTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestMapperTest.kt @@ -41,7 +41,7 @@ internal class ApiRequestMapperTest { @Test fun testConfigRequest() { with(mapper.configRequest(CONFIG_URL)) { - assertEquals(CONFIG_URL, url.toString()) + assertEquals(CONFIG_URL, url.url) assertEquals("application/json", contentType) assertEquals("application/json", accept) assertTrue(userAgent.startsWith("Embrace/a/")) @@ -140,7 +140,7 @@ internal class ApiRequestMapperTest { } private fun ApiRequest.assertCoreFieldsPopulated(endpoint: String) { - assertEquals("$BASE_URL$endpoint", url.toString()) + assertEquals("$BASE_URL$endpoint", url.url) assertEquals(HttpMethod.POST, httpMethod) assertEquals("appId", appId) assertEquals("deviceId", deviceId) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestTest.kt index 98217f5779..3a6a50183e 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/ApiRequestTest.kt @@ -5,7 +5,7 @@ import io.embrace.android.embracesdk.assertJsonMatchesGoldenFile import io.embrace.android.embracesdk.deserializeEmptyJsonString import io.embrace.android.embracesdk.deserializeJsonFromResource import io.embrace.android.embracesdk.internal.comms.api.ApiRequest -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.network.http.HttpMethod import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -24,7 +24,7 @@ internal class ApiRequestTest { "test_did", "test_eid", "test_lid", - EmbraceUrl.create("https://google.com"), + ApiRequestUrl("https://google.com"), HttpMethod.GET, "d800f828fec4409dcabc7f5252e7ce71" ) @@ -50,7 +50,7 @@ internal class ApiRequestTest { @Test fun testMinimalHeaders() { - val minimal = ApiRequest(url = EmbraceUrl.create("https://google.com")) + val minimal = ApiRequest(url = ApiRequestUrl("https://google.com")) assertTrue(minimal.getHeaders()["User-Agent"].toString().startsWith("Embrace/a/")) assertEquals( @@ -96,7 +96,7 @@ internal class ApiRequestTest { fun testSessionRequest() { assertFalse(request.isSessionRequest()) - val copy = request.copy(url = EmbraceUrl.create("https://example.com/v2/spans")) + val copy = request.copy(url = ApiRequestUrl("https://example.com/v2/spans")) assertTrue(copy.isSessionRequest()) } } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/EmbraceApiServiceTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/EmbraceApiServiceTest.kt index 05ff794d55..206dffb34a 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/EmbraceApiServiceTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/api/EmbraceApiServiceTest.kt @@ -302,7 +302,7 @@ internal class EmbraceApiServiceTest { val request = fakePendingApiCallsSender.retryQueue.single().first val payload = fakePendingApiCallsSender.retryQueue.single().second - assertEquals("https://a-$fakeAppId.data.emb-api.com/v2/logs", request.url.toString()) + assertEquals("https://a-$fakeAppId.data.emb-api.com/v2/logs", request.url.url) val type: ParameterizedType = Types.newParameterizedType(Envelope::class.java, LogPayload::class.java) assertArrayEquals(getGenericsExpectedPayloadSerialized(logsEnvelope, type), payload) } @@ -346,7 +346,7 @@ internal class EmbraceApiServiceTest { apiService.sendLog(event) assertEquals(0, fakeApiClient.sentRequests.size) val request = fakePendingApiCallsSender.retryQueue.single().first - assertEquals("https://a-$fakeAppId.data.emb-api.com/v1/log/logging", request.url.toString()) + assertEquals("https://a-$fakeAppId.data.emb-api.com/v1/log/logging", request.url.url) } @Test @@ -575,7 +575,7 @@ internal class EmbraceApiServiceTest { assertEquals(fakeDeviceId, deviceId) assertEquals(expectedEventId, eventId) assertEquals(expectedLogId, logId) - assertEquals(expectedUrl, url.toString()) + assertEquals(expectedUrl, url.url) assertEquals(expectedMethod, httpMethod) assertEquals(expectedEtag, eTag) } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbracePendingApiCallsSenderTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbracePendingApiCallsSenderTest.kt index 6651dc0594..455c44971c 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbracePendingApiCallsSenderTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbracePendingApiCallsSenderTest.kt @@ -6,6 +6,7 @@ import io.embrace.android.embracesdk.internal.EventType import io.embrace.android.embracesdk.internal.capture.connectivity.NetworkConnectivityService import io.embrace.android.embracesdk.internal.comms.api.ApiRequest import io.embrace.android.embracesdk.internal.comms.api.ApiRequestMapper +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.internal.comms.api.ApiResponse import io.embrace.android.embracesdk.internal.comms.api.EmbraceApiUrlBuilder import io.embrace.android.embracesdk.internal.comms.api.Endpoint @@ -327,10 +328,10 @@ internal class EmbracePendingApiCallsSenderTest { pendingApiCallsSender.setSendMethod(mockRetryMethod) if (loadFailedRequest) { - val mockApiRequest = mockk(relaxed = true) { - every { url.endpoint() } returns Endpoint.SESSIONS - } - pendingApiCalls.add(PendingApiCall(mockApiRequest, "cached_payload_1")) + val request = ApiRequest( + url = ApiRequestUrl("https://fake.com/${Endpoint.SESSIONS.path}") + ) + pendingApiCalls.add(PendingApiCall(request, "cached_payload_1")) } if (runRetryJobAfterScheduling) { diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/PendingApiCallsTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/PendingApiCallsTest.kt index 4aa07d7511..5eec0d912e 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/PendingApiCallsTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/PendingApiCallsTest.kt @@ -2,7 +2,7 @@ package io.embrace.android.embracesdk.comms.delivery import io.embrace.android.embracesdk.concurrency.BlockingScheduledExecutorService import io.embrace.android.embracesdk.internal.comms.api.ApiRequest -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl +import io.embrace.android.embracesdk.internal.comms.api.ApiRequestUrl import io.embrace.android.embracesdk.internal.comms.api.Endpoint import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCall import io.embrace.android.embracesdk.internal.comms.delivery.PendingApiCalls @@ -28,7 +28,7 @@ internal class PendingApiCallsTest { @Test fun `test adding pending api calls associated to endpoints`() { val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/spans"), + url = ApiRequestUrl("http://test.url/spans"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -39,7 +39,7 @@ internal class PendingApiCallsTest { pendingApiCalls.add(pendingApiCall1) val request2 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -57,7 +57,7 @@ internal class PendingApiCallsTest { @Test fun `test hasPendingApiCallsToSend`() { val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/sessions"), + url = ApiRequestUrl("http://test.url/sessions"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -72,7 +72,7 @@ internal class PendingApiCallsTest { @Test fun `test pollNextPendingApiCall always return session if exists`() { val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -83,7 +83,7 @@ internal class PendingApiCallsTest { pendingApiCalls.add(pendingApiCall1) val request2 = ApiRequest( - url = EmbraceUrl.create("http://test.url/spans"), + url = ApiRequestUrl("http://test.url/spans"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -111,7 +111,7 @@ internal class PendingApiCallsTest { val path = it.path repeat(queueLimit) { val request = ApiRequest( - url = EmbraceUrl.create("http://test.url/$path"), + url = ApiRequestUrl("http://test.url/$path"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -124,7 +124,7 @@ internal class PendingApiCallsTest { } val exceedingRequest = ApiRequest( - url = EmbraceUrl.create("http://test.url/$path"), + url = ApiRequestUrl("http://test.url/$path"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", @@ -151,7 +151,7 @@ internal class PendingApiCallsTest { @Test fun `test pollNextPendingApiCall doesn't return api calls from rate limited endpoint`() { val request1 = ApiRequest( - url = EmbraceUrl.create("http://test.url/events"), + url = ApiRequestUrl("http://test.url/events"), httpMethod = HttpMethod.POST, appId = "test_app_id_1", deviceId = "test_device_id", diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeOpenTelemetryModule.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeOpenTelemetryModule.kt index ff263bcd51..3bd17bcbd9 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeOpenTelemetryModule.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeOpenTelemetryModule.kt @@ -17,6 +17,7 @@ import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.api.logs.Logger import io.opentelemetry.api.trace.Tracer import io.opentelemetry.api.trace.TracerProvider +import io.opentelemetry.sdk.common.Clock internal class FakeOpenTelemetryModule( override val currentSessionSpan: CurrentSessionSpan = FakeCurrentSessionSpan(), @@ -39,4 +40,6 @@ internal class FakeOpenTelemetryModule( get() = EmbOpenTelemetry(traceProviderSupplier = { FakeTracerProvider() }) override val externalTracerProvider: TracerProvider get() = FakeTracerProvider() + override val openTelemetryClock: Clock + get() = FakeOpenTelemetryClock(FakeClock()) } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt index b72923a042..bf78b1df9f 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/injection/FakeInitModule.kt @@ -2,11 +2,8 @@ package io.embrace.android.embracesdk.fakes.injection import io.embrace.android.embracesdk.fakes.FakeClock import io.embrace.android.embracesdk.fakes.FakeEmbLogger -import io.embrace.android.embracesdk.fakes.FakeOpenTelemetryClock import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.clock.Clock -import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock -import io.embrace.android.embracesdk.internal.clock.SystemClock import io.embrace.android.embracesdk.internal.injection.InitModule import io.embrace.android.embracesdk.internal.injection.InitModuleImpl import io.embrace.android.embracesdk.internal.injection.OpenTelemetryModule @@ -14,8 +11,7 @@ import io.embrace.android.embracesdk.internal.injection.OpenTelemetryModuleImpl import io.embrace.android.embracesdk.internal.logging.EmbLogger internal class FakeInitModule( - clock: Clock = NormalizedIntervalClock(systemClock = SystemClock()), - openTelemetryClock: io.opentelemetry.sdk.common.Clock = FakeOpenTelemetryClock(clock), + clock: Clock = FakeClock(), logger: EmbLogger = FakeEmbLogger(), systemInfo: SystemInfo = SystemInfo( osVersion = "99.0.0", @@ -24,7 +20,6 @@ internal class FakeInitModule( ), initModule: InitModule = InitModuleImpl( clock = clock, - openTelemetryClock = openTelemetryClock, logger = logger, systemInfo = systemInfo ) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/InitModuleImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/InitModuleImplTest.kt index 0751a3bc92..ce2e334e82 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/InitModuleImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/injection/InitModuleImplTest.kt @@ -2,9 +2,7 @@ package io.embrace.android.embracesdk.injection import androidx.test.ext.junit.runners.AndroidJUnit4 import io.embrace.android.embracesdk.fakes.FakeClock -import io.embrace.android.embracesdk.fakes.FakeOpenTelemetryClock import io.embrace.android.embracesdk.internal.SystemInfo -import io.embrace.android.embracesdk.internal.clock.NormalizedIntervalClock import io.embrace.android.embracesdk.internal.injection.InitModuleImpl import io.embrace.android.embracesdk.internal.telemetry.EmbraceTelemetryService import org.junit.Assert.assertEquals @@ -20,7 +18,7 @@ internal class InitModuleImplTest { @Test fun testInitModuleImplDefaults() { val initModule = InitModuleImpl() - assertTrue(initModule.clock is NormalizedIntervalClock) + assertNotNull(initModule.clock) assertTrue(initModule.telemetryService is EmbraceTelemetryService) assertEquals(initModule.systemInfo, SystemInfo()) assertEquals(initModule.processIdentifier.length, 16) @@ -30,11 +28,9 @@ internal class InitModuleImplTest { @Test fun testInitModuleImplOverrideComponents() { val clock = FakeClock() - val openTelemetryClock = FakeOpenTelemetryClock(clock) val systemInfo = SystemInfo() val initModule = InitModuleImpl( clock = clock, - openTelemetryClock = openTelemetryClock, systemInfo = systemInfo ) assertSame(clock, initModule.clock) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapterTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapterTest.kt deleted file mode 100644 index 6cb56db056..0000000000 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/serialization/EmbraceUrlAdapterTest.kt +++ /dev/null @@ -1,18 +0,0 @@ -package io.embrace.android.embracesdk.internal.serialization - -import io.embrace.android.embracesdk.internal.comms.api.EmbraceUrl -import org.junit.Assert.assertEquals -import org.junit.Test - -internal class EmbraceUrlAdapterTest { - - private val serializer = EmbraceSerializer() - - @Test - fun `test EmbraceUrl serialization`() { - val embraceUrl = EmbraceUrl.create("http://fake.url") - val jsonStr: String = serializer.toJson(embraceUrl) - val serialized: EmbraceUrl = serializer.fromJson(jsonStr, EmbraceUrl::class.java) - assertEquals(embraceUrl.toString(), serialized.toString()) - } -} diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt index e4d7ac76b1..985543a791 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanFactoryImplTest.kt @@ -27,7 +27,7 @@ internal class EmbraceSpanFactoryImplTest { tracer = FakeTracer() embraceSpanFactory = EmbraceSpanFactoryImpl( tracer = tracer, - openTelemetryClock = initModule.openTelemetryClock, + openTelemetryClock = initModule.openTelemetryModule.openTelemetryClock, spanRepository = spanRepository, ) } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt index 1f231762c7..0c7872c282 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanImplTest.kt @@ -47,7 +47,7 @@ internal class EmbraceSpanImplTest { fun setup() { fakeClock = FakeClock() val fakeInitModule = FakeInitModule(fakeClock) - openTelemetryClock = fakeInitModule.openTelemetryClock + openTelemetryClock = fakeInitModule.openTelemetryModule.openTelemetryClock spanRepository = SpanRepository() serializer = fakeInitModule.jsonSerializer embraceSpan = EmbraceSpanImpl( diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/SpanServiceImplTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/SpanServiceImplTest.kt index 6412559c9b..0733e4aa52 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/SpanServiceImplTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/spans/SpanServiceImplTest.kt @@ -51,7 +51,7 @@ internal class SpanServiceImplTest { currentSessionSpan = currentSessionSpan, embraceSpanFactory = EmbraceSpanFactoryImpl( tracer = initModule.openTelemetryModule.sdkTracer, - openTelemetryClock = initModule.openTelemetryClock, + openTelemetryClock = initModule.openTelemetryModule.openTelemetryClock, spanRepository = initModule.openTelemetryModule.spanRepository, ) ) diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/opentelemetry/EmbSpanTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/opentelemetry/EmbSpanTest.kt index 8577981285..56c5108700 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/opentelemetry/EmbSpanTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/opentelemetry/EmbSpanTest.kt @@ -30,7 +30,7 @@ internal class EmbSpanTest { @Before fun setup() { fakeClock = FakeClock() - openTelemetryClock = FakeInitModule(fakeClock).openTelemetryClock + openTelemetryClock = FakeInitModule(fakeClock).openTelemetryModule.openTelemetryClock fakeEmbraceSpan = FakePersistableEmbraceSpan.started(clock = fakeClock) embSpan = EmbSpan( embraceSpan = fakeEmbraceSpan, From 3dc1284f4071d4a49e98eea6162b516d4f3bbbb2 Mon Sep 17 00:00:00 2001 From: Jamie Lynch Date: Fri, 26 Jul 2024 12:01:10 +0100 Subject: [PATCH 2/3] refactor: move otel module --- .../api/embrace-android-api.api | 51 +++++++++++++++++++ .../embracesdk/internal/InternalTracingApi.kt | 0 .../android/embracesdk/spans/TracingApi.kt | 0 embrace-android-core/build.gradle.kts | 11 ++++ .../arch/schema/AppTerminationCause.kt | 16 ++++++ .../internal/injection/OpenTelemetryModule.kt | 28 +++++----- .../internal/logs/EmbraceLogRecordExporter.kt | 2 +- .../logs/EmbraceLogRecordProcessor.kt | 2 +- .../embracesdk/internal/logs/LogSink.kt | 12 ++--- .../opentelemetry/EmbraceAttributeKeys.kt | 38 +++++++------- .../OpenTelemetryConfiguration.kt | 20 ++++---- .../internal/spans/CurrentSessionSpan.kt | 11 ++-- .../embracesdk/internal/spans/EmbraceExt.kt | 29 +++++++++++ .../internal/spans/EmbraceSpanData.kt | 20 ++------ .../internal/spans/EmbraceSpanExporter.kt | 0 .../internal/spans/EmbraceSpanProcessor.kt | 0 .../internal/spans/EmbraceTracer.kt | 4 +- .../internal/spans/InternalTracer.kt | 2 +- .../internal/spans/SpanRepository.kt | 18 ++++--- .../embracesdk/internal/spans/SpanSink.kt | 8 +-- .../internal/utils/CollectionExtensions.kt | 6 +-- .../embracesdk/internal/payload/Log.kt | 2 +- .../api/embrace-android-sdk.api | 51 ------------------- .../assertions/InternalErrorAssertions.kt | 5 +- .../testcases/ExternalTracerTest.kt | 3 +- .../arch/schema/AppTerminationCause.kt | 16 ------ .../internal/spans/EmbraceExtensions.kt | 26 ---------- .../embracesdk/internal/spans/SpanDataExt.kt | 16 ++++++ .../embracesdk/internal/spans/SpanSinkImpl.kt | 2 +- .../delivery/EmbraceDeliveryServiceTest.kt | 3 +- .../fakes/FakeCurrentSessionSpan.kt | 3 +- .../internal/payload/SpanMapperTest.kt | 8 +-- 32 files changed, 220 insertions(+), 193 deletions(-) rename {embrace-android-sdk/src/main/java => embrace-android-api/src/main/kotlin}/io/embrace/android/embracesdk/internal/InternalTracingApi.kt (100%) rename {embrace-android-sdk/src/main/java => embrace-android-api/src/main/kotlin}/io/embrace/android/embracesdk/spans/TracingApi.kt (100%) create mode 100644 embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt (77%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt (96%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt (93%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/logs/LogSink.kt (78%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt (51%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt (81%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt (65%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt (63%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/EmbraceSpanExporter.kt (100%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/EmbraceSpanProcessor.kt (100%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt (96%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt (99%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt (83%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/SpanSink.kt (78%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt (91%) rename {embrace-android-sdk/src/main/java => embrace-android-payload/src/main/kotlin}/io/embrace/android/embracesdk/internal/payload/Log.kt (98%) delete mode 100644 embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt create mode 100644 embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanDataExt.kt diff --git a/embrace-android-api/api/embrace-android-api.api b/embrace-android-api/api/embrace-android-api.api index 50c8555caa..26048cc462 100644 --- a/embrace-android-api/api/embrace-android-api.api +++ b/embrace-android-api/api/embrace-android-api.api @@ -15,6 +15,23 @@ public abstract interface annotation class io/embrace/android/embracesdk/annotat public abstract interface annotation class io/embrace/android/embracesdk/annotation/StartupActivity : java/lang/annotation/Annotation { } +public abstract interface class io/embrace/android/embracesdk/internal/InternalTracingApi { + public abstract fun addSpanAttribute (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z + public abstract fun addSpanEvent (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;)Z + public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;)Z + public abstract fun recordSpan (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public abstract fun startSpan (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;)Ljava/lang/String; + public abstract fun stopSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/Long;)Z +} + +public final class io/embrace/android/embracesdk/internal/InternalTracingApi$DefaultImpls { + public static synthetic fun addSpanEvent$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;ILjava/lang/Object;)Z + public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;ILjava/lang/Object;)Z + public static synthetic fun recordSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Ljava/lang/Object; + public static synthetic fun startSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ILjava/lang/Object;)Ljava/lang/String; + public static synthetic fun stopSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/Long;ILjava/lang/Object;)Z +} + public abstract interface class io/embrace/android/embracesdk/spans/EmbraceSpan { public abstract fun addAttribute (Ljava/lang/String;Ljava/lang/String;)Z public abstract fun addEvent (Ljava/lang/String;)Z @@ -73,3 +90,37 @@ public final class io/embrace/android/embracesdk/spans/ErrorCode : java/lang/Enu public static fun values ()[Lio/embrace/android/embracesdk/spans/ErrorCode; } +public abstract interface class io/embrace/android/embracesdk/spans/TracingApi { + public abstract fun createSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public abstract fun createSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public abstract fun getSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public abstract fun isTracingAvailable ()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/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public abstract fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public abstract fun recordSpan (Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public abstract fun recordSpan (Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public abstract fun startSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public abstract fun startSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public abstract fun startSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/lang/Long;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; +} + +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/EmbraceSpan; + 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/EmbraceSpan;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;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public static fun recordSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; + public static fun startSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; + public static fun startSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; +} + diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/InternalTracingApi.kt b/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/internal/InternalTracingApi.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/InternalTracingApi.kt rename to embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/internal/InternalTracingApi.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/spans/TracingApi.kt b/embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/spans/TracingApi.kt rename to embrace-android-api/src/main/kotlin/io/embrace/android/embracesdk/spans/TracingApi.kt diff --git a/embrace-android-core/build.gradle.kts b/embrace-android-core/build.gradle.kts index 4973a25ccd..6afede3d48 100644 --- a/embrace-android-core/build.gradle.kts +++ b/embrace-android-core/build.gradle.kts @@ -6,6 +6,16 @@ description = "Embrace Android SDK: Core" android { namespace = "io.embrace.android.embracesdk.core" + defaultConfig { + // For library projects only, the BuildConfig.VERSION_NAME and BuildConfig.VERSION_CODE properties have been removed from the generated BuildConfig class + // + // https://developer.android.com/studio/releases/gradle-plugin#version_properties_removed_from_buildconfig_class_in_library_projects + buildConfigField("String", "VERSION_NAME", "\"${version}\"") + buildConfigField("String", "VERSION_CODE", "\"${53}\"") + } + buildFeatures { + buildConfig = true + } } apiValidation.validationDisabled = true @@ -15,6 +25,7 @@ dependencies { compileOnly(project(":embrace-android-api")) compileOnly(platform(libs.opentelemetry.bom)) compileOnly(libs.opentelemetry.api) + compileOnly(libs.opentelemetry.sdk) compileOnly(libs.opentelemetry.semconv) compileOnly(libs.opentelemetry.semconv.incubating) compileOnly(libs.lifecycle.common.java8) diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt new file mode 100644 index 0000000000..d351a7503b --- /dev/null +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt @@ -0,0 +1,16 @@ +package io.embrace.android.embracesdk.internal.arch.schema + +/** + * Attribute that stores the reason an app instance terminated + */ +public sealed class AppTerminationCause( + override val value: String +) : FixedAttribute { + override val key: EmbraceAttributeKey = EmbraceAttributeKey(id = "termination_cause") + + public object Crash : AppTerminationCause("crash") + + public object UserTermination : AppTerminationCause("user_termination") + + public object Unknown : AppTerminationCause("unknown") +} diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt similarity index 77% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt index 62032970de..4c32292fb3 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/injection/OpenTelemetryModule.kt @@ -16,72 +16,72 @@ import io.opentelemetry.api.trace.TracerProvider /** * Module that instantiates various OpenTelemetry related components */ -internal interface OpenTelemetryModule { +public interface OpenTelemetryModule { /** * Configuration for the OpenTelemetry SDK */ - val openTelemetryConfiguration: OpenTelemetryConfiguration + public val openTelemetryConfiguration: OpenTelemetryConfiguration /** * Caches span instances that are in progress or completed in the current session */ - val spanRepository: SpanRepository + public val spanRepository: SpanRepository /** * Provides storage for completed spans that have not been sent off-device */ - val spanSink: SpanSink + public val spanSink: SpanSink /** * An instance of the OpenTelemetry component obtained from the wrapped SDK to create spans */ - val sdkTracer: Tracer + public val sdkTracer: Tracer /** * Component that manages and provides access to the current session span */ - val currentSessionSpan: CurrentSessionSpan + public val currentSessionSpan: CurrentSessionSpan /** * Service to record spans */ - val spanService: SpanService + public val spanService: SpanService /** * Implementation of public tracing API */ - val embraceTracer: EmbraceTracer + public val embraceTracer: EmbraceTracer /** * Implementation of internal tracing API */ - val internalTracer: InternalTracer + public val internalTracer: InternalTracer /** * An instance of the OpenTelemetry component obtained from the wrapped SDK to create log records */ - val logger: Logger + public val logger: Logger /** * Provides storage for completed logs that have not been forwarded yet to the delivery service */ - val logSink: LogSink + public val logSink: LogSink /** * Provides an [OpenTelemetry] instance that can be used by instrumentation libraries to record telemetry as if it were using the * Embrace APIs. Currently, only the APIs related [Tracer] have operational implementations. Every other method will return no-op * implementations that records no data. */ - val externalOpenTelemetry: OpenTelemetry + public val externalOpenTelemetry: OpenTelemetry /** * Provides [Tracer] instances for instrumentation external to the Embrace SDK to create spans */ - val externalTracerProvider: TracerProvider + public val externalTracerProvider: TracerProvider /** * OpenTelemetry SDK compatible clock based on [clock] */ - val openTelemetryClock: io.opentelemetry.sdk.common.Clock + public val openTelemetryClock: io.opentelemetry.sdk.common.Clock } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt similarity index 96% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt index 4057654d44..6cb103ebfd 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordExporter.kt @@ -9,7 +9,7 @@ import io.opentelemetry.sdk.logs.export.LogRecordExporter /** * Exports the given [LogRecordData] to a [LogSink] */ -internal class EmbraceLogRecordExporter( +public class EmbraceLogRecordExporter( private val logSink: LogSink, private val externalLogRecordExporter: LogRecordExporter ) : LogRecordExporter { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt similarity index 93% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt index 5c80800bbd..fbc39b58a1 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/EmbraceLogRecordProcessor.kt @@ -8,7 +8,7 @@ import io.opentelemetry.sdk.logs.export.LogRecordExporter /** * [LogRecordProcessor] that exports log records it to the given [LogRecordExporter] */ -internal class EmbraceLogRecordProcessor( +public class EmbraceLogRecordProcessor( private val logRecordExporter: LogRecordExporter ) : LogRecordProcessor { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/LogSink.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogSink.kt similarity index 78% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/LogSink.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogSink.kt index c18f73c8e4..f8c913d658 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/logs/LogSink.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/logs/LogSink.kt @@ -8,31 +8,31 @@ import io.opentelemetry.sdk.logs.data.LogRecordData * A service that stores exported logs and provides access to them so they * can be sent off-device at the appropriate cadence. */ -internal interface LogSink { +public interface LogSink { /** * Store [Log] objects to be sent in the nexdt batch. Implementations must support concurrent invocations. */ - fun storeLogs(logs: List): CompletableResultCode + public fun storeLogs(logs: List): CompletableResultCode /** * Returns the list of currently stored [Log] objects, waiting to be sent in the next batch */ - fun completedLogs(): List + public fun completedLogs(): List /** * Returns and clears the currently stored [Log] objects, to be used when the next batch is to be sent. * Implementations of this method must make sure the clearing and returning is atomic, i.e. logs cannot be added during this operation. */ - fun flushLogs(): List + public fun flushLogs(): List /** * Return a [Log] that is to be sent immediately rather than batched */ - fun pollNonbatchedLog(): Log? + public fun pollNonbatchedLog(): Log? /** * Registers a callback to be called after new logs are stored. */ - fun registerLogStoredCallback(onLogsStored: () -> Unit) + public fun registerLogStoredCallback(onLogsStored: () -> Unit) } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt similarity index 51% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt index 78759ab918..0bed840de3 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/EmbraceAttributeKeys.kt @@ -6,94 +6,94 @@ import io.embrace.android.embracesdk.internal.payload.ThreadInfo /** * A snapshot of the current call stack of the threads running in the app process per [ThreadInfo] */ -internal val embAndroidThreads = EmbraceAttributeKey("android.threads") +public val embAndroidThreads: EmbraceAttributeKey = EmbraceAttributeKey("android.threads") /** * Sequence number for the number of crashes captured by Embrace on the device, reported on every crash */ -internal val embCrashNumber = EmbraceAttributeKey("android.crash_number") +public val embCrashNumber: EmbraceAttributeKey = EmbraceAttributeKey("android.crash_number") /** * Attribute name for the exception handling type - whether it's handled or unhandled */ -internal val embExceptionHandling = EmbraceAttributeKey("exception_handling") +public val embExceptionHandling: EmbraceAttributeKey = EmbraceAttributeKey("exception_handling") /** * Monotonically increasing sequence ID given to completed span that is expected to be sent to the server */ -internal val embProcessIdentifier: EmbraceAttributeKey = EmbraceAttributeKey("process_identifier") +public val embProcessIdentifier: EmbraceAttributeKey = EmbraceAttributeKey("process_identifier") /** * Attribute name for the unique ID assigned to each app instance */ -internal val embSequenceId: EmbraceAttributeKey = EmbraceAttributeKey(id = "sequence_id", isPrivate = true) +public val embSequenceId: EmbraceAttributeKey = EmbraceAttributeKey(id = "sequence_id", isPrivate = true) /** * Attribute name for the application state (foreground/background) at the time the log was recorded */ -internal val embState = EmbraceAttributeKey("state") +public val embState: EmbraceAttributeKey = EmbraceAttributeKey("state") /** * Attribute name for whether the session is a cold start */ -internal val embColdStart = EmbraceAttributeKey("cold_start") +public val embColdStart: EmbraceAttributeKey = EmbraceAttributeKey("cold_start") /** * Attribute name for session number (integer sequence ID) */ -internal val embSessionNumber = EmbraceAttributeKey("session_number") +public val embSessionNumber: EmbraceAttributeKey = EmbraceAttributeKey("session_number") /** * Attribute name that indicates whether the session was ended by the SDK or an unexpected termination */ -internal val embCleanExit = EmbraceAttributeKey("clean_exit") +public val embCleanExit: EmbraceAttributeKey = EmbraceAttributeKey("clean_exit") /** * Attribute name that indicates whether the session was terminated */ -internal val embTerminated = EmbraceAttributeKey("terminated") +public val embTerminated: EmbraceAttributeKey = EmbraceAttributeKey("terminated") /** * Attribute name that represents last known time that the session existed (nanoseconds since epoch) */ -internal val embHeartbeatTimeUnixNano = EmbraceAttributeKey("heartbeat_time_unix_nano") +public val embHeartbeatTimeUnixNano: EmbraceAttributeKey = EmbraceAttributeKey("heartbeat_time_unix_nano") /** * Attribute name that identifies the crash report tied to the session */ -internal val embCrashId = EmbraceAttributeKey("crash_id") +public val embCrashId: EmbraceAttributeKey = EmbraceAttributeKey("crash_id") /** * Attribute name that identifies the session start type */ -internal val embSessionStartType = EmbraceAttributeKey("session_start_type") +public val embSessionStartType: EmbraceAttributeKey = EmbraceAttributeKey("session_start_type") /** * Attribute name that identifies the session end type */ -internal val embSessionEndType = EmbraceAttributeKey("session_end_type") +public val embSessionEndType: EmbraceAttributeKey = EmbraceAttributeKey("session_end_type") /** * Attribute name that identifies the startup duration */ -internal val embSessionStartupDuration = EmbraceAttributeKey("startup_duration") +public val embSessionStartupDuration: EmbraceAttributeKey = EmbraceAttributeKey("startup_duration") /** * Attribute name that identifies the startup threshold */ -internal val embSessionStartupThreshold = EmbraceAttributeKey("threshold") +public val embSessionStartupThreshold: EmbraceAttributeKey = EmbraceAttributeKey("threshold") /** * Attribute name that identifies the SDK duration */ -internal val embSdkStartupDuration = EmbraceAttributeKey("sdk_startup_duration") +public val embSdkStartupDuration: EmbraceAttributeKey = EmbraceAttributeKey("sdk_startup_duration") /** * Attribute name that identifies the error log count in a session */ -internal val embErrorLogCount = EmbraceAttributeKey("error_log_count") +public val embErrorLogCount: EmbraceAttributeKey = EmbraceAttributeKey("error_log_count") /** * Attribute name that identifies the number of free bytes on disk */ -internal val embFreeDiskBytes = EmbraceAttributeKey("disk_free_bytes") +public val embFreeDiskBytes: EmbraceAttributeKey = EmbraceAttributeKey("disk_free_bytes") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt similarity index 81% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt index 7b88abc967..460a6511e0 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/opentelemetry/OpenTelemetryConfiguration.kt @@ -1,6 +1,6 @@ package io.embrace.android.embracesdk.internal.opentelemetry -import io.embrace.android.embracesdk.BuildConfig +import io.embrace.android.embracesdk.core.BuildConfig import io.embrace.android.embracesdk.internal.SystemInfo import io.embrace.android.embracesdk.internal.logs.EmbraceLogRecordExporter import io.embrace.android.embracesdk.internal.logs.EmbraceLogRecordProcessor @@ -19,15 +19,15 @@ import io.opentelemetry.semconv.incubating.DeviceIncubatingAttributes import io.opentelemetry.semconv.incubating.OsIncubatingAttributes import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes -internal class OpenTelemetryConfiguration( +public class OpenTelemetryConfiguration( spanSink: SpanSink, logSink: LogSink, systemInfo: SystemInfo, processIdentifier: String ) { - val embraceSdkName = BuildConfig.LIBRARY_PACKAGE_NAME - val embraceSdkVersion = BuildConfig.VERSION_NAME - val resource: Resource = Resource.getDefault().toBuilder() + public val embraceSdkName: String = BuildConfig.LIBRARY_PACKAGE_NAME + public val embraceSdkVersion: String = BuildConfig.VERSION_NAME + public val resource: Resource = Resource.getDefault().toBuilder() .put(ServiceAttributes.SERVICE_NAME, embraceSdkName) .put(ServiceAttributes.SERVICE_VERSION, embraceSdkVersion) .put(OsIncubatingAttributes.OS_NAME, systemInfo.osName) @@ -45,7 +45,7 @@ internal class OpenTelemetryConfiguration( private val externalSpanExporters = mutableListOf() private val externalLogExporters = mutableListOf() - val spanProcessor: SpanProcessor by lazy { + public val spanProcessor: SpanProcessor by lazy { EmbraceSpanProcessor( EmbraceSpanExporter( spanSink = spanSink, @@ -55,7 +55,7 @@ internal class OpenTelemetryConfiguration( ) } - val logProcessor: LogRecordProcessor by lazy { + public val logProcessor: LogRecordProcessor by lazy { EmbraceLogRecordProcessor( EmbraceLogRecordExporter( logSink = logSink, @@ -64,13 +64,13 @@ internal class OpenTelemetryConfiguration( ) } - fun addSpanExporter(spanExporter: SpanExporter) { + public fun addSpanExporter(spanExporter: SpanExporter) { externalSpanExporters.add(spanExporter) } - fun addLogExporter(logExporter: LogRecordExporter) { + public fun addLogExporter(logExporter: LogRecordExporter) { externalLogExporters.add(logExporter) } - fun hasConfiguredOtelExporters() = externalLogExporters.isNotEmpty() || externalSpanExporters.isNotEmpty() + public fun hasConfiguredOtelExporters(): Boolean = externalLogExporters.isNotEmpty() || externalSpanExporters.isNotEmpty() } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt similarity index 65% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt index cf257866a8..a902a04b41 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/CurrentSessionSpan.kt @@ -8,19 +8,22 @@ import io.embrace.android.embracesdk.spans.EmbraceSpan /** * Abstraction of the current session span */ -internal interface CurrentSessionSpan : Initializable, SessionSpanWriter { +public interface CurrentSessionSpan : Initializable, SessionSpanWriter { /** * End the current session span and start a new one if the app is not terminating */ - fun endSession(startNewSession: Boolean, appTerminationCause: AppTerminationCause? = null): List + public fun endSession( + startNewSession: Boolean, + appTerminationCause: AppTerminationCause? = null + ): List /** * Returns true if a span with the given parameters can be started in the current session */ - fun canStartNewSpan(parent: EmbraceSpan?, internal: Boolean): Boolean + public fun canStartNewSpan(parent: EmbraceSpan?, internal: Boolean): Boolean /** * Returns the current session ID */ - fun getSessionId(): String + public fun getSessionId(): String } diff --git a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt index aafc02aeeb..577949df90 100644 --- a/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt @@ -1,6 +1,12 @@ package io.embrace.android.embracesdk.internal.spans +import io.embrace.android.embracesdk.internal.arch.schema.EmbraceAttributeKey +import io.embrace.android.embracesdk.internal.arch.schema.FixedAttribute +import io.opentelemetry.api.common.Attributes import io.opentelemetry.api.logs.Severity +import io.opentelemetry.api.trace.Span +import io.opentelemetry.sdk.logs.data.LogRecordData +import io.opentelemetry.sdk.trace.data.SpanData /** * Prefix added to OTel signal object names recorded by the SDK @@ -27,3 +33,26 @@ public fun io.embrace.android.embracesdk.Severity.toOtelSeverity(): Severity = w * Return the appropriate internal Embrace attribute usage name given the current string */ internal fun String.toEmbraceUsageAttributeName(): String = EMBRACE_USAGE_ATTRIBUTE_NAME_PREFIX + this + +/** + * Returns the attributes as a new Map + */ +public fun Attributes.toStringMap(): Map = asMap().entries.associate { + it.key.key.toString() to it.value.toString() +} + +public fun EmbraceSpanData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = + fixedAttribute.value == attributes[fixedAttribute.key.name] + +internal fun Span.setEmbraceAttribute(key: EmbraceAttributeKey, value: String): Span { + setAttribute(key.name, value) + return this +} + +public fun Span.setFixedAttribute(fixedAttribute: FixedAttribute): Span = setEmbraceAttribute(fixedAttribute.key, fixedAttribute.value) + +internal fun SpanData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = + attributes.asMap()[fixedAttribute.key.attributeKey] == fixedAttribute.value + +public fun LogRecordData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = + attributes[fixedAttribute.key.attributeKey] == fixedAttribute.value diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt similarity index 63% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt index 830448b338..4e8df47e8d 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanData.kt @@ -4,12 +4,11 @@ import io.embrace.android.embracesdk.internal.clock.nanosToMillis import io.embrace.android.embracesdk.spans.EmbraceSpanEvent import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.sdk.trace.data.EventData -import io.opentelemetry.sdk.trace.data.SpanData /** * Serializable representation of [EmbraceSpanData] */ -internal data class EmbraceSpanData( +public data class EmbraceSpanData( val traceId: String, val spanId: String, @@ -28,20 +27,9 @@ internal data class EmbraceSpanData( val attributes: Map = emptyMap() ) { - internal constructor(spanData: SpanData) : this( - traceId = spanData.spanContext.traceId, - spanId = spanData.spanContext.spanId, - parentSpanId = spanData.parentSpanId, - name = spanData.name, - startTimeNanos = spanData.startEpochNanos, - endTimeNanos = spanData.endEpochNanos, - status = spanData.status.statusCode, - events = fromEventData(eventDataList = spanData.events), - attributes = spanData.attributes.toStringMap(), - ) - - companion object { - fun fromEventData(eventDataList: List?): List { + + public companion object { + public fun fromEventData(eventDataList: List?): List { val events = mutableListOf() eventDataList?.forEach { eventData -> val event = EmbraceSpanEvent.create( diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanExporter.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanExporter.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanExporter.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanExporter.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanProcessor.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanProcessor.kt similarity index 100% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanProcessor.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanProcessor.kt diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt similarity index 96% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt index cf78901a5d..e3a98cb655 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceTracer.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.spans.EmbraceSpanEvent import io.embrace.android.embracesdk.spans.ErrorCode import io.embrace.android.embracesdk.spans.TracingApi -internal class EmbraceTracer( +public class EmbraceTracer( private val clock: Clock, private val spanService: SpanService, ) : TracingApi { @@ -70,7 +70,7 @@ internal class EmbraceTracer( * Return the current time in millis for the clock instance used by the Embrace SDK. This should be used to obtain the time * in used for [recordCompletedSpan] so the timestamps will be in sync with those used by the SDK when a time is implicitly recorded. */ - fun getSdkCurrentTimeMs(): Long = clock.now() + public fun getSdkCurrentTimeMs(): Long = clock.now() @Deprecated("Not required. Use Embrace.isStarted() to know when the full tracing API is available") override fun isTracingAvailable(): Boolean = spanService.initialized() diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt similarity index 99% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt index bfc09a2e6a..7da281b0b5 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/InternalTracer.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.spans.EmbraceSpan import io.embrace.android.embracesdk.spans.EmbraceSpanEvent import io.embrace.android.embracesdk.spans.ErrorCode -internal class InternalTracer( +public class InternalTracer( private val spanRepository: SpanRepository, private val embraceTracer: EmbraceTracer, ) : InternalTracingApi { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt similarity index 83% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt index 3ce31ad010..fea43db75e 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanRepository.kt @@ -10,7 +10,7 @@ import java.util.concurrent.atomic.AtomicInteger /** * Allows the tracking of [EmbraceSpan] instances so that their references can be retrieved with its associated spanId */ -internal class SpanRepository { +public class SpanRepository { private val activeSpans: MutableMap = ConcurrentHashMap() private val completedSpans: MutableMap = mutableMapOf() private val spanIdsInProcess: MutableMap = ConcurrentHashMap() @@ -18,7 +18,7 @@ internal class SpanRepository { /** * Track the [EmbraceSpan] if it has been started and it's not already tracked. */ - fun trackStartedSpan(embraceSpan: PersistableEmbraceSpan) { + public fun trackStartedSpan(embraceSpan: PersistableEmbraceSpan) { val spanId = embraceSpan.spanId ?: return if (notTracked(spanId)) { @@ -37,7 +37,7 @@ internal class SpanRepository { /** * Transition active span to completed span if the span is tracked and the span is actually stopped. */ - fun trackedSpanStopped(spanId: String) { + public fun trackedSpanStopped(spanId: String) { spanIdsInProcess.lockAndRun(spanId) { activeSpans[spanId]?.takeIf { !it.isRecording }?.let { activeSpans.remove(spanId) }?.let { embraceSpan -> completedSpans[spanId] = embraceSpan @@ -48,7 +48,7 @@ internal class SpanRepository { /** * Return the [EmbraceSpan] with the corresponding [spanId] if it's tracked. Return null otherwise. */ - fun getSpan(spanId: String): EmbraceSpan? = + public fun getSpan(spanId: String): EmbraceSpan? = spanIdsInProcess.lockAndRun(spanId) { activeSpans[spanId] ?: completedSpans[spanId] } @@ -56,19 +56,21 @@ internal class SpanRepository { /** * Get a list of active spans that are being tracked */ - fun getActiveSpans(): List = synchronized(spanIdsInProcess) { activeSpans.values.toList() } + public fun getActiveSpans(): List = synchronized(spanIdsInProcess) { + activeSpans.values.toList() + } /** * Get a list of completed spans that are being tracked. */ - fun getCompletedSpans(): List = synchronized(spanIdsInProcess) { + public fun getCompletedSpans(): List = synchronized(spanIdsInProcess) { completedSpans.values.toList() } /** * Stop the existing active spans and mark them as failed */ - fun failActiveSpans(failureTimeMs: Long) { + public fun failActiveSpans(failureTimeMs: Long) { getActiveSpans().filterNot { it.hasFixedAttribute(EmbType.Ux.Session) }.forEach { span -> span.stop(ErrorCode.FAILURE, failureTimeMs) } @@ -77,7 +79,7 @@ internal class SpanRepository { /** * Clear the spans this repository is tracking */ - fun clearCompletedSpans() { + public fun clearCompletedSpans() { synchronized(spanIdsInProcess) { completedSpans.clear() } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSink.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanSink.kt similarity index 78% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSink.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanSink.kt index aeb66dbe97..e2a247edb2 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSink.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanSink.kt @@ -7,20 +7,20 @@ import io.opentelemetry.sdk.trace.data.SpanData * A service that stores all the spans that are completed and exported via [EmbraceSpanExporter], and provides access to them so they * can be sent off-device at the appropriate cadence. */ -internal interface SpanSink { +public interface SpanSink { /** * Stores spans that have been completed. Implementations must support concurrent invocations. */ - fun storeCompletedSpans(spans: List): CompletableResultCode + public fun storeCompletedSpans(spans: List): CompletableResultCode /** * Returns the list of the currently stored completed spans. */ - fun completedSpans(): List + public fun completedSpans(): List /** * Returns and clears the currently stored completed Spans. Implementations of this method must make sure the clearing and returning is * atomic, i.e. spans cannot be added during this operation. */ - fun flushSpans(): List + public fun flushSpans(): List } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt similarity index 91% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt index 34c081c75c..a2eecf0c41 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/utils/CollectionExtensions.kt @@ -7,7 +7,7 @@ import java.util.concurrent.atomic.AtomicInteger * Returns the element at the specified index. * Returns null if the index is out of bounds, instead of the out-of-bounds exception. */ -internal fun List.at(index: Int): T? { +public fun List.at(index: Int): T? { return if (index >= 0 && index < count()) { this[index] } else { @@ -18,7 +18,7 @@ internal fun List.at(index: Int): T? { /** * Dynamically allocate a set of locks in this map to support mutual exclusion for executing blocks of code when using the same key */ -internal fun MutableMap.lockAndRun(key: String, code: () -> T): T { +public fun MutableMap.lockAndRun(key: String, code: () -> T): T { var lock: AtomicInteger // Find the lock for the given key if it exists - create a new one if it doesn't @@ -52,7 +52,7 @@ internal fun MutableMap.lockAndRun(key: String, code: * or equal to the size of the number of elements requested, but since the underlying data can change after the size check, you can * get more elements than requested if they were added during the [toList] call. */ -internal fun Collection.threadSafeTake(n: Int): List { +public fun Collection.threadSafeTake(n: Int): List { return if (n == 0) { emptyList() } else { diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Log.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Log.kt similarity index 98% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Log.kt rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Log.kt index bfdf3e6293..ec830f1a5c 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Log.kt +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Log.kt @@ -21,7 +21,7 @@ import com.squareup.moshi.JsonClass * processing span. If span_id is present, trace_id SHOULD be also present. */ @JsonClass(generateAdapter = true) -internal data class Log( +public data class Log( /* The time the log was captured, in nanoseconds since the Unix epoch */ @Json(name = "time_unix_nano") diff --git a/embrace-android-sdk/api/embrace-android-sdk.api b/embrace-android-sdk/api/embrace-android-sdk.api index ba7f8336fa..d93df3a812 100644 --- a/embrace-android-sdk/api/embrace-android-sdk.api +++ b/embrace-android-sdk/api/embrace-android-sdk.api @@ -204,23 +204,6 @@ public abstract interface class io/embrace/android/embracesdk/internal/EmbraceIn public abstract fun stopSdk ()V } -public abstract interface class io/embrace/android/embracesdk/internal/InternalTracingApi { - public abstract fun addSpanAttribute (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z - public abstract fun addSpanEvent (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;)Z - public abstract fun recordCompletedSpan (Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;)Z - public abstract fun recordSpan (Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public abstract fun startSpan (Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;)Ljava/lang/String; - public abstract fun stopSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/Long;)Z -} - -public final class io/embrace/android/embracesdk/internal/InternalTracingApi$DefaultImpls { - public static synthetic fun addSpanEvent$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/util/Map;ILjava/lang/Object;)Z - public static synthetic fun recordCompletedSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;JJLio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;ILjava/lang/Object;)Z - public static synthetic fun recordSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Ljava/lang/Object; - public static synthetic fun startSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Long;ILjava/lang/Object;)Ljava/lang/String; - public static synthetic fun stopSpan$default (Lio/embrace/android/embracesdk/internal/InternalTracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/ErrorCode;Ljava/lang/Long;ILjava/lang/Object;)Z -} - public abstract interface class io/embrace/android/embracesdk/internal/api/BreadcrumbApi { public abstract fun addBreadcrumb (Ljava/lang/String;)V } @@ -423,37 +406,3 @@ public final class io/embrace/android/embracesdk/network/http/HttpMethod : java/ public static fun values ()[Lio/embrace/android/embracesdk/network/http/HttpMethod; } -public abstract interface class io/embrace/android/embracesdk/spans/TracingApi { - public abstract fun createSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun createSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun getSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun isTracingAvailable ()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/EmbraceSpan;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public abstract fun recordSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public abstract fun recordSpan (Ljava/lang/String;Ljava/util/Map;Ljava/util/List;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public abstract fun recordSpan (Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public abstract fun startSpan (Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun startSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public abstract fun startSpan (Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;Ljava/lang/Long;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; -} - -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/EmbraceSpan; - 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/EmbraceSpan;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;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public static fun recordSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Ljava/lang/Object; - public static fun startSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; - public static fun startSpan (Lio/embrace/android/embracesdk/spans/TracingApi;Ljava/lang/String;Lio/embrace/android/embracesdk/spans/EmbraceSpan;)Lio/embrace/android/embracesdk/spans/EmbraceSpan; -} - diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/assertions/InternalErrorAssertions.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/assertions/InternalErrorAssertions.kt index 1f623e8ce4..a0816f34d6 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/assertions/InternalErrorAssertions.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/assertions/InternalErrorAssertions.kt @@ -27,8 +27,9 @@ internal fun assertInternalErrorLogged( } val matchingLogs = logs.filter { log -> - log.attributes?.findAttributeValue(ExceptionAttributes.EXCEPTION_TYPE.key) == exceptionClassName && - log.attributes.findAttributeValue(ExceptionAttributes.EXCEPTION_MESSAGE.key) == errorMessage + val attrs = log.attributes + attrs?.findAttributeValue(ExceptionAttributes.EXCEPTION_TYPE.key) == exceptionClassName && + attrs.findAttributeValue(ExceptionAttributes.EXCEPTION_MESSAGE.key) == errorMessage } if (matchingLogs.isEmpty()) { fail("No internal errors found matching the expected exception") diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ExternalTracerTest.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ExternalTracerTest.kt index 88971a591e..3471137aa8 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ExternalTracerTest.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/testcases/ExternalTracerTest.kt @@ -15,6 +15,7 @@ import io.embrace.android.embracesdk.internal.utils.truncatedStacktraceText import io.embrace.android.embracesdk.internal.opentelemetry.EmbSpan import io.embrace.android.embracesdk.internal.opentelemetry.EmbSpanBuilder import io.embrace.android.embracesdk.internal.opentelemetry.EmbTracer +import io.embrace.android.embracesdk.internal.spans.toEmbraceSpanData import io.embrace.android.embracesdk.recordSession import io.embrace.android.embracesdk.spans.ErrorCode import io.opentelemetry.api.OpenTelemetry @@ -159,7 +160,7 @@ internal class ExternalTracerTest { assertTrue("Timed out waiting for the span to be exported", spanExporter.awaitSpanExport(3)) val exportedSpan: SpanData = spanExporter.exportedSpans.single { it.name == "external-span" } - assertEquals(parent.toOldPayload(), EmbraceSpanData(exportedSpan)) + assertEquals(parent.toOldPayload(), exportedSpan.toEmbraceSpanData()) with(exportedSpan.instrumentationScopeInfo) { assertEquals("external-tracer", name) assertEquals("1.0.0", version) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt deleted file mode 100644 index 32d3b74191..0000000000 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/schema/AppTerminationCause.kt +++ /dev/null @@ -1,16 +0,0 @@ -package io.embrace.android.embracesdk.internal.arch.schema - -/** - * Attribute that stores the reason an app instance terminated - */ -internal sealed class AppTerminationCause( - override val value: String -) : FixedAttribute { - override val key = EmbraceAttributeKey(id = "termination_cause") - - internal object Crash : AppTerminationCause("crash") - - internal object UserTermination : AppTerminationCause("user_termination") - - internal object Unknown : AppTerminationCause("unknown") -} diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt index 01b63de0bb..bb1604ccec 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceExtensions.kt @@ -9,15 +9,12 @@ import io.embrace.android.embracesdk.internal.payload.SpanEvent import io.embrace.android.embracesdk.spans.EmbraceSpan import io.embrace.android.embracesdk.spans.EmbraceSpanEvent import io.opentelemetry.api.common.AttributeKey -import io.opentelemetry.api.common.Attributes import io.opentelemetry.api.common.AttributesBuilder import io.opentelemetry.api.logs.LogRecordBuilder import io.opentelemetry.api.trace.Span import io.opentelemetry.api.trace.SpanBuilder import io.opentelemetry.api.trace.StatusCode import io.opentelemetry.api.trace.Tracer -import io.opentelemetry.sdk.logs.data.LogRecordData -import io.opentelemetry.sdk.trace.data.SpanData import io.opentelemetry.semconv.ExceptionAttributes /** @@ -44,25 +41,11 @@ internal fun Tracer.embraceSpanBuilder( parentSpan = parent, ) -internal fun Span.setEmbraceAttribute(key: EmbraceAttributeKey, value: String): Span { - setAttribute(key.name, value) - return this -} - -internal fun Span.setFixedAttribute(fixedAttribute: FixedAttribute): Span = setEmbraceAttribute(fixedAttribute.key, fixedAttribute.value) - internal fun LogRecordBuilder.setFixedAttribute(fixedAttribute: FixedAttribute): LogRecordBuilder { setAttribute(fixedAttribute.key.attributeKey, fixedAttribute.value) return this } -/** - * Returns the attributes as a new Map - */ -internal fun Attributes.toStringMap(): Map = asMap().entries.associate { - it.key.key.toString() to it.value.toString() -} - /** * Populate an [AttributesBuilder] with String key-value pairs from a [Map] */ @@ -73,15 +56,6 @@ internal fun AttributesBuilder.fromMap(attributes: Map): Attribu return this } -internal fun SpanData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = - attributes.asMap()[fixedAttribute.key.attributeKey] == fixedAttribute.value - -internal fun LogRecordData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = - attributes[fixedAttribute.key.attributeKey] == fixedAttribute.value - -internal fun EmbraceSpanData.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean = - fixedAttribute.value == attributes[fixedAttribute.key.name] - internal fun io.embrace.android.embracesdk.internal.payload.Span.hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean { return fixedAttribute.value == attributes?.singleOrNull { it.key == fixedAttribute.key.name }?.data } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanDataExt.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanDataExt.kt new file mode 100644 index 0000000000..f2300ef2ba --- /dev/null +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanDataExt.kt @@ -0,0 +1,16 @@ +package io.embrace.android.embracesdk.internal.spans + +import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData.Companion.fromEventData +import io.opentelemetry.sdk.trace.data.SpanData + +internal fun SpanData.toEmbraceSpanData() = EmbraceSpanData( + traceId = spanContext.traceId, + spanId = spanContext.spanId, + parentSpanId = parentSpanId, + name = name, + startTimeNanos = startEpochNanos, + endTimeNanos = endEpochNanos, + status = status.statusCode, + events = fromEventData(eventDataList = events), + attributes = attributes.toStringMap(), +) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSinkImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSinkImpl.kt index 42525fb941..fa96a7db64 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSinkImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanSinkImpl.kt @@ -13,7 +13,7 @@ internal class SpanSinkImpl : SpanSink { override fun storeCompletedSpans(spans: List): CompletableResultCode { try { - completedSpans += spans.map { EmbraceSpanData(spanData = it) } + completedSpans += spans.map { it.toEmbraceSpanData() } } catch (t: Throwable) { return CompletableResultCode.ofFailure() } diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceDeliveryServiceTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceDeliveryServiceTest.kt index 3064396ea6..23e2aa2c77 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceDeliveryServiceTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/comms/delivery/EmbraceDeliveryServiceTest.kt @@ -41,6 +41,7 @@ import io.embrace.android.embracesdk.internal.session.orchestrator.SessionSnapsh import io.embrace.android.embracesdk.internal.session.orchestrator.SessionSnapshotType.NORMAL_END import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData import io.embrace.android.embracesdk.internal.spans.findAttributeValue +import io.embrace.android.embracesdk.internal.spans.toEmbraceSpanData import io.embrace.android.embracesdk.internal.worker.BackgroundWorker import io.embrace.android.embracesdk.spans.ErrorCode import io.opentelemetry.api.trace.SpanId @@ -194,7 +195,7 @@ internal class EmbraceDeliveryServiceTest { @Test fun `do not add failed span from a snapshot if a span with the same id is already in the payload`() { - val startedSnapshot = EmbraceSpanData(perfSpanSnapshot) + val startedSnapshot = perfSpanSnapshot.toEmbraceSpanData() val completedSpan = startedSnapshot.copy(endTimeNanos = startedSnapshot.startTimeNanos + 10000000L) val snapshots = listOfNotNull(startedSnapshot) val base = fakeSessionEnvelope() diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeCurrentSessionSpan.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeCurrentSessionSpan.kt index 7bfa551221..206af0a5d3 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeCurrentSessionSpan.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeCurrentSessionSpan.kt @@ -7,6 +7,7 @@ import io.embrace.android.embracesdk.internal.arch.schema.SchemaType import io.embrace.android.embracesdk.internal.clock.millisToNanos import io.embrace.android.embracesdk.internal.spans.CurrentSessionSpan import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData +import io.embrace.android.embracesdk.internal.spans.toEmbraceSpanData import io.embrace.android.embracesdk.spans.EmbraceSpan import io.opentelemetry.sdk.trace.data.StatusData import java.util.concurrent.atomic.AtomicInteger @@ -52,7 +53,7 @@ internal class FakeCurrentSessionSpan( endingSessionSpan.spanStatus = if (appTerminationCause == null) StatusData.ok() else StatusData.error() sessionIteration.incrementAndGet() sessionSpan = if (appTerminationCause == null) newSessionSpan(clock.now()) else null - return listOf(EmbraceSpanData((endingSessionSpan))) + return listOf((endingSessionSpan).toEmbraceSpanData()) } override fun canStartNewSpan(parent: EmbraceSpan?, internal: Boolean): Boolean { diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/payload/SpanMapperTest.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/payload/SpanMapperTest.kt index bd36840687..42702954f2 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/payload/SpanMapperTest.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/internal/payload/SpanMapperTest.kt @@ -7,7 +7,7 @@ import io.embrace.android.embracesdk.arch.assertNotPrivateSpan import io.embrace.android.embracesdk.arch.assertSuccessful import io.embrace.android.embracesdk.fakes.FakeSpanData import io.embrace.android.embracesdk.internal.clock.nanosToMillis -import io.embrace.android.embracesdk.internal.spans.EmbraceSpanData +import io.embrace.android.embracesdk.internal.spans.toEmbraceSpanData import io.embrace.android.embracesdk.spans.ErrorCode import io.opentelemetry.api.trace.StatusCode import org.junit.Assert.assertEquals @@ -17,7 +17,7 @@ internal class SpanMapperTest { @Test fun toSpan() { - val input = EmbraceSpanData(FakeSpanData.perfSpanCompleted) + val input = FakeSpanData.perfSpanCompleted.toEmbraceSpanData() val output = input.toNewPayload() assertEquals(input.traceId, output.traceId) @@ -45,7 +45,7 @@ internal class SpanMapperTest { @Test fun `terminating span snapshot works as expected`() { - val snapshot = EmbraceSpanData(FakeSpanData.perfSpanSnapshot).toNewPayload() + val snapshot = FakeSpanData.perfSpanSnapshot.toEmbraceSpanData().toNewPayload() val terminationTimeMs = snapshot.startTimeNanos!!.nanosToMillis() + 60000L val failedSpan = snapshot.toFailedSpan(terminationTimeMs) @@ -69,7 +69,7 @@ internal class SpanMapperTest { @Test fun `terminating span snapshot as old payload works as expected`() { - val snapshot = EmbraceSpanData(FakeSpanData.perfSpanSnapshot) + val snapshot = FakeSpanData.perfSpanSnapshot.toEmbraceSpanData() val terminationTimeMs = snapshot.startTimeNanos.nanosToMillis() + 60000L val failedSpan = snapshot.toFailedSpan(terminationTimeMs) From f70d802e887117a865f4ba776d031375396c3771 Mon Sep 17 00:00:00 2001 From: Jamie Lynch Date: Fri, 26 Jul 2024 12:23:41 +0100 Subject: [PATCH 3/3] refactor: move declaration of data source to feature module --- .../internal/capture/FeatureModule.kt | 43 +++++++++++++++++++ .../injection/DataSourceModuleImpl.kt | 38 ++++++---------- 2 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/FeatureModule.kt diff --git a/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/FeatureModule.kt b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/FeatureModule.kt new file mode 100644 index 0000000000..c3d15c3f15 --- /dev/null +++ b/embrace-android-features/src/main/kotlin/io/embrace/android/embracesdk/internal/capture/FeatureModule.kt @@ -0,0 +1,43 @@ +package io.embrace.android.embracesdk.internal.capture + +import io.embrace.android.embracesdk.internal.arch.datasource.DataSourceState +import io.embrace.android.embracesdk.internal.capture.crumbs.BreadcrumbDataSource +import io.embrace.android.embracesdk.internal.capture.memory.MemoryWarningDataSource +import io.embrace.android.embracesdk.internal.config.ConfigService +import io.embrace.android.embracesdk.internal.injection.CoreModule +import io.embrace.android.embracesdk.internal.injection.InitModule +import io.embrace.android.embracesdk.internal.injection.OpenTelemetryModule +import io.embrace.android.embracesdk.internal.injection.singleton + +public class FeatureModule( + coreModule: CoreModule, + initModule: InitModule, + otelModule: OpenTelemetryModule, + configService: ConfigService +) { + public val memoryWarningDataSource: DataSourceState by singleton { + DataSourceState( + factory = { + MemoryWarningDataSource( + application = coreModule.application, + clock = initModule.clock, + sessionSpanWriter = otelModule.currentSessionSpan, + logger = initModule.logger, + ) + }, + configGate = { configService.autoDataCaptureBehavior.isMemoryServiceEnabled() }, + ) + } + + public val breadcrumbDataSource: DataSourceState by singleton { + DataSourceState( + factory = { + BreadcrumbDataSource( + breadcrumbBehavior = configService.breadcrumbBehavior, + writer = otelModule.currentSessionSpan, + logger = initModule.logger + ) + } + ) + } +} diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt index 150719d697..0c1e329c7a 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/injection/DataSourceModuleImpl.kt @@ -6,6 +6,7 @@ import io.embrace.android.embracesdk.internal.arch.DataCaptureOrchestrator import io.embrace.android.embracesdk.internal.arch.EmbraceFeatureRegistry import io.embrace.android.embracesdk.internal.arch.datasource.DataSource import io.embrace.android.embracesdk.internal.arch.datasource.DataSourceState +import io.embrace.android.embracesdk.internal.capture.FeatureModule import io.embrace.android.embracesdk.internal.capture.aei.AeiDataSource import io.embrace.android.embracesdk.internal.capture.aei.AeiDataSourceImpl import io.embrace.android.embracesdk.internal.capture.connectivity.NetworkStatusDataSource @@ -40,6 +41,15 @@ internal class DataSourceModuleImpl( private val configService = essentialServiceModule.configService + private val featureModule: FeatureModule by singleton { + FeatureModule( + coreModule, + initModule, + otelModule, + configService + ) + } + override val dataCaptureOrchestrator: DataCaptureOrchestrator by singleton { DataCaptureOrchestrator( configService, @@ -50,17 +60,7 @@ internal class DataSourceModuleImpl( override val embraceFeatureRegistry: EmbraceFeatureRegistry = dataCaptureOrchestrator - override val breadcrumbDataSource: DataSourceState by dataSourceState { - DataSourceState( - factory = { - BreadcrumbDataSource( - breadcrumbBehavior = configService.breadcrumbBehavior, - writer = otelModule.currentSessionSpan, - logger = initModule.logger - ) - } - ) - } + override val breadcrumbDataSource: DataSourceState by dataSourceState(featureModule::breadcrumbDataSource) override val tapDataSource: DataSourceState by dataSourceState { DataSourceState( @@ -125,19 +125,9 @@ internal class DataSourceModuleImpl( ) } - override val memoryWarningDataSource: DataSourceState by dataSourceState { - DataSourceState( - factory = { - MemoryWarningDataSource( - application = coreModule.application, - clock = initModule.clock, - sessionSpanWriter = otelModule.currentSessionSpan, - logger = initModule.logger, - ) - }, - configGate = { configService.autoDataCaptureBehavior.isMemoryServiceEnabled() } - ) - } + override val memoryWarningDataSource: DataSourceState by dataSourceState( + featureModule::memoryWarningDataSource + ) private val aeiService: AeiDataSourceImpl? by singleton { if (BuildVersionChecker.isAtLeast(Build.VERSION_CODES.R)) {