From 582b441e90e8ac3e0c3d2898d2878bbad843ea84 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Mon, 14 Nov 2022 15:49:27 +0100 Subject: [PATCH 1/5] Add contexts to SentryTracer and add otel context to it --- .../sentry/opentelemetry/SentrySpanProcessor.java | 3 +-- sentry/api/sentry.api | 6 ++++++ sentry/src/main/java/io/sentry/ITransaction.java | 8 ++++++++ sentry/src/main/java/io/sentry/NoOpTransaction.java | 12 ++++++++++++ sentry/src/main/java/io/sentry/SentryTracer.java | 13 +++++++++++++ .../java/io/sentry/protocol/SentryTransaction.java | 3 +++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java index fd1e73f6d55..70bedc077f6 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java @@ -176,8 +176,7 @@ private void updateTransactionWithOtelData( spanDescription.getDescription(), spanDescription.getTransactionNameSource()); final @NotNull Map otelContext = toOtelContext(otelSpan); - System.out.println(otelContext); - // TODO set otel context on transaction + sentryTransaction.setContext("otel", otelContext); } private @NotNull Map toOtelContext(final @NotNull ReadableSpan otelSpan) { diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index e3bd6f13806..365565ad0ca 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -516,6 +516,7 @@ public abstract interface class io/sentry/ISpan { } public abstract interface class io/sentry/ITransaction : io/sentry/ISpan { + public abstract fun getContexts ()Ljava/util/Map; public abstract fun getEventId ()Lio/sentry/protocol/SentryId; public abstract fun getLatestActiveSpan ()Lio/sentry/Span; public abstract fun getName ()Ljava/lang/String; @@ -525,6 +526,7 @@ public abstract interface class io/sentry/ITransaction : io/sentry/ISpan { public abstract fun isProfileSampled ()Ljava/lang/Boolean; public abstract fun isSampled ()Ljava/lang/Boolean; public abstract fun scheduleFinish ()V + public abstract fun setContext (Ljava/lang/String;Ljava/lang/Object;)V public abstract fun setName (Ljava/lang/String;)V public abstract fun setName (Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V } @@ -765,6 +767,7 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { public fun finish ()V public fun finish (Lio/sentry/SpanStatus;)V public fun finish (Lio/sentry/SpanStatus;Ljava/util/Date;)V + public fun getContexts ()Ljava/util/Map; public fun getData (Ljava/lang/String;)Ljava/lang/Object; public fun getDescription ()Ljava/lang/String; public fun getEventId ()Lio/sentry/protocol/SentryId; @@ -783,6 +786,7 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { public fun isProfileSampled ()Ljava/lang/Boolean; public fun isSampled ()Ljava/lang/Boolean; public fun scheduleFinish ()V + public fun setContext (Ljava/lang/String;Ljava/lang/Object;)V public fun setData (Ljava/lang/String;Ljava/lang/Object;)V public fun setDescription (Ljava/lang/String;)V public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V @@ -1564,6 +1568,7 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun finish (Lio/sentry/SpanStatus;)V public fun finish (Lio/sentry/SpanStatus;Ljava/util/Date;)V public fun getChildren ()Ljava/util/List; + public fun getContexts ()Ljava/util/Map; public fun getData ()Ljava/util/Map; public fun getData (Ljava/lang/String;)Ljava/lang/Object; public fun getDescription ()Ljava/lang/String; @@ -1585,6 +1590,7 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun isProfileSampled ()Ljava/lang/Boolean; public fun isSampled ()Ljava/lang/Boolean; public fun scheduleFinish ()V + public fun setContext (Ljava/lang/String;Ljava/lang/Object;)V public fun setData (Ljava/lang/String;Ljava/lang/Object;)V public fun setDescription (Ljava/lang/String;)V public fun setMeasurement (Ljava/lang/String;Ljava/lang/Number;)V diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index bed79fec6b7..a7319397eba 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -3,6 +3,7 @@ import io.sentry.protocol.SentryId; import io.sentry.protocol.TransactionNameSource; import java.util.List; +import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -77,4 +78,11 @@ public interface ITransaction extends ISpan { /** Schedules when transaction should be automatically finished. */ void scheduleFinish(); + + @ApiStatus.Internal + void setContext(@NotNull String key, @NotNull Object context); + + @ApiStatus.Internal + @NotNull + Map getContexts(); } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index bb731576a0c..dc3ba96bb2b 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -5,6 +5,8 @@ import java.util.Collections; import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -177,4 +179,14 @@ public void setMeasurement(@NotNull String name, @NotNull Number value) {} @Override public void setMeasurement( @NotNull String name, @NotNull Number value, @NotNull MeasurementUnit unit) {} + + @ApiStatus.Internal + @Override + public void setContext(@NotNull String key, @NotNull Object context) {} + + @ApiStatus.Internal + @Override + public @NotNull Map getContexts() { + return new ConcurrentHashMap<>(); + } } diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 1d2c2993147..1837ce865ca 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -78,6 +78,7 @@ public final class SentryTracer implements ITransaction { private @NotNull TransactionNameSource transactionNameSource; private final @NotNull Map measurements; private final @NotNull Instrumenter instrumenter; + private final @NotNull Map contexts = new ConcurrentHashMap<>(); public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { this(context, hub, null); @@ -661,6 +662,18 @@ Map getMeasurements() { return measurements; } + @ApiStatus.Internal + @Override + public void setContext(@NotNull String key, @NotNull Object context) { + contexts.put(key, context); + } + + @ApiStatus.Internal + @Override + public @NotNull Map getContexts() { + return contexts; + } + private static final class FinishStatus { static final FinishStatus NOT_FINISHED = FinishStatus.notFinished(); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index a1e96fa3607..fab4b2ae426 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -67,6 +67,9 @@ public SentryTransaction(final @NotNull SentryTracer sentryTracer) { } } final Contexts contexts = this.getContexts(); + + contexts.putAll(sentryTracer.getContexts()); + final SpanContext tracerContext = sentryTracer.getSpanContext(); // tags must be placed on the root of the transaction instead of contexts.trace.tags contexts.setTrace( From 93058290543550b12fef39af35fcbfa1bdb49a07 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 15 Nov 2022 08:06:17 +0100 Subject: [PATCH 2/5] Use contexts instead of map on SentryTracer --- sentry-android-core/last_crash | 1 + .../build.gradle.kts | 4 ++-- .../opentelemetry/SentrySpanProcessor.java | 20 +++++++++++++++++-- sentry/api/sentry.api | 6 +++--- .../src/main/java/io/sentry/ITransaction.java | 4 ++-- .../main/java/io/sentry/NoOpTransaction.java | 7 +++---- .../src/main/java/io/sentry/SentryTracer.java | 5 +++-- 7 files changed, 32 insertions(+), 15 deletions(-) create mode 100644 sentry-android-core/last_crash diff --git a/sentry-android-core/last_crash b/sentry-android-core/last_crash new file mode 100644 index 00000000000..bfb8d0c6add --- /dev/null +++ b/sentry-android-core/last_crash @@ -0,0 +1 @@ +2022-11-11T10:33:27.818Z \ No newline at end of file diff --git a/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts b/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts index ed0f93dace0..32f3bf1f84c 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts +++ b/sentry-opentelemetry/sentry-opentelemetry-agent/build.gradle.kts @@ -145,8 +145,8 @@ tasks { attributes.put("Premain-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") attributes.put("Can-Redefine-Classes", "true") attributes.put("Can-Retransform-Classes", "true") - attributes.put("Implementation-Vendor", "Demo") - attributes.put("Implementation-Version", "demo-${project.version}-otel-${Config.Libs.otelJavaagentVersion}") + attributes.put("Implementation-Vendor", "Sentry") + attributes.put("Implementation-Version", "sentry-${project.version}-otel-${Config.Libs.otelJavaagentVersion}") } } diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java index 70bedc077f6..66c252af3d3 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java @@ -1,5 +1,6 @@ package io.sentry.opentelemetry; +import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.api.trace.SpanKind; import io.opentelemetry.api.trace.StatusCode; @@ -183,8 +184,8 @@ private void updateTransactionWithOtelData( final @NotNull SpanData spanData = otelSpan.toSpanData(); final @NotNull Map context = new HashMap<>(); - context.put("attributes", spanData.getAttributes().asMap()); - context.put("resource", spanData.getResource().getAttributes().asMap()); + context.put("attributes", toMapWithStringKeys(spanData.getAttributes())); + context.put("resource", toMapWithStringKeys(spanData.getResource().getAttributes())); return context; } @@ -233,4 +234,19 @@ private SpanStatus mapOtelStatus(final @NotNull ReadableSpan otelSpan) { private boolean hasSentryBeenInitialized() { return Sentry.isEnabled(); } + + private @NotNull Map toMapWithStringKeys(@Nullable Attributes attributes) { + @NotNull Map mapWithStringKeys = new HashMap<>(); + + if (attributes != null) { + attributes.forEach( + (key, value) -> { + if (key != null) { + mapWithStringKeys.put(key.getKey(), value); + } + }); + } + + return mapWithStringKeys; + } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 365565ad0ca..13c54eb75fb 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -516,7 +516,7 @@ public abstract interface class io/sentry/ISpan { } public abstract interface class io/sentry/ITransaction : io/sentry/ISpan { - public abstract fun getContexts ()Ljava/util/Map; + public abstract fun getContexts ()Lio/sentry/protocol/Contexts; public abstract fun getEventId ()Lio/sentry/protocol/SentryId; public abstract fun getLatestActiveSpan ()Lio/sentry/Span; public abstract fun getName ()Ljava/lang/String; @@ -767,7 +767,7 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { public fun finish ()V public fun finish (Lio/sentry/SpanStatus;)V public fun finish (Lio/sentry/SpanStatus;Ljava/util/Date;)V - public fun getContexts ()Ljava/util/Map; + public fun getContexts ()Lio/sentry/protocol/Contexts; public fun getData (Ljava/lang/String;)Ljava/lang/Object; public fun getDescription ()Ljava/lang/String; public fun getEventId ()Lio/sentry/protocol/SentryId; @@ -1568,7 +1568,7 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun finish (Lio/sentry/SpanStatus;)V public fun finish (Lio/sentry/SpanStatus;Ljava/util/Date;)V public fun getChildren ()Ljava/util/List; - public fun getContexts ()Ljava/util/Map; + public fun getContexts ()Lio/sentry/protocol/Contexts; public fun getData ()Ljava/util/Map; public fun getData (Ljava/lang/String;)Ljava/lang/Object; public fun getDescription ()Ljava/lang/String; diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index a7319397eba..6e1c525fe88 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -1,9 +1,9 @@ package io.sentry; +import io.sentry.protocol.Contexts; import io.sentry.protocol.SentryId; import io.sentry.protocol.TransactionNameSource; import java.util.List; -import java.util.Map; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -84,5 +84,5 @@ public interface ITransaction extends ISpan { @ApiStatus.Internal @NotNull - Map getContexts(); + Contexts getContexts(); } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index dc3ba96bb2b..9df2241ad8f 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -1,12 +1,11 @@ package io.sentry; +import io.sentry.protocol.Contexts; import io.sentry.protocol.SentryId; import io.sentry.protocol.TransactionNameSource; import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -186,7 +185,7 @@ public void setContext(@NotNull String key, @NotNull Object context) {} @ApiStatus.Internal @Override - public @NotNull Map getContexts() { - return new ConcurrentHashMap<>(); + public @NotNull Contexts getContexts() { + return new Contexts(); } } diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 1837ce865ca..62932b3902b 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -1,5 +1,6 @@ package io.sentry; +import io.sentry.protocol.Contexts; import io.sentry.protocol.MeasurementValue; import io.sentry.protocol.SentryId; import io.sentry.protocol.SentryTransaction; @@ -78,7 +79,7 @@ public final class SentryTracer implements ITransaction { private @NotNull TransactionNameSource transactionNameSource; private final @NotNull Map measurements; private final @NotNull Instrumenter instrumenter; - private final @NotNull Map contexts = new ConcurrentHashMap<>(); + private final @NotNull Contexts contexts = new Contexts(); public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { this(context, hub, null); @@ -670,7 +671,7 @@ public void setContext(@NotNull String key, @NotNull Object context) { @ApiStatus.Internal @Override - public @NotNull Map getContexts() { + public @NotNull Contexts getContexts() { return contexts; } From 6cd522a0fb3592d2be92ea42bd978a71c0bee974 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 15 Nov 2022 08:48:50 +0100 Subject: [PATCH 3/5] Remove crash marker --- sentry-android-core/last_crash | 1 - 1 file changed, 1 deletion(-) delete mode 100644 sentry-android-core/last_crash diff --git a/sentry-android-core/last_crash b/sentry-android-core/last_crash deleted file mode 100644 index bfb8d0c6add..00000000000 --- a/sentry-android-core/last_crash +++ /dev/null @@ -1 +0,0 @@ -2022-11-11T10:33:27.818Z \ No newline at end of file From bde13a9c410d4fff1feb94b85dedbb4bf5bca802 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 15 Nov 2022 09:09:09 +0100 Subject: [PATCH 4/5] Add test for contexts --- .../test/java/io/sentry/SentryTracerTest.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index 304fe75300c..5f0b9f2dd20 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -207,6 +207,31 @@ class SentryTracerTest { ) } + @Test + fun `when transaction is finished, context is set`() { + val tracer = fixture.getSut() + val otelContext = mapOf( + "attributes" to mapOf( + "db.connection_string" to "hsqldb:mem:", + "db.statement" to "CREATE TABLE person ( id INTEGER IDENTITY PRIMARY KEY, firstName VARCHAR(?) NOT NULL, lastName VARCHAR(?) NOT NULL )" + ), + "resource" to mapOf( + "process.runtime.version" to "17.0.4.1+1", + "telemetry.auto.version" to "sentry-6.7.0-otel-1.19.2" + ) + ) + tracer.setContext("otel", otelContext) + tracer.finish() + + verify(fixture.hub).captureTransaction( + check { + assertEquals(otelContext, it.contexts["otel"]) + }, + anyOrNull(), + anyOrNull() + ) + } + @Test fun `returns sentry-trace header`() { val tracer = fixture.getSut() From 71d79f1e9e4dd5cd5826c393596de7b385b93c75 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 16 Nov 2022 15:36:54 +0100 Subject: [PATCH 5/5] Code Review changes --- .../java/io/sentry/opentelemetry/SentrySpanProcessor.java | 4 ++-- sentry/src/main/java/io/sentry/SentryTracer.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java index 66c252af3d3..51191d232ba 100644 --- a/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java +++ b/sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanProcessor.java @@ -235,8 +235,8 @@ private boolean hasSentryBeenInitialized() { return Sentry.isEnabled(); } - private @NotNull Map toMapWithStringKeys(@Nullable Attributes attributes) { - @NotNull Map mapWithStringKeys = new HashMap<>(); + private @NotNull Map toMapWithStringKeys(final @Nullable Attributes attributes) { + final @NotNull Map mapWithStringKeys = new HashMap<>(); if (attributes != null) { attributes.forEach( diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 62932b3902b..7af02aa22ae 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -665,7 +665,7 @@ Map getMeasurements() { @ApiStatus.Internal @Override - public void setContext(@NotNull String key, @NotNull Object context) { + public void setContext(final @NotNull String key, final @NotNull Object context) { contexts.put(key, context); }