Skip to content

Commit

Permalink
Initialize Sentry in OTEL Java Agent and allow configuring it (#2386)
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Nov 28, 2022
1 parent 82f359f commit 41586a4
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 43 deletions.
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ object Config {
val SENTRY_SPRING_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring"
val SENTRY_SPRING_BOOT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot"
val SENTRY_SPRING_BOOT_JAKARTA_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.spring-boot.jakarta"
val SENTRY_OPENTELEMETRY_AGENT_SDK_NAME = "$SENTRY_JAVA_SDK_NAME.opentelemetry.agent"
val group = "io.sentry"
val description = "SDK for sentry.io"
val versionNameProp = "versionName"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ tasks {
attributes.put("Can-Retransform-Classes", "true")
attributes.put("Implementation-Vendor", "Sentry")
attributes.put("Implementation-Version", "sentry-${project.version}-otel-${Config.Libs.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)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,87 @@
import io.opentelemetry.sdk.autoconfigure.spi.AutoConfigurationCustomizerProvider;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
import io.opentelemetry.sdk.trace.SdkTracerProviderBuilder;
import io.sentry.Instrumenter;
import io.sentry.Sentry;
import io.sentry.SentryOptions;
import io.sentry.protocol.SdkVersion;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class SentryAutoConfigurationCustomizerProvider
implements AutoConfigurationCustomizerProvider {

@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) {
Sentry.init(
options -> {
options.setEnableExternalConfiguration(true);
options.setInstrumenter(Instrumenter.OTEL);
final @Nullable SdkVersion sdkVersion = createSdkVersion(options);
if (sdkVersion != null) {
options.setSdkVersion(sdkVersion);
}
});
}

autoConfiguration
.addTracerProviderCustomizer(this::configureSdkTracerProvider)
.addPropertiesSupplier(this::getDefaultProperties);
}

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

try {
final @NotNull Enumeration<URL> resources =
ClassLoader.getSystemClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
try {
final @NotNull Manifest manifest = new Manifest(resources.nextElement().openStream());
final @Nullable Attributes mainAttributes = manifest.getMainAttributes();
if (mainAttributes != null) {
final @Nullable String name = mainAttributes.getValue("Sentry-Opentelemetry-SDK-Name");
final @Nullable String version = mainAttributes.getValue("Sentry-Version-Name");

if (name != null && version != null) {
sdkVersion = SdkVersion.updateSdkVersion(sdkVersion, name, version);
sdkVersion.addPackage("maven:io.sentry:sentry-opentelemetry-agent", version);
final @Nullable String otelVersion =
mainAttributes.getValue("Sentry-Opentelemetry-Version-Name");
if (otelVersion != null) {
sdkVersion.addPackage("maven:io.opentelemetry:opentelemetry-sdk", otelVersion);
}
final @Nullable String otelJavaagentVersion =
mainAttributes.getValue("Sentry-Opentelemetry-Javaagent-Version-Name");
if (otelJavaagentVersion != null) {
sdkVersion.addPackage(
"maven:io.opentelemetry.javaagent:opentelemetry-javaagent",
otelJavaagentVersion);
}
}
}
} catch (Exception e) {
// ignore
}
}
} catch (IOException e) {
// ignore
}

return sdkVersion;
}

private SdkTracerProviderBuilder configureSdkTracerProvider(
SdkTracerProviderBuilder tracerProvider, ConfigProperties config) {
return tracerProvider.addSpanProcessor(new SentrySpanProcessor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,8 @@ public <C> Context extract(
Context modifiedContext = context.with(SentryOtelKeys.SENTRY_TRACE_KEY, sentryTraceHeader);

final @Nullable String baggageString = getter.get(carrier, BaggageHeader.BAGGAGE_HEADER);
if (baggageString != null) {
Baggage baggage = Baggage.fromHeader(baggageString);
modifiedContext = modifiedContext.with(SentryOtelKeys.SENTRY_BAGGAGE_KEY, baggage);
}
Baggage baggage = Baggage.fromHeader(baggageString);
modifiedContext = modifiedContext.with(SentryOtelKeys.SENTRY_BAGGAGE_KEY, baggage);

Span wrappedSpan = Span.wrap(otelSpanContext);
modifiedContext = modifiedContext.with(wrappedSpan);
Expand Down

This file was deleted.

2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/Baggage.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public final class Baggage {
final @NotNull ILogger logger;

@NotNull
public static Baggage fromHeader(final String headerValue) {
public static Baggage fromHeader(final @Nullable String headerValue) {
return Baggage.fromHeader(
headerValue, false, HubAdapter.getInstance().getOptions().getLogger());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ final class ClasspathPropertiesLoader implements PropertiesLoader {
private final @NotNull ILogger logger;

public ClasspathPropertiesLoader(
@NotNull String fileName, @NotNull ClassLoader classLoader, @NotNull ILogger logger) {
@NotNull String fileName, @Nullable ClassLoader classLoader, @NotNull ILogger logger) {
this.fileName = fileName;
this.classLoader = classLoader;
// bootstrap classloader is represented as null, so using system classloader instead
if (classLoader == null) {
this.classLoader = ClassLoader.getSystemClassLoader();
} else {
this.classLoader = classLoader;
}
this.logger = logger;
}

public ClasspathPropertiesLoader(@NotNull ILogger logger) {
// TODO check not null
this("sentry.properties", ClasspathPropertiesLoader.class.getClassLoader(), logger);
}

Expand Down
11 changes: 11 additions & 0 deletions sentry/src/test/java/io/sentry/SentryTracerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import org.mockito.kotlin.never
import org.mockito.kotlin.spy
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.Date
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -119,6 +121,15 @@ class SentryTracerTest {
assertEquals(SpanStatus.ABORTED, tracer.status)
}

@Test
fun `when transaction is finished with status and timestamp, timestamp and status are set`() {
val tracer = fixture.getSut()
val date = Date.from(LocalDateTime.of(2022, 12, 24, 23, 59, 58, 0).toInstant(ZoneOffset.UTC))
tracer.finish(SpanStatus.ABORTED, date)
assertEquals(tracer.timestamp, DateUtils.dateToSeconds(date))
assertEquals(SpanStatus.ABORTED, tracer.status)
}

@Test
fun `when transaction is finished, transaction is captured`() {
val tracer = fixture.getSut()
Expand Down

0 comments on commit 41586a4

Please sign in to comment.