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

Add OpenTelemetryLinkErrorEventProcessor for linking errors to traces created via OpenTelemetry #2418

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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
### Features

- Add SENTRY_AUTO_INIT environment variable to control OpenTelemetry Agent init ([#2410](https://github.com/getsentry/sentry-java/pull/2410))
- Add OpenTelemetryLinkErrorEventProcessor for linking errors to traces created via OpenTelemetry ([#2418](https://github.com/getsentry/sentry-java/pull/2418))

## 6.9.1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
options -> {
options.setEnableExternalConfiguration(true);
options.setInstrumenter(Instrumenter.OTEL);
options.addEventProcessor(new OpenTelemetryLinkErrorEventProcessor());
final @Nullable SdkVersion sdkVersion = createSdkVersion(options);
if (sdkVersion != null) {
options.setSdkVersion(sdkVersion);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
public final class io/sentry/opentelemetry/OpenTelemetryLinkErrorEventProcessor : io/sentry/EventProcessor {
public fun <init> ()V
public fun process (Lio/sentry/SentryEvent;Lio/sentry/Hint;)Lio/sentry/SentryEvent;
}

public final class io/sentry/opentelemetry/OtelSpanInfo {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Lio/sentry/protocol/TransactionNameSource;)V
public fun getDescription ()Ljava/lang/String;
Expand Down Expand Up @@ -26,13 +31,6 @@ public final class io/sentry/opentelemetry/SentrySpanProcessor : io/opentelemetr
public fun onStart (Lio/opentelemetry/context/Context;Lio/opentelemetry/sdk/trace/ReadWriteSpan;)V
}

public final class io/sentry/opentelemetry/SentrySpanStorage {
public fun get (Ljava/lang/String;)Lio/sentry/ISpan;
public static fun getInstance ()Lio/sentry/opentelemetry/SentrySpanStorage;
public fun removeAndGet (Ljava/lang/String;)Lio/sentry/ISpan;
public fun store (Ljava/lang/String;Lio/sentry/ISpan;)V
}

public final class io/sentry/opentelemetry/SpanDescriptionExtractor {
public fun <init> ()V
public fun extractSpanDescription (Lio/opentelemetry/sdk/trace/ReadableSpan;)Lio/sentry/opentelemetry/OtelSpanInfo;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.sentry.opentelemetry;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanId;
import io.opentelemetry.api.trace.TraceId;
import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.HubAdapter;
import io.sentry.ISpan;
import io.sentry.Instrumenter;
import io.sentry.SentryEvent;
import io.sentry.SentrySpanStorage;
import io.sentry.SpanContext;
import io.sentry.protocol.SentryId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class OpenTelemetryLinkErrorEventProcessor implements EventProcessor {

private final @NotNull SentrySpanStorage spanStorage = SentrySpanStorage.getInstance();

@Override
public @Nullable SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) {
if (Instrumenter.OTEL.equals(HubAdapter.getInstance().getOptions().getInstrumenter())) {
@NotNull final Span otelSpan = Span.current();
@NotNull final String traceId = otelSpan.getSpanContext().getTraceId();
@NotNull final String spanId = otelSpan.getSpanContext().getSpanId();

if (TraceId.isValid(traceId) && SpanId.isValid(spanId)) {
final @Nullable ISpan sentrySpan = spanStorage.get(spanId);
if (sentrySpan != null) {
final @NotNull SpanContext sentrySpanSpanContext = sentrySpan.getSpanContext();
final @NotNull String operation = sentrySpanSpanContext.getOperation();
final @Nullable io.sentry.SpanId parentSpanId = sentrySpanSpanContext.getParentSpanId();
final @NotNull SpanContext spanContext =
new SpanContext(
new SentryId(traceId),
new io.sentry.SpanId(spanId),
operation,
parentSpanId,
null);

event.getContexts().setTrace(spanContext);
Copy link
Member

@markushi markushi Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

l: I'm probably missing some context here, but is it fine to override the existing trace context?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say yes because it only does so in case instrumenter is set to otel, there's an OTEL span with valid IDs and it can find the Sentry span in the shared storage. For now we don't allow starting transactions outside of OTEL if instrumenter is set to otel. So there shouldn't be anything worth keeping in there.

}
}
}

return event;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import io.sentry.Baggage;
import io.sentry.BaggageHeader;
import io.sentry.ISpan;
import io.sentry.SentrySpanStorage;
import io.sentry.SentryTraceHeader;
import io.sentry.exception.InvalidSentryTraceHeaderException;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.sentry.ISpan;
import io.sentry.ITransaction;
import io.sentry.Instrumenter;
import io.sentry.SentrySpanStorage;
import io.sentry.SentryTraceHeader;
import io.sentry.SpanId;
import io.sentry.SpanStatus;
Expand Down
7 changes: 7 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -1562,6 +1562,13 @@ public abstract interface class io/sentry/SentryOptions$TracesSamplerCallback {
public abstract fun sample (Lio/sentry/SamplingContext;)Ljava/lang/Double;
}

public final class io/sentry/SentrySpanStorage {
public fun get (Ljava/lang/String;)Lio/sentry/ISpan;
public static fun getInstance ()Lio/sentry/SentrySpanStorage;
public fun removeAndGet (Ljava/lang/String;)Lio/sentry/ISpan;
public fun store (Ljava/lang/String;Lio/sentry/ISpan;)V
}

public final class io/sentry/SentryTraceHeader {
public static final field SENTRY_TRACE_HEADER Ljava/lang/String;
public fun <init> (Lio/sentry/protocol/SentryId;Lio/sentry/SpanId;Ljava/lang/Boolean;)V
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package io.sentry.opentelemetry;
package io.sentry;

import io.sentry.ISpan;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
* Has been moved to `sentry` gradle module to include it in the bootstrap classloader without
* having to introduce yet another module for OpenTelemetry support.
*/
@ApiStatus.Internal
public final class SentrySpanStorage {
private static volatile @Nullable SentrySpanStorage INSTANCE;
Expand Down