Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to OTel semantic convention keys #1139

Merged
merged 1 commit into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.embrace.android.embracesdk.internal.arch.schema

import io.embrace.android.embracesdk.internal.clock.millisToNanos
import io.embrace.android.embracesdk.internal.payload.AppExitInfoData
import io.embrace.android.embracesdk.internal.payload.NetworkCapturedCall
import io.embrace.android.embracesdk.internal.utils.toNonNullMap
import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import io.opentelemetry.semconv.HttpAttributes
import io.opentelemetry.semconv.UrlAttributes
import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes
import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes

/**
* The collections of attribute schemas used by the associated telemetry types.
Expand Down Expand Up @@ -44,46 +47,6 @@ public sealed class SchemaType(
override val schemaAttributes: Map<String, String> = mapOf("view.name" to viewName)
}

/**
* Represents a span in which a thread was blocked.
*/
public class ThreadBlockage(
threadPriority: Int,
lastKnownTimeMs: Long,
intervalCode: Int
) : SchemaType(
telemetryType = EmbType.Performance.ThreadBlockage,
fixedObjectName = "thread_blockage"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"thread_priority" to threadPriority.toString(),
"last_known_time_unix_nano" to lastKnownTimeMs.millisToNanos().toString(),
"interval_code" to intervalCode.toString()
)
}

/**
* Represents a point in time when a thread was blocked.
*/
public class ThreadBlockageSample(
sampleOverheadMs: Long,
frameCount: Int,
stacktrace: String,
sampleCode: Int,
threadState: Thread.State
) : SchemaType(
telemetryType = EmbType.Performance.ThreadBlockageSample,
fixedObjectName = "thread_blockage_sample"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"sample_overhead" to sampleOverheadMs.millisToNanos().toString(),
"frame_count" to frameCount.toString(),
"stacktrace" to stacktrace,
"sample_code" to sampleCode.toString(),
"thread_state" to threadState.toString()
)
}

/**
* Represents a push notification event.
* @param viewName The name of the view that the tap event occurred in.
Expand Down Expand Up @@ -111,48 +74,6 @@ public sealed class SchemaType(
).toNonNullMap()
}

/**
* Represents a span in which a native thread was blocked.
*/
public class NativeThreadBlockage(
threadId: Int,
threadName: String,
threadPriority: Int,
threadState: String,
samplingOffsetMs: Long,
stackUnwinder: String,
) : SchemaType(
telemetryType = EmbType.Performance.NativeThreadBlockage,
fixedObjectName = "native_thread_blockage"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"thread_id" to threadId.toString(),
"thread_name" to threadName,
"thread_priority" to threadPriority.toString(),
"thread_state" to threadState,
"sampling_offset_ms" to samplingOffsetMs.toString(),
"stack_unwinder" to stackUnwinder,
)
}

/**
* Represents a point in time when a native thread was blocked.
*/
public class NativeThreadBlockageSample(
result: Int,
sampleOverheadMs: Long,
stacktrace: String,
) : SchemaType(
telemetryType = EmbType.Performance.NativeThreadBlockageSample,
fixedObjectName = "native_thread_blockage_sample"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"result" to result.toString(),
"sample_overhead_ms" to sampleOverheadMs.toString(),
"stacktrace" to stacktrace
)
}

/**
* Represents a tap breadcrumb event.
* @param viewName The name of the view that the tap event occurred in.
Expand Down Expand Up @@ -181,7 +102,7 @@ public sealed class SchemaType(
fixedObjectName = "web-view"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"webview.url" to url
UrlAttributes.URL_FULL.key to url
).toNonNullMap()
}

Expand Down Expand Up @@ -259,23 +180,23 @@ public sealed class SchemaType(
override val schemaAttributes: Map<String, String> = mapOf(
"duration" to networkCapturedCall.duration.toString(),
"end-time" to networkCapturedCall.endTime.toString(),
"http-method" to networkCapturedCall.httpMethod,
"matched-url" to networkCapturedCall.matchedUrl,
HttpAttributes.HTTP_REQUEST_METHOD.key to networkCapturedCall.httpMethod,
UrlAttributes.URL_FULL.key to networkCapturedCall.matchedUrl,
"network-id" to networkCapturedCall.networkId,
"request-body" to networkCapturedCall.requestBody,
"request-body-size" to networkCapturedCall.requestBodySize.toString(),
HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE.key to networkCapturedCall.requestBodySize.toString(),
"request-query" to networkCapturedCall.requestQuery,
"request-query-headers" to networkCapturedCall.requestQueryHeaders.toString(),
"http.request.header" to networkCapturedCall.requestQueryHeaders.toString(),
"request-size" to networkCapturedCall.requestSize.toString(),
"response-body" to networkCapturedCall.responseBody,
"response-body-size" to networkCapturedCall.responseBodySize.toString(),
"response-headers" to networkCapturedCall.responseHeaders.toString(),
HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE.key to networkCapturedCall.responseBodySize.toString(),
"http.response.header" to networkCapturedCall.responseHeaders.toString(),
"response-size" to networkCapturedCall.responseSize.toString(),
"response-status" to networkCapturedCall.responseStatus.toString(),
"session-id" to networkCapturedCall.sessionId,
HttpAttributes.HTTP_RESPONSE_STATUS_CODE.key to networkCapturedCall.responseStatus.toString(),
SessionIncubatingAttributes.SESSION_ID.key to networkCapturedCall.sessionId,
"start-time" to networkCapturedCall.startTime.toString(),
"url" to networkCapturedCall.url,
"error-message" to networkCapturedCall.errorMessage,
ExceptionAttributes.EXCEPTION_MESSAGE.key to networkCapturedCall.errorMessage,
"encrypted-payload" to networkCapturedCall.encryptedPayload
).toNonNullMap()
}
Expand All @@ -300,7 +221,7 @@ public sealed class SchemaType(
fixedObjectName = "webview-info"
) {
override val schemaAttributes: Map<String, String> = mapOf(
"emb.webview_info.url" to url,
UrlAttributes.URL_FULL.key to url,
"emb.webview_info.web_vitals" to webVitals,
"emb.webview_info.tag" to tag
).toNonNullMap()
Expand Down Expand Up @@ -344,12 +265,12 @@ public sealed class SchemaType(
fixedObjectName = "internal-error"
) {
override val schemaAttributes: Map<String, String> = mapOf(
ExceptionIncubatingAttributes.EXCEPTION_TYPE.key to throwable.javaClass.name,
ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key to throwable.stackTrace.joinToString(
ExceptionAttributes.EXCEPTION_TYPE.key to throwable.javaClass.name,
ExceptionAttributes.EXCEPTION_STACKTRACE.key to throwable.stackTrace.joinToString(
"\n",
transform = StackTraceElement::toString
),
ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key to (throwable.message ?: "")
ExceptionAttributes.EXCEPTION_MESSAGE.key to (throwable.message ?: "")
)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package io.embrace.android.embracesdk.internal.spans

import io.embrace.android.embracesdk.internal.arch.schema.EmbType
import io.embrace.android.embracesdk.internal.arch.schema.EmbraceAttributeKey
import io.embrace.android.embracesdk.internal.arch.schema.FixedAttribute
import io.embrace.android.embracesdk.internal.payload.Span
import io.embrace.android.embracesdk.spans.EmbraceSpan
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.context.Context
import io.opentelemetry.context.ContextKey
Expand Down Expand Up @@ -34,12 +34,12 @@ public interface PersistableEmbraceSpan : EmbraceSpan, ImplicitContextKeyed {
/**
* Get the value of the attribute with the given key. Returns null if the attribute does not exist.
*/
public fun getSystemAttribute(key: EmbraceAttributeKey): String?
public fun getSystemAttribute(key: AttributeKey<String>): String?

/**
* Set the value of the attribute with the given key, overwriting the original value if it's already set
*/
public fun setSystemAttribute(key: EmbraceAttributeKey, value: String)
public fun setSystemAttribute(key: AttributeKey<String>, value: String)

/**
* Remove the custom attribute with the given key name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import io.embrace.android.embracesdk.internal.payload.Span
import io.embrace.android.embracesdk.internal.payload.SpanEvent
import io.embrace.android.embracesdk.internal.spans.findAttributeValue
import io.embrace.android.embracesdk.internal.spans.hasFixedAttribute
import io.embrace.android.embracesdk.internal.opentelemetry.embSessionId
import io.embrace.android.embracesdk.internal.payload.getSessionSpan
import io.opentelemetry.semconv.incubating.SessionIncubatingAttributes

/**
* Finds the first Span Event matching the given [TelemetryType]
Expand Down Expand Up @@ -55,7 +55,7 @@ internal fun Envelope<SessionPayload>.getSessionId(): String {
val sessionSpan = checkNotNull(getSessionSpan()) {
"No session span found in session message"
}
return checkNotNull(sessionSpan.attributes?.findAttributeValue(embSessionId.name)) {
return checkNotNull(sessionSpan.attributes?.findAttributeValue(SessionIncubatingAttributes.SESSION_ID.key)) {
"No session id found in session message"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package io.embrace.android.embracesdk.assertions
import io.embrace.android.embracesdk.FakeDeliveryService
import io.embrace.android.embracesdk.internal.injection.ModuleInitBootstrapper
import io.embrace.android.embracesdk.internal.spans.findAttributeValue
import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import org.junit.Assert.fail

/**
Expand All @@ -27,8 +27,8 @@ internal fun assertInternalErrorLogged(
}

val matchingLogs = logs.filter { log ->
log.attributes?.findAttributeValue(ExceptionIncubatingAttributes.EXCEPTION_TYPE.key) == exceptionClassName &&
log.attributes.findAttributeValue(ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key) == errorMessage
log.attributes?.findAttributeValue(ExceptionAttributes.EXCEPTION_TYPE.key) == exceptionClassName &&
log.attributes.findAttributeValue(ExceptionAttributes.EXCEPTION_MESSAGE.key) == errorMessage
}
if (matchingLogs.isEmpty()) {
fail("No internal errors found matching the expected exception")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package io.embrace.android.embracesdk.assertions

import io.embrace.android.embracesdk.IntegrationTestRule
import io.embrace.android.embracesdk.internal.opentelemetry.embExceptionHandling
import io.embrace.android.embracesdk.internal.payload.Log
import io.embrace.android.embracesdk.internal.serialization.EmbraceSerializer
import io.embrace.android.embracesdk.internal.serialization.truncatedStacktrace
import io.embrace.android.embracesdk.internal.opentelemetry.embExceptionHandling
import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull

Expand All @@ -31,14 +31,14 @@ internal fun assertOtelLogReceived(
assertEquals(expectedTimeMs * 1000000, log.timeUnixNano)
expectedType?.let { assertAttribute(log, embExceptionHandling.name, it) }
expectedExceptionName?.let {
assertAttribute(log, ExceptionIncubatingAttributes.EXCEPTION_TYPE.key, expectedExceptionName)
assertAttribute(log, ExceptionAttributes.EXCEPTION_TYPE.key, expectedExceptionName)
}
expectedExceptionMessage?.let {
assertAttribute(log, ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key, expectedExceptionMessage)
assertAttribute(log, ExceptionAttributes.EXCEPTION_MESSAGE.key, expectedExceptionMessage)
}
expectedStacktrace?.let {
val serializedStack = EmbraceSerializer().truncatedStacktrace(it.toTypedArray())
assertAttribute(log, ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key, serializedStack)
assertAttribute(log, ExceptionAttributes.EXCEPTION_STACKTRACE.key, serializedStack)
}
expectedProperties?.forEach { (key, value) ->
assertAttribute(log, key, value.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import io.embrace.android.embracesdk.internal.spans.findAttributeValue
import io.embrace.android.embracesdk.internal.payload.WebVital
import io.embrace.android.embracesdk.internal.payload.WebVitalType
import io.embrace.android.embracesdk.recordSession
import io.opentelemetry.semconv.UrlAttributes.URL_FULL
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -54,7 +55,7 @@ internal class WebviewFeatureTest {
val attrs = checkNotNull(event.attributes)
assertEquals("emb-webview-info", event.name)
assertEquals("myWebView", attrs.findAttributeValue("emb.webview_info.tag"))
assertEquals("https://embrace.io/", attrs.findAttributeValue("emb.webview_info.url"))
assertEquals("https://embrace.io/", attrs.findAttributeValue(URL_FULL.key))

val webVitalsAttr = checkNotNull(attrs.findAttributeValue("emb.webview_info.web_vitals"))
val type = Types.newParameterizedType(List::class.java, WebVital::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import io.opentelemetry.api.trace.StatusCode
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.context.Context
import io.opentelemetry.sdk.trace.data.SpanData
import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNull
Expand Down Expand Up @@ -148,9 +148,9 @@ internal class ExternalTracerTest {
timestampNanos = checkNotNull(startTimeMs?.millisToNanos()),
attributes = listOf(
Attribute("bad", "yes"),
Attribute(ExceptionIncubatingAttributes.EXCEPTION_MESSAGE.key, "bah"),
Attribute(ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key, stacktrace),
Attribute(ExceptionIncubatingAttributes.EXCEPTION_TYPE.key, checkNotNull(RuntimeException::class.java.canonicalName))
Attribute(ExceptionAttributes.EXCEPTION_MESSAGE.key, "bah"),
Attribute(ExceptionAttributes.EXCEPTION_STACKTRACE.key, stacktrace),
Attribute(ExceptionAttributes.EXCEPTION_TYPE.key, checkNotNull(RuntimeException::class.java.canonicalName))
)
)
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import io.embrace.android.embracesdk.internal.spans.findAttributeValue
import io.embrace.android.embracesdk.recordSession
import io.embrace.android.embracesdk.internal.worker.WorkerName
import io.opentelemetry.api.logs.Severity
import io.opentelemetry.semconv.incubating.ExceptionIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Before
Expand Down Expand Up @@ -170,7 +170,7 @@ internal class FlutterInternalInterfaceTest {
expectedEmbType = "sys.flutter_exception",
)
val attrs = checkNotNull(log.attributes)
assertEquals(expectedStacktrace, attrs.findAttributeValue(ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key))
assertEquals(expectedStacktrace, attrs.findAttributeValue(ExceptionAttributes.EXCEPTION_STACKTRACE.key))
assertEquals(expectedContext, attrs.findAttributeValue("emb.exception.context"))
assertEquals(expectedLibrary, attrs.findAttributeValue("emb.exception.library"))
}
Expand Down Expand Up @@ -207,7 +207,7 @@ internal class FlutterInternalInterfaceTest {
expectedEmbType = "sys.flutter_exception",
)
val attrs = checkNotNull(log.attributes)
assertEquals(expectedStacktrace, attrs.findAttributeValue(ExceptionIncubatingAttributes.EXCEPTION_STACKTRACE.key))
assertEquals(expectedStacktrace, attrs.findAttributeValue(ExceptionAttributes.EXCEPTION_STACKTRACE.key))
assertEquals(expectedContext, attrs.findAttributeValue("emb.exception.context"))
assertEquals(expectedLibrary, attrs.findAttributeValue("emb.exception.library"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import io.embrace.android.embracesdk.network.http.HttpMethod
import io.embrace.android.embracesdk.recordSession
import io.opentelemetry.semconv.HttpAttributes
import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes
import io.opentelemetry.semconv.ExceptionAttributes
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
Expand Down Expand Up @@ -267,7 +268,7 @@ internal class NetworkRequestApiTest {
assertEquals(expectedRequest.bytesSent.toString(), attrs.findAttributeValue(HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE.key))
assertEquals(expectedRequest.bytesReceived.toString(), attrs.findAttributeValue(HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE.key))
assertEquals(null, attrs.findAttributeValue("error.type"))
assertEquals(null, attrs.findAttributeValue("error.message"))
assertEquals(null, attrs.findAttributeValue(ExceptionAttributes.EXCEPTION_MESSAGE.key))
val statusCode = expectedRequest.responseCode
val expectedStatus = if (statusCode != null && statusCode >= 200 && statusCode < 400) {
Span.Status.UNSET
Expand All @@ -280,7 +281,7 @@ internal class NetworkRequestApiTest {
assertEquals(null, attrs.findAttributeValue(HttpIncubatingAttributes.HTTP_REQUEST_BODY_SIZE.key))
assertEquals(null, attrs.findAttributeValue(HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE.key))
assertEquals(expectedRequest.errorType, attrs.findAttributeValue("error.type"))
assertEquals(expectedRequest.errorMessage, attrs.findAttributeValue("error.message"))
assertEquals(expectedRequest.errorMessage, attrs.findAttributeValue(ExceptionAttributes.EXCEPTION_MESSAGE.key))
assertEquals(Span.Status.ERROR, status)
}
}
Expand Down
Loading
Loading