From 9371fdf7ce887da57f935291b7d93a44cd27d329 Mon Sep 17 00:00:00 2001 From: Jamie Lynch Date: Fri, 19 Jul 2024 16:51:04 +0100 Subject: [PATCH] refactor: modularise span data source --- .../arch/datasource/SpanDataSource.kt | 6 ++-- .../embracesdk/internal/spans/EmbraceExt.kt | 11 +++++++ .../internal/spans/EmbraceSpanBuilder.kt | 26 ++++++++-------- .../internal/spans/PersistableEmbraceSpan.kt | 20 ++++++------ .../embracesdk/internal/spans/SpanService.kt | 15 ++++----- .../embracesdk/internal/payload/Span.kt | 7 ++--- .../embracesdk/internal/payload/SpanEvent.kt | 2 +- .../android/embracesdk/SpanAssertions.kt | 12 +++---- .../testcases/NetworkRequestApiTest.kt | 1 - .../embracesdk/testcases/TracingApiTest.kt | 9 +++--- .../internal/gating/SpanSanitizer.kt | 3 +- .../embracesdk/internal/payload/SpanMapper.kt | 1 + .../internal/spans/EmbraceExtensions.kt | 10 ------ .../android/embracesdk/fakes/FakeSession.kt | 2 ++ .../internal/spans/EmbraceSpanImplTest.kt | 31 ++++++++++--------- 15 files changed, 81 insertions(+), 75 deletions(-) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt (89%) create mode 100644 embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt (78%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt (72%) rename {embrace-android-sdk/src/main/java => embrace-android-core/src/main/kotlin}/io/embrace/android/embracesdk/internal/spans/SpanService.kt (91%) rename {embrace-android-sdk/src/main/java => embrace-android-payload/src/main/kotlin}/io/embrace/android/embracesdk/internal/payload/Span.kt (92%) rename {embrace-android-sdk/src/main/java => embrace-android-payload/src/main/kotlin}/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt (95%) diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt similarity index 89% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt index 0e94ac77fa..abf1817623 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/arch/datasource/SpanDataSource.kt @@ -8,7 +8,7 @@ import io.embrace.android.embracesdk.spans.EmbraceSpan /** * A [DataSource] that adds or alters a span. */ -internal interface SpanDataSource : DataSource { +public interface SpanDataSource : DataSource { /** * The DataSource should call this function when it wants to start, stop, or mutate @@ -27,14 +27,14 @@ internal interface SpanDataSource : DataSource { * This function returns true if data was successfully captured & false if not. * This is assumed to be the case if [captureAction] completed without throwing. */ - fun captureSpanData( + public fun captureSpanData( countsTowardsLimits: Boolean, inputValidation: () -> Boolean, captureAction: SpanService.() -> Unit ): Boolean } -internal fun SpanService.startSpanCapture(schemaType: SchemaType, startTimeMs: Long): PersistableEmbraceSpan? { +public fun SpanService.startSpanCapture(schemaType: SchemaType, startTimeMs: Long): PersistableEmbraceSpan? { return startSpan( name = schemaType.fixedObjectName, startTimeMs = startTimeMs, 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 new file mode 100644 index 0000000000..0e49127e21 --- /dev/null +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceExt.kt @@ -0,0 +1,11 @@ +package io.embrace.android.embracesdk.internal.spans + +/** + * Prefix added to OTel signal object names recorded by the SDK + */ +private const val EMBRACE_OBJECT_NAME_PREFIX = "emb-" + +/** + * Return the appropriate name used for telemetry created by Embrace given the current value + */ +public fun String.toEmbraceObjectName(): String = EMBRACE_OBJECT_NAME_PREFIX + this diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt similarity index 78% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt index a2bf07cc5f..bf5234901c 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/EmbraceSpanBuilder.kt @@ -16,24 +16,24 @@ import java.util.concurrent.TimeUnit /** * Wrapper for the [SpanBuilder] that stores the input data so that they can be accessed */ -internal class EmbraceSpanBuilder( +public class EmbraceSpanBuilder( tracer: Tracer, name: String, telemetryType: TelemetryType, - val internal: Boolean, + public val internal: Boolean, private: Boolean, parentSpan: EmbraceSpan?, ) { - lateinit var parentContext: Context + public lateinit var parentContext: Context private set - val spanName = if (internal) { + public val spanName: String = if (internal) { name.toEmbraceObjectName() } else { name } - var startTimeMs: Long? = null + public var startTimeMs: Long? = null private val sdkSpanBuilder = tracer.spanBuilder(spanName) private val fixedAttributes = mutableListOf(telemetryType) @@ -53,34 +53,34 @@ internal class EmbraceSpanBuilder( } } - fun startSpan(startTimeMs: Long): Span { + public fun startSpan(startTimeMs: Long): Span { sdkSpanBuilder.setStartTimestamp(startTimeMs, TimeUnit.MILLISECONDS) return sdkSpanBuilder.startSpan() } - fun getFixedAttributes(): List = fixedAttributes + public fun getFixedAttributes(): List = fixedAttributes - fun getCustomAttributes(): Map = customAttributes + public fun getCustomAttributes(): Map = customAttributes - fun setCustomAttribute(key: String, value: String) { + public fun setCustomAttribute(key: String, value: String) { customAttributes[key] = value } - fun getParentSpan(): EmbraceSpan? = parentContext.getEmbraceSpan() + public fun getParentSpan(): EmbraceSpan? = parentContext.getEmbraceSpan() - fun setParentContext(context: Context) { + public fun setParentContext(context: Context) { parentContext = context sdkSpanBuilder.setParent(parentContext) updateKeySpan() } - fun setNoParent() { + public fun setNoParent() { parentContext = Context.root() sdkSpanBuilder.setNoParent() updateKeySpan() } - fun setSpanKind(spanKind: SpanKind) { + public fun setSpanKind(spanKind: SpanKind) { sdkSpanBuilder.setSpanKind(spanKind) } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt similarity index 72% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt index 744e37888b..1925fd746a 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/PersistableEmbraceSpan.kt @@ -13,52 +13,52 @@ import io.opentelemetry.context.ImplicitContextKeyed /** * An [EmbraceSpan] that has can generate a snapshot of its current state for persistence */ -internal interface PersistableEmbraceSpan : EmbraceSpan, ImplicitContextKeyed { +public interface PersistableEmbraceSpan : EmbraceSpan, ImplicitContextKeyed { /** * Create a new [Context] object based in this span and its parent's context. This can be used for the parent [Context] for a new span * with this span as its parent. */ - fun asNewContext(): Context? + public fun asNewContext(): Context? /** * Create a snapshot of the current state of the object */ - fun snapshot(): Span? + public fun snapshot(): Span? /** * Checks to see if the given span has a particular [FixedAttribute] */ - fun hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean + public fun hasFixedAttribute(fixedAttribute: FixedAttribute): Boolean /** * Get the value of the attribute with the given key. Returns null if the attribute does not exist. */ - fun getSystemAttribute(key: EmbraceAttributeKey): String? + public fun getSystemAttribute(key: EmbraceAttributeKey): String? /** * Set the value of the attribute with the given key, overwriting the original value if it's already set */ - fun setSystemAttribute(key: EmbraceAttributeKey, value: String) + public fun setSystemAttribute(key: EmbraceAttributeKey, value: String) /** * Remove the custom attribute with the given key name */ - fun removeCustomAttribute(key: String): Boolean + public fun removeCustomAttribute(key: String): Boolean /** * Removes all events with the given [EmbType] */ - fun removeEvents(type: EmbType): Boolean + public fun removeEvents(type: EmbType): Boolean /** * Set the [StatusCode] and status description of the wrapped Span */ - fun setStatus(statusCode: StatusCode, description: String = "") + public fun setStatus(statusCode: StatusCode, description: String = "") override fun storeInContext(context: Context): Context = context.with(embraceSpanContextKey, this) } -internal fun Context.getEmbraceSpan(): PersistableEmbraceSpan? = get(embraceSpanContextKey) +public fun Context.getEmbraceSpan(): PersistableEmbraceSpan? = get(embraceSpanContextKey) private val embraceSpanContextKey = ContextKey.named("embrace-span-key") diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanService.kt b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanService.kt similarity index 91% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanService.kt rename to embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanService.kt index 8cfd2372cb..35ef9a2d14 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/spans/SpanService.kt +++ b/embrace-android-core/src/main/kotlin/io/embrace/android/embracesdk/internal/spans/SpanService.kt @@ -10,12 +10,13 @@ import io.embrace.android.embracesdk.spans.ErrorCode /** * Internal service that supports the creation and recording of [EmbraceSpan] */ -internal interface SpanService : Initializable { +public interface SpanService : Initializable { + /** * Return an [EmbraceSpan] instance that can be used to record spans. Returns null if at least one input parameter is not valid or if * the SDK or session is not in a state where a new span can be recorded. */ - fun createSpan( + public fun createSpan( name: String, parent: EmbraceSpan? = null, type: TelemetryType = EmbType.Performance.Default, @@ -27,12 +28,12 @@ internal interface SpanService : Initializable { * Return an [EmbraceSpan] instance that can be used to record spans given the [EmbraceSpanBuilder]. Returns null if the builder will * not build a valid span or if the SDK and session is not in a state where a new span can be recorded. */ - fun createSpan(embraceSpanBuilder: EmbraceSpanBuilder): PersistableEmbraceSpan? + public fun createSpan(embraceSpanBuilder: EmbraceSpanBuilder): PersistableEmbraceSpan? /** * Create, start, and return a new [EmbraceSpan] with the given parameters */ - fun startSpan( + public fun startSpan( name: String, parent: EmbraceSpan? = null, startTimeMs: Long? = null, @@ -59,7 +60,7 @@ internal interface SpanService : Initializable { * Records a span around the execution of the given lambda. If the lambda throws an uncaught exception, it will be recorded as a * [ErrorCode.FAILURE]. The span will be the provided name, and the appropriate prefix will be prepended to it if [internal] is true. */ - fun recordSpan( + public fun recordSpan( name: String, parent: EmbraceSpan? = null, type: TelemetryType = EmbType.Performance.Default, @@ -74,7 +75,7 @@ internal interface SpanService : Initializable { * Record a completed span for an operation with the given start and end times. Returns true if the span was recorded or queued to be * recorded, false if it wasn't. */ - fun recordCompletedSpan( + public fun recordCompletedSpan( name: String, startTimeMs: Long, endTimeMs: Long, @@ -90,5 +91,5 @@ internal interface SpanService : Initializable { /** * Return the [EmbraceSpan] corresponding to the given spanId if it is active or it has completed in the current session */ - fun getSpan(spanId: String): EmbraceSpan? + public fun getSpan(spanId: String): EmbraceSpan? } diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Span.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Span.kt similarity index 92% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Span.kt rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Span.kt index 9b4d2d4ec6..7fc1b3ce19 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/Span.kt +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/Span.kt @@ -2,7 +2,6 @@ package io.embrace.android.embracesdk.internal.payload import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import io.opentelemetry.api.trace.SpanId /** * A span represents a single unit of work done in the app. It can be a network request, a database @@ -19,7 +18,7 @@ import io.opentelemetry.api.trace.SpanId * @param attributes */ @JsonClass(generateAdapter = true) -internal data class Span( +public data class Span( /* The ID of the trace that this span is part of */ @Json(name = "trace_id") @@ -31,7 +30,7 @@ internal data class Span( /* A value that uniquely identifies the parent span */ @Json(name = "parent_span_id") - val parentSpanId: String? = SpanId.getInvalid(), + val parentSpanId: String? = null, /* The name of the span */ @Json(name = "name") @@ -62,7 +61,7 @@ internal data class Span( * Values: UNSET,ERROR,OK */ @JsonClass(generateAdapter = false) - internal enum class Status(val value: String) { + public enum class Status(public val value: String) { @Json(name = "Unset") UNSET("Unset"), diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt similarity index 95% rename from embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt rename to embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt index e145a91c29..1d86c3afcf 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt +++ b/embrace-android-payload/src/main/kotlin/io/embrace/android/embracesdk/internal/payload/SpanEvent.kt @@ -11,7 +11,7 @@ import com.squareup.moshi.JsonClass * @param attributes */ @JsonClass(generateAdapter = true) -internal data class SpanEvent( +public data class SpanEvent( /* The name of the event */ @Json(name = "name") diff --git a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/SpanAssertions.kt b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/SpanAssertions.kt index 3435311896..8832e46a69 100644 --- a/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/SpanAssertions.kt +++ b/embrace-android-sdk/src/integrationTest/kotlin/io/embrace/android/embracesdk/SpanAssertions.kt @@ -16,10 +16,10 @@ import io.embrace.android.embracesdk.internal.payload.getSessionSpan * Finds the first Span Event matching the given [TelemetryType] */ internal fun Span.findEventOfType(telemetryType: TelemetryType): SpanEvent { - checkNotNull(events) { + val sanitizedEvents = checkNotNull(events) { "No events found in span" } - return checkNotNull(events.single { it.hasFixedAttribute(telemetryType) }) { + return checkNotNull(sanitizedEvents.single { it.hasFixedAttribute(telemetryType) }) { "Event not found: $name" } } @@ -28,10 +28,10 @@ internal fun Span.findEventOfType(telemetryType: TelemetryType): SpanEvent { * Finds the Span Events matching the given [TelemetryType] */ internal fun Span.findEventsOfType(telemetryType: TelemetryType): List { - checkNotNull(events) { + val sanitizedEvents = checkNotNull(events) { "No events found in span" } - return checkNotNull(events.filter { checkNotNull(it.attributes).hasFixedAttribute(telemetryType) }) { + return checkNotNull(sanitizedEvents.filter { checkNotNull(it.attributes).hasFixedAttribute(telemetryType) }) { "Events not found: $name" } } @@ -40,10 +40,10 @@ internal fun Span.findEventsOfType(telemetryType: TelemetryType): List?, @@ -27,7 +28,7 @@ internal class SpanSanitizer( val sanitizedSessionSpan = Span( sessionSpan.traceId, sessionSpan.spanId, - sessionSpan.parentSpanId, + sessionSpan.parentSpanId ?: SpanId.getInvalid(), sessionSpan.name, sessionSpan.startTimeNanos, sessionSpan.endTimeNanos, diff --git a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanMapper.kt b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanMapper.kt index 3bf10cde9f..9875d00f82 100644 --- a/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanMapper.kt +++ b/embrace-android-sdk/src/main/java/io/embrace/android/embracesdk/internal/payload/SpanMapper.kt @@ -87,6 +87,7 @@ internal fun Span.toFailedSpan(endTimeMs: Long): Span { return copy( endTimeNanos = endTimeMs.millisToNanos(), + parentSpanId = this.parentSpanId ?: SpanId.getInvalid(), status = Span.Status.ERROR, attributes = newAttributes.map { Attribute(it.key, it.value) }.plus(attributes ?: emptyList()) ) 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 d34577d379..125c8cb213 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 @@ -27,11 +27,6 @@ import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes * Note: there's no explicit tests for these extensions as their functionality will be validated as part of other tests. */ -/** - * 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 */ @@ -84,11 +79,6 @@ internal fun AttributesBuilder.fromMap(attributes: Map): Attribu return this } -/** - * Return the appropriate name used for telemetry created by Embrace given the current value - */ -internal fun String.toEmbraceObjectName(): String = EMBRACE_OBJECT_NAME_PREFIX + this - /** * Return the appropriate internal Embrace attribute usage name given the current string */ diff --git a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeSession.kt b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeSession.kt index 57bf683f4a..730c974d2d 100644 --- a/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeSession.kt +++ b/embrace-android-sdk/src/test/java/io/embrace/android/embracesdk/fakes/FakeSession.kt @@ -12,6 +12,7 @@ import io.embrace.android.embracesdk.internal.payload.SessionPayload import io.embrace.android.embracesdk.internal.payload.SessionZygote import io.embrace.android.embracesdk.internal.payload.Span import io.embrace.android.embracesdk.internal.payload.getSessionSpan +import io.opentelemetry.api.trace.SpanId internal fun fakeSessionZygote() = SessionZygote( sessionId = "fakeSessionId", @@ -30,6 +31,7 @@ internal fun fakeSessionEnvelope( val sessionSpan = Span( startTimeNanos = startMs.millisToNanos(), endTimeNanos = endMs.millisToNanos(), + parentSpanId = SpanId.getInvalid(), attributes = listOf( Attribute("emb.type", EmbType.Ux.Session.value), Attribute(embSessionId.name, sessionId) 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 895d7adf7f..ddda14d95f 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 @@ -203,34 +203,35 @@ internal class EmbraceSpanImplTest { } with(checkNotNull(embraceSpan.snapshot())) { - assertEquals(2, checkNotNull(events).size) - with(events.first()) { + val sanitizedEvents = checkNotNull(events) + assertEquals(2, sanitizedEvents.size) + with(sanitizedEvents.first()) { assertEquals(EmbraceSpanImpl.EXCEPTION_EVENT_NAME, name) - checkNotNull(attributes) + val attrs = checkNotNull(attributes) assertEquals(timestampNanos, timestampNanos) assertEquals( IllegalStateException::class.java.canonicalName, - attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_TYPE.key }.data + attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_TYPE.key }.data ) - assertEquals("oops", attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key }.data) + assertEquals("oops", attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key }.data) assertEquals( firstExceptionStackTrace, - attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key }.data + attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key }.data ) } - with(events.last()) { + with(sanitizedEvents.last()) { assertEquals(EmbraceSpanImpl.EXCEPTION_EVENT_NAME, name) - checkNotNull(attributes) + val attrs = checkNotNull(attributes) assertEquals(timestampNanos, timestampNanos) assertEquals( RuntimeException::class.java.canonicalName, - attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_TYPE.key }.data + attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_TYPE.key }.data ) - assertEquals("haha", attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key }.data) - assertEquals("myValue", attributes.single { it.key == "myKey" }.data) + assertEquals("haha", attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key }.data) + assertEquals("myValue", attrs.single { it.key == "myKey" }.data) assertEquals( secondExceptionStackTrace, - attributes.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key }.data + attrs.single { it.key == ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key }.data ) } } @@ -441,9 +442,9 @@ internal class EmbraceSpanImplTest { assertEquals(eventCount, events?.size) assertTrue(hasFixedAttribute(expectedType)) assertEquals(isPrivate, hasFixedAttribute(PrivateSpan)) - checkNotNull(attributes) - val embraceAttributeCount = attributes.filter { checkNotNull(it.key).startsWith("emb.") }.size - val customAttributeCount = attributes.size - embraceAttributeCount + val attrs = checkNotNull(attributes) + val embraceAttributeCount = attrs.filter { checkNotNull(it.key).startsWith("emb.") }.size + val customAttributeCount = attrs.size - embraceAttributeCount assertEquals(expectedEmbraceAttributes, embraceAttributeCount) assertEquals(expectedCustomAttributeCount, customAttributeCount) }