diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 062cd0bf2..ea794a5c2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,7 @@ opentelemetry-api = { module = "io.opentelemetry:opentelemetry-api" } opentelemetry-sdk = { module = "io.opentelemetry:opentelemetry-sdk" } opentelemetry-exporter-zipkin = { module = "io.opentelemetry:opentelemetry-exporter-zipkin" } opentelemetry-exporter-logging = { module = "io.opentelemetry:opentelemetry-exporter-logging" } +opentelemetry-apievents = { module = "io.opentelemetry:opentelemetry-api-events" } zipkin-sender-okhttp3 = { module = "io.zipkin.reporter2:zipkin-sender-okhttp3", version.ref = "zipkin-reporter"} #Test tools diff --git a/instrumentation/build.gradle.kts b/instrumentation/build.gradle.kts index bbbaee619..a73211289 100644 --- a/instrumentation/build.gradle.kts +++ b/instrumentation/build.gradle.kts @@ -70,6 +70,9 @@ dependencies { implementation(libs.opentelemetry.exporter.logging) implementation(libs.opentelemetry.instrumentation.api) implementation(libs.opentelemetry.semconv) + implementation(libs.opentelemetry.apievents) + + implementation("io.opentelemetry:opentelemetry-api-events") testImplementation(libs.bundles.mockito) testImplementation(libs.bundles.junit) diff --git a/instrumentation/src/main/java/io/opentelemetry/android/emitter/EventEmitterWithData.java b/instrumentation/src/main/java/io/opentelemetry/android/emitter/EventEmitterWithData.java new file mode 100644 index 000000000..be5dd5a0f --- /dev/null +++ b/instrumentation/src/main/java/io/opentelemetry/android/emitter/EventEmitterWithData.java @@ -0,0 +1,51 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.emitter; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.events.EventEmitter; +import java.util.Map; + +class EventEmitterWithData { + + private static final String EVENT_DATA = "event.data"; + + private final EventEmitter delegate; + + EventEmitterWithData(EventEmitter delegate) { + this.delegate = delegate; + } + + public void emit(String eventName, Attributes attributes, Map data) { + Attributes dataAsAttribute = convertRichDataObjectIntoAttributes(data); + Attributes eventAttrs = + attributes.toBuilder().put(EVENT_DATA, dataAsAttribute.toString()).build(); + delegate.emit(eventName, eventAttrs); + } + + public Attributes convertRichDataObjectIntoAttributes(Map data) { + AttributesBuilder builder = Attributes.builder(); + for (String key : data.keySet()) { + Object val = data.get(key); + if (val != null) { + if (val instanceof String) { + builder.put(AttributeKey.stringKey(key), (String) val); + } else if (val instanceof Long) { + builder.put(AttributeKey.longKey(key), (Long) val); + } else if (val instanceof Double) { + builder.put(AttributeKey.doubleKey(key), (Double) val); + } else if (val instanceof Boolean) { + builder.put(AttributeKey.booleanKey(key), (Boolean) val); + } else { + builder.put(AttributeKey.stringKey(key), val.toString()); + } + } + } + return builder.build(); + } +} diff --git a/instrumentation/src/test/java/io/opentelemetry/android/emitter/EventEmitterWithDataTest.java b/instrumentation/src/test/java/io/opentelemetry/android/emitter/EventEmitterWithDataTest.java new file mode 100644 index 000000000..4840c900a --- /dev/null +++ b/instrumentation/src/test/java/io/opentelemetry/android/emitter/EventEmitterWithDataTest.java @@ -0,0 +1,56 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.android.emitter; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; + +public class EventEmitterWithDataTest { + + @Test + public void testConvertRichDataObjectIntoAttributes() { + Exception crashData = null; + try { + throw new RuntimeException("Crash!"); + } catch (Exception e) { + crashData = e; + } + + StringWriter stacktrace = new StringWriter(); + crashData.printStackTrace(new PrintWriter(stacktrace)); + + Map data = new HashMap<>(); + data.put("stringKey", "key"); + data.put("longKey", 123L); + data.put("doubleKey", 12.3); + data.put("booleanKey", true); + + data.put("stacktrace", stacktrace.toString()); + data.put("thread", Thread.currentThread().toString()); + data.put("throwableMessage", crashData.getMessage()); + + EventEmitterWithData emitter = new EventEmitterWithData(null); + Attributes attributes = emitter.convertRichDataObjectIntoAttributes(data); + + assertEquals(attributes.size(), data.size()); + assertEquals(data.get("stacktrace"), attributes.get(AttributeKey.stringKey("stacktrace"))); + assertEquals(data.get("thread"), attributes.get(AttributeKey.stringKey("thread"))); + assertEquals( + data.get("throwableMessage"), + attributes.get(AttributeKey.stringKey("throwableMessage"))); + assertEquals(data.get("stringKey"), attributes.get(AttributeKey.stringKey("stringKey"))); + assertEquals(data.get("longKey"), attributes.get(AttributeKey.longKey("longKey"))); + assertEquals(data.get("doubleKey"), attributes.get(AttributeKey.doubleKey("doubleKey"))); + assertEquals(data.get("booleanKey"), attributes.get(AttributeKey.booleanKey("booleanKey"))); + } +}