Skip to content
Draft
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
4 changes: 4 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ detekt = "1.23.8"
binaryCompatValidator = "0.18.1"
fragment = "1.8.9"
koverGradlePlugin = "0.9.2"
opentelemetryKotlin = "0.5.1"

[libraries]
opentelemetry-platform-alpha = { module = "io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha", version.ref = "opentelemetry-instrumentation-alpha" }
Expand Down Expand Up @@ -56,6 +57,8 @@ auto-service-processor = { module = "dev.zacsweers.autoservice:auto-service-ksp"
compose = { group = "androidx.compose.ui", name = "ui", version.ref = "compose" }
detekt-plugin = { module = "io.gitlab.arturbosch.detekt:detekt-gradle-plugin", version.ref = "detekt" }
binary-compat-validator = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "binaryCompatValidator" }
opentelemetry-kotlin = { group = "io.embrace.opentelemetry.kotlin", name = "opentelemetry-kotlin", version.ref = "opentelemetryKotlin" }
opentelemetry-kotlin-compat = { group = "io.embrace.opentelemetry.kotlin", name = "opentelemetry-kotlin-compat", version.ref = "opentelemetryKotlin" }

#Test tools
opentelemetry-sdk-testing = { module = "io.opentelemetry:opentelemetry-sdk-testing" }
Expand All @@ -75,6 +78,7 @@ assertj-core = "org.assertj:assertj-core:3.27.6"
awaitility = "org.awaitility:awaitility:4.3.0"
mockwebserver = "com.google.mockwebserver:mockwebserver:20130706"
okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" }
opentelemetry-kotlin-testing = { group = "io.embrace.opentelemetry.kotlin", name = "opentelemetry-kotlin-testing", version.ref = "opentelemetryKotlin" }

#Compilation tools
desugarJdkLibs = "com.android.tools:desugar_jdk_libs:2.1.5"
Expand Down
3 changes: 3 additions & 0 deletions instrumentation/crash/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,7 @@ dependencies {
implementation(libs.opentelemetry.instrumentation.api)
testImplementation(libs.awaitility)
testImplementation(libs.robolectric)

implementation(libs.opentelemetry.kotlin)
implementation(libs.opentelemetry.kotlin.compat)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@

package io.opentelemetry.android.instrumentation.crash

import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.attributes.setAttributes
import io.embrace.opentelemetry.kotlin.getLogger
import io.embrace.opentelemetry.kotlin.toOtelKotlinApi
import io.opentelemetry.android.instrumentation.common.EventAttributesExtractor
import io.opentelemetry.api.common.Attributes
import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder
import io.opentelemetry.api.common.AttributesBuilder
import io.opentelemetry.context.Context
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.semconv.ExceptionAttributes.EXCEPTION_MESSAGE
Expand Down Expand Up @@ -37,35 +41,42 @@ internal class CrashReporter(
Thread.setDefaultUncaughtExceptionHandler(handler)
}

@OptIn(ExperimentalApi::class)
private fun processCrash(
openTelemetry: OpenTelemetrySdk,
crashDetails: CrashDetails,
) {
val logger = openTelemetry.sdkLoggerProvider.loggerBuilder("io.opentelemetry.crash").build()
val otel = openTelemetry.toOtelKotlinApi()
val logger = otel.getLogger("io.opentelemetry.crash")
val throwable = crashDetails.cause
val thread = crashDetails.thread
val attributesBuilder =
Attributes
.builder()
.put(THREAD_ID, thread.id)
.put(THREAD_NAME, thread.name)
.put(EXCEPTION_MESSAGE, throwable.message)
.put(
EXCEPTION_STACKTRACE,
throwable.stackTraceToString(),
).put(EXCEPTION_TYPE, throwable.javaClass.name)

val attributesBuilder = Attributes.builder()
for (extractor in extractors) {
val extractedAttributes = extractor.extract(Context.current(), crashDetails)
attributesBuilder.putAll(extractedAttributes)
}
val eventBuilder =
logger.logRecordBuilder() as ExtendedLogRecordBuilder
eventBuilder
.setEventName("device.crash")
.setAllAttributes(attributesBuilder.build())
.emit()

logger.log(body = "device.crash") {
// event name not supported yet. Use body as an example instead.
setAttributes(
mapOf<String, Any>(
THREAD_ID.key to thread.id,
THREAD_NAME.key to thread.name,
EXCEPTION_STACKTRACE.key to throwable.stackTraceToString(),
EXCEPTION_TYPE.key to throwable.javaClass.name,
),
)
setAttributes(attributesBuilder.toMap())

throwable.message?.let {
setStringAttribute(EXCEPTION_MESSAGE.key, it)
}
}
}

private fun AttributesBuilder.toMap(): Map<String, Any> = build().asMap().mapKeys { (k, _) -> k.key }

private fun waitForCrashFlush(openTelemetry: OpenTelemetrySdk) {
val flushResult = openTelemetry.sdkLoggerProvider.forceFlush()
flushResult.join(10, TimeUnit.SECONDS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ internal class CrashReportIntegrationTest {
expectedExcType: String,
expectedExcMessage: String? = null,
) {
assertEquals("device.crash", eventName)
assertEquals(Severity.UNDEFINED_SEVERITY_NUMBER, severity)

val attrs = attributes.asMap().mapKeys { it.key.key }
Expand Down
2 changes: 2 additions & 0 deletions instrumentation/slowrendering/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ dependencies {
implementation(libs.androidx.core)
implementation(libs.opentelemetry.semconv)
implementation(libs.opentelemetry.sdk)
implementation(libs.opentelemetry.kotlin)
implementation(libs.opentelemetry.kotlin.compat)
implementation(libs.opentelemetry.instrumentation.api)
implementation(libs.opentelemetry.sdk.extension.incubator)
testImplementation(libs.robolectric)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ package io.opentelemetry.android.instrumentation.slowrendering
import android.os.Build
import android.util.Log
import com.google.auto.service.AutoService
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.getTracer
import io.embrace.opentelemetry.kotlin.toOtelKotlinApi
import io.opentelemetry.android.common.RumConstants
import io.opentelemetry.android.instrumentation.AndroidInstrumentation
import io.opentelemetry.android.instrumentation.InstallationContext
Expand Down Expand Up @@ -64,6 +67,7 @@ class SlowRenderingInstrumentation : AndroidInstrumentation {
return this
}

@OptIn(ExperimentalApi::class)
override fun install(ctx: InstallationContext) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
Log.w(
Expand All @@ -85,7 +89,8 @@ class SlowRenderingInstrumentation : AndroidInstrumentation {
jankReporter = jankReporter.combine(EventJankReporter(logger, FROZEN_THRESHOLD_MS / 1000.0, debugVerbose))

if (useDeprecatedSpan) {
val tracer = ctx.openTelemetry.getTracer("io.opentelemetry.slow-rendering")
val otel = ctx.openTelemetry.toOtelKotlinApi()
val tracer = otel.getTracer("io.opentelemetry.slow-rendering")
jankReporter = jankReporter.combine(SpanBasedJankReporter(tracer))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
package io.opentelemetry.android.instrumentation.slowrendering

import android.util.Log
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.tracing.Tracer
import io.opentelemetry.android.common.RumConstants
import io.opentelemetry.api.trace.Span
import io.opentelemetry.api.trace.Tracer
import java.time.Instant
import java.util.concurrent.TimeUnit

internal const val SLOW_THRESHOLD_MS = 16
internal const val FROZEN_THRESHOLD_MS = 700

@OptIn(ExperimentalApi::class)
internal class SpanBasedJankReporter(
private val tracer: Tracer,
) : JankReporter {
Expand Down Expand Up @@ -57,13 +59,13 @@ internal class SpanBasedJankReporter(
slowCount: Int,
now: Instant,
) {
val span: Span =
tracer
.spanBuilder(spanName)
.setAttribute("count", slowCount.toLong())
.setAttribute("activity.name", activityName)
.setStartTimestamp(now)
.startSpan()
span.end(now)
val span =
tracer.createSpan(spanName, startTimestamp = now.toNanoSeconds()) {
setLongAttribute("count", slowCount.toLong())
setStringAttribute("activity.name", activityName)
}
span.end(now.toNanoSeconds())
}

private fun Instant.toNanoSeconds(): Long = TimeUnit.MILLISECONDS.convert(toEpochMilli(), TimeUnit.NANOSECONDS)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,11 @@
import android.os.Handler;
import android.view.FrameMetrics;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import io.embrace.opentelemetry.kotlin.OpenTelemetryExtKt;
import io.embrace.opentelemetry.kotlin.OtelJavaOpenTelemetryExtKt;
import io.embrace.opentelemetry.kotlin.tracing.Tracer;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
import io.opentelemetry.sdk.trace.data.SpanData;
import java.time.Duration;
Expand Down Expand Up @@ -122,7 +125,10 @@ public void addAndRemove() {

@Test
public void removeWithMetrics() {
Tracer tracer = otelTesting.getOpenTelemetry().getTracer("testTracer");
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
io.embrace.opentelemetry.kotlin.OpenTelemetry otelKotlin =
OtelJavaOpenTelemetryExtKt.toOtelKotlinApi(openTelemetry);
Tracer tracer = OpenTelemetryExtKt.getTracer(otelKotlin, "testTracer");
jankReporter = new SpanBasedJankReporter(tracer);
SlowRenderListener testInstance =
new SlowRenderListener(
Expand Down Expand Up @@ -157,7 +163,10 @@ public void start() {
.when(exec)
.scheduleWithFixedDelay(any(), eq(1001L), eq(1001L), eq(TimeUnit.MILLISECONDS));

Tracer tracer = otelTesting.getOpenTelemetry().getTracer("testTracer");
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
io.embrace.opentelemetry.kotlin.OpenTelemetry otelKotlin =
OtelJavaOpenTelemetryExtKt.toOtelKotlinApi(openTelemetry);
Tracer tracer = OpenTelemetryExtKt.getTracer(otelKotlin, "testTracer");
jankReporter = new SpanBasedJankReporter(tracer);
SlowRenderListener testInstance =
new SlowRenderListener(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ package io.opentelemetry.android.instrumentation.slowrendering

import android.app.Application
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.createCompatOpenTelemetry
import io.embrace.opentelemetry.kotlin.toOtelJavaApi
import io.mockk.Called
import io.mockk.MockKAnnotations
import io.mockk.Runs
Expand Down Expand Up @@ -100,16 +103,16 @@ class SlowRenderingInstrumentationTest {
verify { application.registerActivityLifecycleCallbacks(capture(capturedListener)) }
}

@OptIn(ExperimentalApi::class)
@Config(sdk = [24, 25])
@Test
fun `can use legacy span`() {
val capturedListener = slot<SlowRenderListener>()
every { openTelemetry.getTracer(any()) }.returns(mockk())
val otel = createCompatOpenTelemetry().toOtelJavaApi()
every { application.registerActivityLifecycleCallbacks(any()) } just Runs
val ctx = InstallationContext(application, openTelemetry, mockk())
val ctx = InstallationContext(application, otel, mockk())
slowRenderingInstrumentation.enableDeprecatedZeroDurationSpan().install(ctx)

verify { openTelemetry.getTracer("io.opentelemetry.slow-rendering") }
verify { application.registerActivityLifecycleCallbacks(capture(capturedListener)) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
package io.opentelemetry.android.instrumentation.slowrendering

import android.util.Log
import io.embrace.opentelemetry.kotlin.ExperimentalApi
import io.embrace.opentelemetry.kotlin.getTracer
import io.embrace.opentelemetry.kotlin.toOtelKotlinApi
import io.embrace.opentelemetry.kotlin.tracing.Tracer
import io.mockk.every
import io.mockk.mockkStatic
import io.opentelemetry.api.common.AttributeKey
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule
import io.opentelemetry.sdk.trace.data.SpanData
Expand All @@ -21,6 +24,7 @@ import org.junit.jupiter.api.Test

private val COUNT_KEY = AttributeKey.longKey("count")

@OptIn(ExperimentalApi::class)
class SpanBasedJankReporterTest {
private lateinit var tracer: Tracer

Expand All @@ -29,7 +33,7 @@ class SpanBasedJankReporterTest {

@BeforeEach
fun setup() {
tracer = otelTesting.openTelemetry.getTracer("testTracer")
tracer = otelTesting.openTelemetry.toOtelKotlinApi().getTracer("testTracer")
}

@Test
Expand Down