Skip to content
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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
- Fix `ClassNotFoundException` for `io.sentry.spring.SentrySpringServletContainerInitializer` in `sentry-spring-jakarta` ([#2411](https://github.com/getsentry/sentry-java/issues/2411))
- Fix `sentry-samples-spring-jakarta` ([#2411](https://github.com/getsentry/sentry-java/issues/2411))

### 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))

### Dependencies

- Bump OpenTelemetry to 1.20.1 and OpenTelemetry Java Agent to 1.20.2 ([#2420](https://github.com/getsentry/sentry-java/pull/2420))

## 6.9.1

### Fixes
Expand Down
17 changes: 13 additions & 4 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,19 @@ object Config {

val apolloKotlin = "com.apollographql.apollo3:apollo-runtime:3.3.0"

val otelVersion = "1.19.0"
val otelAlphaVersion = "1.19.0-alpha"
val otelJavaagentVersion = "1.19.2"
val otelJavaagentAlphaVersion = "1.19.2-alpha"
object OpenTelemetry {
val otelVersion = "1.20.1"
val otelAlphaVersion = "1.20.1-alpha"
val otelJavaagentVersion = "1.20.2"
val otelJavaagentAlphaVersion = "1.20.2-alpha"

val otelSdk = "io.opentelemetry:opentelemetry-sdk:$otelVersion"
val otelSemconv = "io.opentelemetry:opentelemetry-semconv:$otelAlphaVersion"
val otelJavaAgent = "io.opentelemetry.javaagent:opentelemetry-javaagent:$otelJavaagentVersion"
val otelJavaAgentExtensionApi = "io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:$otelJavaagentAlphaVersion"
val otelJavaAgentTooling = "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:$otelJavaagentAlphaVersion"
val otelExtensionAutoconfigureSpi = "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:$otelVersion"
}
}

object AnnotationProcessors {
Expand Down
7 changes: 7 additions & 0 deletions sentry-opentelemetry/sentry-opentelemetry-agent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ Sentry.init(
Using the `otel` instrumenter will ensure `Sentry` instrumentation will be done via OpenTelemetry
and integrations as well as direct interactions with transactions and spans have no effect.

## Controlling auto initialization of Sentry

By default if you pass either `SENTRY_DSN` or `SENTRY_PROPERTIES_FILE` as environment variable,
Sentry will automatically be initialized by this agent. To disable this behaviour, you can set
`SENTRY_AUTO_INIT=false` as environment variable. You will then have to initialize Sentry inside
the target application.

## Debugging

To enable debug logging for Sentry, please provide `SENTRY_DEBUG=true` as environment variable or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ fun relocatePackages(shadowJar: ShadowJar) {
// rewrite dependencies calling Logger.getLogger
shadowJar.relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger")

// rewrite library instrumentation dependencies
shadowJar.relocate("io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation")
// prevents conflict with library instrumentation, since these classes live in the bootstrap class loader
shadowJar.relocate("io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation") {
// Exclude resource providers since they live in the agent class loader
exclude("io.opentelemetry.instrumentation.resources.*")
exclude("io.opentelemetry.instrumentation.spring.resources.*")
}

// relocate OpenTelemetry API usage
shadowJar.relocate("io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api")
Expand Down Expand Up @@ -50,7 +54,7 @@ val upstreamAgent = configurations.create("upstreamAgent") {
dependencies {
bootstrapLibs(projects.sentry)
javaagentLibs(projects.sentryOpentelemetry.sentryOpentelemetryAgentcustomization)
upstreamAgent("io.opentelemetry.javaagent:opentelemetry-javaagent:${Config.Libs.otelJavaagentVersion}")
upstreamAgent(Config.Libs.OpenTelemetry.otelJavaAgent)
}

fun isolateClasses(jars: Iterable<File>): CopySpec {
Expand Down Expand Up @@ -146,11 +150,11 @@ tasks {
attributes.put("Can-Redefine-Classes", "true")
attributes.put("Can-Retransform-Classes", "true")
attributes.put("Implementation-Vendor", "Sentry")
attributes.put("Implementation-Version", "sentry-${project.version}-otel-${Config.Libs.otelJavaagentVersion}")
attributes.put("Implementation-Version", "sentry-${project.version}-otel-${Config.Libs.OpenTelemetry.otelJavaagentVersion}")
attributes.put("Sentry-Version-Name", project.version)
attributes.put("Sentry-Opentelemetry-SDK-Name", Config.Sentry.SENTRY_OPENTELEMETRY_AGENT_SDK_NAME)
attributes.put("Sentry-Opentelemetry-Version-Name", Config.Libs.otelVersion)
attributes.put("Sentry-Opentelemetry-Javaagent-Version-Name", Config.Libs.otelJavaagentVersion)
attributes.put("Sentry-Opentelemetry-Version-Name", Config.Libs.OpenTelemetry.otelVersion)
attributes.put("Sentry-Opentelemetry-Javaagent-Version-Name", Config.Libs.OpenTelemetry.otelJavaagentVersion)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ dependencies {
compileOnly(projects.sentry)
implementation(projects.sentryOpentelemetry.sentryOpentelemetryCore)

compileOnly("io.opentelemetry:opentelemetry-sdk:${Config.Libs.otelVersion}")
compileOnly("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi:${Config.Libs.otelVersion}")
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${Config.Libs.otelJavaagentAlphaVersion}")
compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${Config.Libs.otelJavaagentAlphaVersion}")
compileOnly(Config.Libs.OpenTelemetry.otelSdk)
compileOnly(Config.Libs.OpenTelemetry.otelExtensionAutoconfigureSpi)
compileOnly(Config.Libs.OpenTelemetry.otelJavaAgentExtensionApi)
compileOnly(Config.Libs.OpenTelemetry.otelJavaAgentTooling)

compileOnly(Config.CompileOnly.nopen)
errorprone(Config.CompileOnly.nopenChecker)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@ public final class SentryAutoConfigurationCustomizerProvider

@Override
public void customize(AutoConfigurationCustomizer autoConfiguration) {
final @Nullable String sentryPropertiesFile = System.getenv("SENTRY_PROPERTIES_FILE");
final @Nullable String sentryDsn = System.getenv("SENTRY_DSN");

if (sentryPropertiesFile != null || sentryDsn != null) {
if (isSentryAutoInitEnabled()) {
Sentry.init(
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 All @@ -43,6 +41,19 @@ public void customize(AutoConfigurationCustomizer autoConfiguration) {
.addPropertiesSupplier(this::getDefaultProperties);
}

private boolean isSentryAutoInitEnabled() {
final @Nullable String sentryAutoInit = System.getenv("SENTRY_AUTO_INIT");

if (sentryAutoInit != null) {
return "true".equalsIgnoreCase(sentryAutoInit);
} else {
final @Nullable String sentryPropertiesFile = System.getenv("SENTRY_PROPERTIES_FILE");
final @Nullable String sentryDsn = System.getenv("SENTRY_DSN");

return sentryPropertiesFile != null || sentryDsn != null;
}
}

private @Nullable SdkVersion createSdkVersion(final @NotNull SentryOptions sentryOptions) {
SdkVersion sdkVersion = sentryOptions.getSdkVersion();

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
Expand Up @@ -21,8 +21,8 @@ tasks.withType<KotlinCompile>().configureEach {
dependencies {
compileOnly(projects.sentry)

compileOnly("io.opentelemetry:opentelemetry-sdk:${Config.Libs.otelVersion}")
compileOnly("io.opentelemetry:opentelemetry-semconv:${Config.Libs.otelAlphaVersion}")
compileOnly(Config.Libs.OpenTelemetry.otelSdk)
compileOnly(Config.Libs.OpenTelemetry.otelSemconv)

compileOnly(Config.CompileOnly.nopen)
errorprone(Config.CompileOnly.nopenChecker)
Expand All @@ -37,8 +37,8 @@ dependencies {
testImplementation(Config.TestLibs.mockitoKotlin)
testImplementation(Config.TestLibs.awaitility)

testImplementation("io.opentelemetry:opentelemetry-sdk:${Config.Libs.otelVersion}")
testImplementation("io.opentelemetry:opentelemetry-semconv:${Config.Libs.otelAlphaVersion}")
testImplementation(Config.Libs.OpenTelemetry.otelSdk)
testImplementation(Config.Libs.OpenTelemetry.otelSemconv)
}

configure<SourceSetContainer> {
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);
}
}
}

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