Skip to content

Commit

Permalink
Add tests for linking errors to otel transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
adinauer committed Dec 13, 2022
1 parent 703d523 commit baf8bd5
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.sentry.EventProcessor;
import io.sentry.Hint;
import io.sentry.HubAdapter;
import io.sentry.IHub;
import io.sentry.ISpan;
import io.sentry.Instrumenter;
import io.sentry.SentryEvent;
Expand All @@ -14,14 +15,25 @@
import io.sentry.protocol.SentryId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;

public final class OpenTelemetryLinkErrorEventProcessor implements EventProcessor {

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

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

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

@Override
public @Nullable SentryEvent process(final @NotNull SentryEvent event, final @NotNull Hint hint) {
if (Instrumenter.OTEL.equals(HubAdapter.getInstance().getOptions().getInstrumenter())) {
if (Instrumenter.OTEL.equals(hub.getOptions().getInstrumenter())) {
@NotNull final Span otelSpan = Span.current();
@NotNull final String traceId = otelSpan.getSpanContext().getTraceId();
@NotNull final String spanId = otelSpan.getSpanContext().getSpanId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import io.opentelemetry.sdk.trace.SdkTracerProvider
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes
import io.sentry.Baggage
import io.sentry.BaggageHeader
import io.sentry.Hint
import io.sentry.IHub
import io.sentry.ISpan
import io.sentry.ITransaction
import io.sentry.Instrumenter
import io.sentry.SentryEvent
import io.sentry.SentryOptions
import io.sentry.SentryTraceHeader
import io.sentry.SpanStatus
Expand Down Expand Up @@ -66,6 +68,7 @@ class SentrySpanProcessorTest {
val hub = mock<IHub>()
val transaction = mock<ITransaction>()
val span = mock<ISpan>()
val spanContext = mock<io.sentry.SpanContext>()
lateinit var openTelemetry: OpenTelemetry
lateinit var tracer: Tracer
val sentryTrace = SentryTraceHeader(SENTRY_TRACE_HEADER_STRING)
Expand All @@ -76,6 +79,11 @@ class SentrySpanProcessorTest {
whenever(hub.options).thenReturn(options)
whenever(hub.startTransaction(any<TransactionContext>(), any<TransactionOptions>())).thenReturn(transaction)

whenever(spanContext.operation).thenReturn("spanContextOp")
whenever(spanContext.parentSpanId).thenReturn(io.sentry.SpanId("cedf5b7571cb4972"))

whenever(transaction.spanContext).thenReturn(spanContext)
whenever(span.spanContext).thenReturn(spanContext)
whenever(span.toSentryTrace()).thenReturn(sentryTrace)
whenever(transaction.toSentryTrace()).thenReturn(sentryTrace)

Expand Down Expand Up @@ -322,6 +330,40 @@ class SentrySpanProcessorTest {
thenTransactionIsFinished()
}

@Test
fun `links error to OTEL transaction`() {
fixture.setup()
val extractedContext = whenExtractingHeaders()

extractedContext.makeCurrent().use { _ ->
val otelSpan = givenSpanBuilder().startSpan()
thenTransactionIsStarted(otelSpan, isContinued = true)

otelSpan.makeCurrent().use { _ ->
val processedEvent = OpenTelemetryLinkErrorEventProcessor(fixture.hub).process(SentryEvent(), Hint())
val traceContext = processedEvent!!.contexts.trace!!

assertEquals("2722d9f6ec019ade60c776169d9a8904", traceContext.traceId.toString())
assertEquals(otelSpan.spanContext.spanId, traceContext.spanId.toString())
assertEquals("cedf5b7571cb4972", traceContext.parentSpanId.toString())
assertEquals("spanContextOp", traceContext.operation)
}

otelSpan.end()
thenTransactionIsFinished()
}
}

@Test
fun `does not link error to OTEL transaction if instrumenter does not match`() {
fixture.options.instrumenter = Instrumenter.SENTRY
fixture.setup()

val processedEvent = OpenTelemetryLinkErrorEventProcessor(fixture.hub).process(SentryEvent(), Hint())

thenNoTraceContextHasBeenAddedToEvent(processedEvent)
}

private fun givenSpanBuilder(spanKind: SpanKind = SpanKind.SERVER, parentSpan: Span? = null): SpanBuilder {
val spanName = if (parentSpan == null) "testspan" else "childspan"
val spanBuilder = fixture.tracer
Expand Down Expand Up @@ -430,6 +472,11 @@ class SentrySpanProcessorTest {
verify(fixture.transaction).setContext(eq("otel"), any())
verify(fixture.transaction).finish(eq(SpanStatus.OK), any<Date>())
}

private fun thenNoTraceContextHasBeenAddedToEvent(event: SentryEvent?) {
assertNotNull(event)
assertNull(event.contexts.trace)
}
}

class HeaderGetter : TextMapGetter<HttpHeaders> {
Expand Down

0 comments on commit baf8bd5

Please sign in to comment.