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

POC for POTEL with merged Hub/Scope #3258

Closed
wants to merge 2 commits into from
Closed
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 build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ allprojects {
repositories {
google()
mavenCentral()
mavenLocal()
}
group = Config.Sentry.group
version = properties[Config.Sentry.versionNameProp].toString()
Expand Down
7 changes: 4 additions & 3 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,14 @@ object Config {
val apolloKotlin = "com.apollographql.apollo3:apollo-runtime:3.8.2"

object OpenTelemetry {
val otelVersion = "1.33.0"
val otelVersion = "1.35.0"
val otelAlphaVersion = "$otelVersion-alpha"
val otelJavaagentVersion = "1.32.0"
val otelJavaagentAlphaVersion = "$otelJavaagentVersion-alpha"
val otelJavaagentVersion = "2.1.0"
val otelJavaagentAlphaVersion = "2.1.0-alpha"
val otelSemanticConvetionsVersion = "1.23.1-alpha"

val otelSdk = "io.opentelemetry:opentelemetry-sdk:$otelVersion"
val otelContext = "io.opentelemetry:opentelemetry-context:$otelVersion"
val otelSemconv = "io.opentelemetry.semconv:opentelemetry-semconv:$otelSemanticConvetionsVersion"
val otelJavaAgent = "io.opentelemetry.javaagent:opentelemetry-javaagent:$otelJavaagentVersion"
val otelJavaAgentExtensionApi = "io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:$otelJavaagentAlphaVersion"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package io.sentry.opentelemetry;

import io.opentelemetry.context.ContextStorage;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizer;
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor;
import io.sentry.Instrumenter;
import io.sentry.Sentry;
import io.sentry.SentryIntegrationPackageStorage;
Expand Down Expand Up @@ -50,6 +52,8 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
}
}

ContextStorage.addWrapper((storage) -> new SentryContextStorage(storage));

autoConfiguration
.addTracerProviderCustomizer(this::configureSdkTracerProvider)
.addPropertiesSupplier(this::getDefaultProperties);
Expand Down Expand Up @@ -140,7 +144,9 @@ private static class VersionInfoHolder {

private SdkTracerProviderBuilder configureSdkTracerProvider(
SdkTracerProviderBuilder tracerProvider, ConfigProperties config) {
return tracerProvider.addSpanProcessor(new SentrySpanProcessor());
return tracerProvider
.addSpanProcessor(new PotelSentrySpanProcessor())
.addSpanProcessor(BatchSpanProcessor.builder(new SentrySpanExporter()).build());
}

private Map<String, String> getDefaultProperties() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
public final class SentryPropagatorProvider implements ConfigurablePropagatorProvider {
@Override
public TextMapPropagator getPropagator(ConfigProperties config) {
return new SentryPropagator();
// return new SentryPropagator();
return new PotelSentryPropagator();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
public final class io/sentry/opentelemetry/InternalSemanticAttributes {
public static final field BREADCRUMB_TYPE Lio/opentelemetry/api/common/AttributeKey;
public static final field IS_REMOTE_PARENT Lio/opentelemetry/api/common/AttributeKey;
public static final field OP Lio/opentelemetry/api/common/AttributeKey;
public static final field ORIGIN Lio/opentelemetry/api/common/AttributeKey;
public static final field PARENT_SAMPLED Lio/opentelemetry/api/common/AttributeKey;
public static final field SAMPLE_RATE Lio/opentelemetry/api/common/AttributeKey;
public static final field SOURCE Lio/opentelemetry/api/common/AttributeKey;
public fun <init> ()V
}

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;
Expand All @@ -10,10 +21,19 @@ public final class io/sentry/opentelemetry/OtelSpanInfo {
public fun getTransactionNameSource ()Lio/sentry/protocol/TransactionNameSource;
}

public final class io/sentry/opentelemetry/SentryOtelKeys {
public static final field SENTRY_BAGGAGE_KEY Lio/opentelemetry/context/ContextKey;
public static final field SENTRY_TRACE_KEY Lio/opentelemetry/context/ContextKey;
public final class io/sentry/opentelemetry/PotelSentryPropagator : io/opentelemetry/context/propagation/TextMapPropagator {
public fun <init> ()V
public fun extract (Lio/opentelemetry/context/Context;Ljava/lang/Object;Lio/opentelemetry/context/propagation/TextMapGetter;)Lio/opentelemetry/context/Context;
public fun fields ()Ljava/util/Collection;
public fun inject (Lio/opentelemetry/context/Context;Ljava/lang/Object;Lio/opentelemetry/context/propagation/TextMapSetter;)V
}

public final class io/sentry/opentelemetry/PotelSentrySpanProcessor : io/opentelemetry/sdk/trace/SpanProcessor {
public fun <init> ()V
public fun isEndRequired ()Z
public fun isStartRequired ()Z
public fun onEnd (Lio/opentelemetry/sdk/trace/ReadableSpan;)V
public fun onStart (Lio/opentelemetry/context/Context;Lio/opentelemetry/sdk/trace/ReadWriteSpan;)V
}

public final class io/sentry/opentelemetry/SentryPropagator : io/opentelemetry/context/propagation/TextMapPropagator {
Expand All @@ -23,6 +43,14 @@ public final class io/sentry/opentelemetry/SentryPropagator : io/opentelemetry/c
public fun inject (Lio/opentelemetry/context/Context;Ljava/lang/Object;Lio/opentelemetry/context/propagation/TextMapSetter;)V
}

public final class io/sentry/opentelemetry/SentrySpanExporter : io/opentelemetry/sdk/trace/export/SpanExporter {
public fun <init> ()V
public fun <init> (Lio/sentry/IHub;)V
public fun export (Ljava/util/Collection;)Lio/opentelemetry/sdk/common/CompletableResultCode;
public fun flush ()Lio/opentelemetry/sdk/common/CompletableResultCode;
public fun shutdown ()Lio/opentelemetry/sdk/common/CompletableResultCode;
}

public final class io/sentry/opentelemetry/SentrySpanProcessor : io/opentelemetry/sdk/trace/SpanProcessor {
public fun <init> ()V
public fun isEndRequired ()Z
Expand All @@ -36,6 +64,18 @@ public final class io/sentry/opentelemetry/SpanDescriptionExtractor {
public fun extractSpanDescription (Lio/opentelemetry/sdk/trace/ReadableSpan;)Lio/sentry/opentelemetry/OtelSpanInfo;
}

public final class io/sentry/opentelemetry/SpanNode {
public fun <init> (Ljava/lang/String;)V
public fun addChild (Lio/sentry/opentelemetry/SpanNode;)V
public fun addChildren (Ljava/util/List;)V
public fun getChildren ()Ljava/util/List;
public fun getId ()Ljava/lang/String;
public fun getParentNode ()Lio/sentry/opentelemetry/SpanNode;
public fun getSpan ()Lio/opentelemetry/sdk/trace/data/SpanData;
public fun setParentNode (Lio/sentry/opentelemetry/SpanNode;)V
public fun setSpan (Lio/opentelemetry/sdk/trace/data/SpanData;)V
}

public final class io/sentry/opentelemetry/TraceData {
public fun <init> (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/sentry/SentryTraceHeader;Lio/sentry/Baggage;)V
public fun getBaggage ()Lio/sentry/Baggage;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.sentry.opentelemetry;

import io.opentelemetry.api.common.AttributeKey;

// TODO context key vs attribute key
public final class InternalSemanticAttributes {
public static final AttributeKey<String> ORIGIN = AttributeKey.stringKey("sentry.origin");
public static final AttributeKey<String> OP = AttributeKey.stringKey("sentry.op");
public static final AttributeKey<String> SOURCE = AttributeKey.stringKey("sentry.source");
public static final AttributeKey<Double> SAMPLE_RATE =
AttributeKey.doubleKey("sentry.sample_rate");
public static final AttributeKey<Boolean> PARENT_SAMPLED =
AttributeKey.booleanKey("sentry.parentSampled");
public static final AttributeKey<Boolean> IS_REMOTE_PARENT =
AttributeKey.booleanKey("sentry.isParentRemote");
public static final AttributeKey<String> BREADCRUMB_TYPE =
AttributeKey.stringKey("sentry.breadcrumb.type");
// public static final AttributeKey<SentryLevel> BREADCRUMB_TYPE =
// InternalAttributeKeyImpl.create("sentry.breadcrumb.type", SentryLevel.class);
// BREADCRUMB_TYPE("sentry.breadcrumb.type"),
// BREADCRUMB_LEVEL("sentry.breadcrumb.level"),
// BREADCRUMB_EVENT_ID("sentry.breadcrumb.event_id"),
// BREADCRUMB_CATEGORY("sentry.breadcrumb.category"),
// BREADCRUMB_DATA("sentry.breadcrumb.data");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package io.sentry.opentelemetry;

import static io.sentry.opentelemetry.SentryOtelKeys.SENTRY_SCOPES_KEY;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.TraceFlags;
import io.opentelemetry.api.trace.TraceState;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapGetter;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.sentry.BaggageHeader;
import io.sentry.HubAdapter;
import io.sentry.IHub;
import io.sentry.PropagationContext;
import io.sentry.Scopes;
import io.sentry.SentryLevel;
import io.sentry.SentryTraceHeader;
import io.sentry.exception.InvalidSentryTraceHeaderException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class PotelSentryPropagator implements TextMapPropagator {

private static final @NotNull List<String> FIELDS =
Arrays.asList(SentryTraceHeader.SENTRY_TRACE_HEADER, BaggageHeader.BAGGAGE_HEADER);
// private final @NotNull SentryWeakSpanStorage spanStorage =
// SentryWeakSpanStorage.getInstance();
private final @NotNull IHub hub;

public PotelSentryPropagator() {
this(HubAdapter.getInstance());
}

PotelSentryPropagator(final @NotNull IHub hub) {
this.hub = hub;
}

@Override
public Collection<String> fields() {
return FIELDS;
}

@Override
public <C> void inject(final Context context, final C carrier, final TextMapSetter<C> setter) {
final @NotNull Span otelSpan = Span.fromContext(context);
final @NotNull SpanContext otelSpanContext = otelSpan.getSpanContext();
if (!otelSpanContext.isValid()) {
hub.getOptions()
.getLogger()
.log(
SentryLevel.DEBUG,
"Not injecting Sentry tracing information for invalid OpenTelemetry span.");
return;
}

/**
* TODO
*
* <p>maybe it could work like this:
*
* <p>getIsolationScope() check if there's a PropagationContext on there and use that for
* generating headers and freezing
*
* <p>if that's not there check Context for data and attach headers
*/

// TODO: inject from OTEL SpanContext and TraceState
System.out.println("TODO");
// TODO how to inject?
// final @Nullable ISpan sentrySpan = spanStorage.get(otelSpanContext.getSpanId());
// if (sentrySpan == null || sentrySpan.isNoOp()) {
// hub.getOptions()
// .getLogger()
// .log(
// SentryLevel.DEBUG,
// "Not injecting Sentry tracing information for span %s as no Sentry span has been
// found or it is a NoOp (trace %s). This might simply mean this is a request to Sentry.",
// otelSpanContext.getSpanId(),
// otelSpanContext.getTraceId());
// return;
// }
//
// final @NotNull SentryTraceHeader sentryTraceHeader = sentrySpan.toSentryTrace();
// setter.set(carrier, sentryTraceHeader.getName(), sentryTraceHeader.getValue());
// final @Nullable BaggageHeader baggageHeader =
// sentrySpan.toBaggageHeader(Collections.emptyList());
// if (baggageHeader != null) {
// setter.set(carrier, baggageHeader.getName(), baggageHeader.getValue());
// }
}

@Override
public <C> Context extract(
final Context context, final C carrier, final TextMapGetter<C> getter) {
final @Nullable Scopes scopesFromParentContext = context.get(SENTRY_SCOPES_KEY);
final @NotNull Scopes scopes =
scopesFromParentContext != null
? scopesFromParentContext.forkedScopes("propagator")
: Scopes.forkedRoots("propagator");

final @Nullable String sentryTraceString =
getter.get(carrier, SentryTraceHeader.SENTRY_TRACE_HEADER);
if (sentryTraceString == null) {

final @NotNull Context modifiedContext = context.with(SENTRY_SCOPES_KEY, scopes);
// return context.with(SENTRY_SCOPES_KEY, scopes);
return modifiedContext;
}
// else {
// // TODO clean up code here
// // TODO should we rely on OTEL trace/span ids here?
// scopes.getIsolationScope().setPropagationContext(new PropagationContext());
// }

try {
SentryTraceHeader sentryTraceHeader = new SentryTraceHeader(sentryTraceString);

final @Nullable String baggageString = getter.get(carrier, BaggageHeader.BAGGAGE_HEADER);
// Baggage baggage = Baggage.fromHeader(baggageString);

// final @NotNull TraceState traceState = TraceState.builder().put("todo.dsc",
// baggage.).build();
final @NotNull TraceState traceState = TraceState.getDefault();

SpanContext otelSpanContext =
SpanContext.createFromRemoteParent(
sentryTraceHeader.getTraceId().toString(),
sentryTraceHeader.getSpanId().toString(),
TraceFlags.getSampled(),
traceState);

Span wrappedSpan = Span.wrap(otelSpanContext);

final @NotNull Context modifiedContext =
context.with(wrappedSpan).with(SENTRY_SCOPES_KEY, scopes);

hub.getOptions()
.getLogger()
.log(SentryLevel.DEBUG, "Continuing Sentry trace %s", sentryTraceHeader.getTraceId());

final @NotNull PropagationContext propagationContext =
PropagationContext.fromHeaders(
hub.getOptions().getLogger(), sentryTraceString, baggageString);
scopes.getIsolationScope().setPropagationContext(propagationContext);

return modifiedContext;
} catch (InvalidSentryTraceHeaderException e) {
hub.getOptions()
.getLogger()
.log(
SentryLevel.ERROR,
"Unable to extract Sentry tracing information from invalid header.",
e);
return context;
}
}
}
Loading