From ab204bdeecc0eea3accec6258dbbed4c6904a8e4 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 3 Mar 2021 16:26:29 +0100 Subject: [PATCH 01/26] WIP --- .../SentrySpanRestTemplateCustomizerTest.kt | 4 +- .../spring/tracing/SentrySpanAdviceTest.kt | 15 +- .../spring/tracing/SentryTracingFilterTest.kt | 5 +- .../tracing/SentryTransactionAdviceTest.kt | 5 +- sentry/src/main/java/io/sentry/Hub.java | 56 ++-- .../src/main/java/io/sentry/HubAdapter.java | 2 +- sentry/src/main/java/io/sentry/IHub.java | 4 +- .../main/java/io/sentry/ISentryClient.java | 4 +- sentry/src/main/java/io/sentry/ISpan.java | 16 +- .../src/main/java/io/sentry/ITransaction.java | 8 - sentry/src/main/java/io/sentry/NoOpHub.java | 6 +- .../main/java/io/sentry/NoOpSentryClient.java | 2 +- sentry/src/main/java/io/sentry/NoOpSpan.java | 10 + .../main/java/io/sentry/NoOpTransaction.java | 5 + .../src/main/java/io/sentry/SentryClient.java | 34 ++- .../java/io/sentry/SentryEnvelopeItem.java | 2 +- .../src/main/java/io/sentry/SentryTracer.java | 234 +++++++++++++++++ .../java/io/sentry/SentryTransaction.java | 247 ++---------------- sentry/src/main/java/io/sentry/Span.java | 104 +++++++- .../test/java/io/sentry/GsonSerializerTest.kt | 8 +- sentry/src/test/java/io/sentry/HubTest.kt | 22 +- sentry/src/test/java/io/sentry/ScopeTest.kt | 20 +- .../test/java/io/sentry/SentryClientTest.kt | 24 +- .../test/java/io/sentry/SentryTracerTest.kt | 179 +++++++++++++ .../java/io/sentry/SentryTransactionTest.kt | 183 ------------- sentry/src/test/java/io/sentry/SpanTest.kt | 172 ++++++------ .../io/sentry/transport/RateLimiterTest.kt | 9 +- 27 files changed, 757 insertions(+), 623 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/SentryTracer.java create mode 100644 sentry/src/test/java/io/sentry/SentryTracerTest.kt delete mode 100644 sentry/src/test/java/io/sentry/SentryTransactionTest.kt diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt index b42ecff415..b3cded2ae3 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt @@ -5,9 +5,11 @@ import com.nhaarman.mockitokotlin2.whenever import io.sentry.IHub import io.sentry.Scope import io.sentry.SentryOptions +import io.sentry.SentryTracer import io.sentry.SentryTransaction import io.sentry.SpanContext import io.sentry.SpanStatus +import io.sentry.TransactionContext import kotlin.test.Test import org.assertj.core.api.Assertions.assertThat import org.springframework.http.HttpMethod @@ -23,7 +25,7 @@ class SentrySpanRestTemplateCustomizerTest { val hub = mock() val restTemplate = RestTemplate() var mockServer = MockRestServiceServer.createServer(restTemplate) - val transaction = SentryTransaction("aTransaction", SpanContext("op", true), hub) + val transaction = SentryTracer(TransactionContext("aTransaction", "op"), hub) internal val customizer = SentrySpanRestTemplateCustomizer(hub) fun getSut(isTransactionActive: Boolean, status: HttpStatus = HttpStatus.OK): RestTemplate { diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentrySpanAdviceTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentrySpanAdviceTest.kt index 4e33a00fb8..194e941a80 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentrySpanAdviceTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentrySpanAdviceTest.kt @@ -6,6 +6,7 @@ import com.nhaarman.mockitokotlin2.whenever import io.sentry.IHub import io.sentry.Scope import io.sentry.SentryOptions +import io.sentry.SentryTracer import io.sentry.SentryTransaction import io.sentry.SpanContext import io.sentry.SpanStatus @@ -42,13 +43,13 @@ class SentrySpanAdviceTest { @BeforeTest fun setup() { - whenever(hub.startTransaction(any(), any())).thenAnswer { SentryTransaction(it.arguments[0] as String, SpanContext(it.arguments[1] as String), hub) } + whenever(hub.startTransaction(any(), any())).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, hub) } } @Test fun `when class is annotated with @SentrySpan, every method call attaches span to existing transaction`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) @@ -62,7 +63,7 @@ class SentrySpanAdviceTest { @Test fun `when class is annotated with @SentrySpan with operation set, every method call attaches span to existing transaction`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) @@ -76,7 +77,7 @@ class SentrySpanAdviceTest { @Test fun `when method is annotated with @SentrySpan with properties set, attaches span to existing transaction`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) @@ -90,7 +91,7 @@ class SentrySpanAdviceTest { @Test fun `when method is annotated with @SentrySpan without properties set, attaches span to existing transaction and sets Span description as className dot methodName`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) @@ -104,7 +105,7 @@ class SentrySpanAdviceTest { @Test fun `when method is annotated with @SentrySpan and returns, attached span has status OK`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) @@ -115,7 +116,7 @@ class SentrySpanAdviceTest { @Test fun `when method is annotated with @SentrySpan and throws exception, attached span has throwable set and INTERNAL_ERROR status`() { val scope = Scope(SentryOptions()) - val tx = SentryTransaction("aTransaction", SpanContext("op"), hub) + val tx = SentryTracer(TransactionContext("aTransaction", "op"), hub) scope.setTransaction(tx) whenever(hub.span).thenReturn(tx) diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt index 620f348d5e..97f3510cdf 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt @@ -11,6 +11,7 @@ import com.nhaarman.mockitokotlin2.verifyZeroInteractions import com.nhaarman.mockitokotlin2.whenever import io.sentry.IHub import io.sentry.SentryOptions +import io.sentry.SentryTracer import io.sentry.SentryTransaction import io.sentry.SpanContext import io.sentry.SpanId @@ -47,10 +48,10 @@ class SentryTracingFilterTest { request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, "/product/{id}") if (sentryTraceHeader != null) { request.addHeader("sentry-trace", sentryTraceHeader) - whenever(hub.startTransaction(any(), any())).thenAnswer { SentryTransaction((it.arguments[0] as TransactionContext).name, it.arguments[0] as SpanContext, hub) } + whenever(hub.startTransaction(any(), any())).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, hub) } } response.status = 200 - whenever(hub.startTransaction(any(), any(), any())).thenAnswer { SentryTransaction(it.arguments[0] as String, SpanContext(it.arguments[1] as String), hub) } + whenever(hub.startTransaction(any(), any(), any())).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, hub) } whenever(hub.isEnabled).thenReturn(isEnabled) return SentryTracingFilter(hub, sentryRequestResolver, transactionNameProvider) } diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt index c0f922bc72..c9f461792e 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt @@ -12,6 +12,7 @@ import io.sentry.Scope import io.sentry.ScopeCallback import io.sentry.SentryOptions import io.sentry.SpanContext +import io.sentry.TransactionContext import kotlin.test.BeforeTest import kotlin.test.Test import org.assertj.core.api.Assertions.assertThat @@ -42,7 +43,7 @@ class SentryTransactionAdviceTest { @BeforeTest fun setup() { - whenever(hub.startTransaction(any(), any())).thenAnswer { io.sentry.SentryTransaction(it.arguments[0] as String, SpanContext(it.arguments[1] as String), hub) } + whenever(hub.startTransaction(any(), any())).thenAnswer { io.sentry.SentryTracer(TransactionContext(it.arguments[0] as String, it.arguments[1] as String), hub) } } @Test @@ -66,7 +67,7 @@ class SentryTransactionAdviceTest { @Test fun `when transaction is already active, does not start new transaction`() { val scope = Scope(SentryOptions()) - scope.setTransaction(io.sentry.SentryTransaction("aTransaction", SpanContext("op"), hub)) + scope.setTransaction(io.sentry.SentryTracer(TransactionContext("aTransaction", "op"), hub)) whenever(hub.configureScope(any())).thenAnswer { (it.arguments[0] as ScopeCallback).run(scope) diff --git a/sentry/src/main/java/io/sentry/Hub.java b/sentry/src/main/java/io/sentry/Hub.java index eb69c70669..59b3102263 100644 --- a/sentry/src/main/java/io/sentry/Hub.java +++ b/sentry/src/main/java/io/sentry/Hub.java @@ -516,32 +516,32 @@ public void flush(long timeoutMillis) { @ApiStatus.Internal @Override public @NotNull SentryId captureTransaction( - final @NotNull ITransaction transaction, final @Nullable Object hint) { + final @NotNull SentryTransaction transaction, final @Nullable Object hint) { Objects.requireNonNull(transaction, "transaction is required"); SentryId sentryId = SentryId.EMPTY_ID; if (!isEnabled()) { options - .getLogger() - .log( - SentryLevel.WARNING, - "Instance is disabled and this 'captureTransaction' call is a no-op."); + .getLogger() + .log( + SentryLevel.WARNING, + "Instance is disabled and this 'captureTransaction' call is a no-op."); } else { if (!transaction.isFinished()) { options - .getLogger() - .log( - SentryLevel.WARNING, - "Capturing unfinished transaction: %s", - transaction.getEventId()); + .getLogger() + .log( + SentryLevel.WARNING, + "Capturing unfinished transaction: %s", + transaction.getEventId()); } if (!Boolean.TRUE.equals(transaction.isSampled())) { options - .getLogger() - .log( - SentryLevel.DEBUG, - "Transaction %s was dropped due to sampling decision.", - transaction.getEventId()); + .getLogger() + .log( + SentryLevel.DEBUG, + "Transaction %s was dropped due to sampling decision.", + transaction.getEventId()); } else { StackItem item = null; try { @@ -549,18 +549,20 @@ public void flush(long timeoutMillis) { sentryId = item.getClient().captureTransaction(transaction, item.getScope(), hint); } catch (Exception e) { options - .getLogger() - .log( - SentryLevel.ERROR, - "Error while capturing transaction with id: " + transaction.getEventId(), - e); + .getLogger() + .log( + SentryLevel.ERROR, + "Error while capturing transaction with id: " + transaction.getEventId(), + e); } finally { +// TODO: clear transaction if (item != null) { + // with transaction thread safe final Scope scope = item.getScope(); - if (scope.getTransaction() == transaction) { + // pass tracer as a hint + if (scope.getTransaction() == /**/) { scope.clearTransaction(); } - } } } } @@ -594,7 +596,7 @@ public void flush(long timeoutMillis) { boolean samplingDecision = tracesSampler.sample(samplingContext); transactionContext.setSampled(samplingDecision); - transaction = new SentryTransaction(transactionContext, this); + transaction = new SentryTracer(transactionContext, this); } return transaction; } @@ -646,4 +648,12 @@ SpanContext getSpanContext(final @NotNull Throwable throwable) { } return null; } + + public void clearTransaction(SentryTracer transaction) { + final StackItem item = stack.peek(); + final Scope scope = item.getScope(); + if (scope.getTransaction() == transaction) { + scope.clearTransaction(); + } + } } diff --git a/sentry/src/main/java/io/sentry/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java index bd5e68c20a..51d9964fc3 100644 --- a/sentry/src/main/java/io/sentry/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -154,7 +154,7 @@ public IHub clone() { } @Override - public @NotNull SentryId captureTransaction(ITransaction transaction, Object hint) { + public @NotNull SentryId captureTransaction(SentryTransaction transaction, Object hint) { return Sentry.getCurrentHub().captureTransaction(transaction, hint); } diff --git a/sentry/src/main/java/io/sentry/IHub.java b/sentry/src/main/java/io/sentry/IHub.java index f54ab48786..2094db725e 100644 --- a/sentry/src/main/java/io/sentry/IHub.java +++ b/sentry/src/main/java/io/sentry/IHub.java @@ -266,7 +266,7 @@ default void addBreadcrumb(@NotNull String message, @NotNull String category) { * @return transaction's id */ @ApiStatus.Internal - SentryId captureTransaction(ITransaction transaction, Object hint); + SentryId captureTransaction(SentryTransaction transaction, Object hint); /** * Captures the transaction and enqueues it for sending to Sentry server. @@ -275,7 +275,7 @@ default void addBreadcrumb(@NotNull String message, @NotNull String category) { * @return transaction's id */ @ApiStatus.Internal - default SentryId captureTransaction(ITransaction transaction) { + default SentryId captureTransaction(SentryTransaction transaction) { return captureTransaction(transaction, null); } diff --git a/sentry/src/main/java/io/sentry/ISentryClient.java b/sentry/src/main/java/io/sentry/ISentryClient.java index 138c88092e..5353505f65 100644 --- a/sentry/src/main/java/io/sentry/ISentryClient.java +++ b/sentry/src/main/java/io/sentry/ISentryClient.java @@ -194,7 +194,7 @@ default SentryId captureEnvelope(SentryEnvelope envelope) { * @param hint SDK specific but provides high level information about the origin of the event * @return The Id (SentryId object) of the event */ - SentryId captureTransaction(ITransaction transaction, Scope scope, Object hint); + SentryId captureTransaction(SentryTransaction transaction, Scope scope, Object hint); /** * Captures a transaction without scope nor hint. @@ -202,7 +202,7 @@ default SentryId captureEnvelope(SentryEnvelope envelope) { * @param transaction the {@link ITransaction} to send * @return The Id (SentryId object) of the event */ - default SentryId captureTransaction(ITransaction transaction) { + default SentryId captureTransaction(SentryTransaction transaction) { return captureTransaction(transaction, null, null); } } diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index bd78c8dc05..bb9a6e0f65 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -5,6 +5,7 @@ /** Represents performance monitoring Span. */ public interface ISpan { + String NAME_TAG = "sentry-name"; /** * Starts a child Span. * @@ -47,14 +48,14 @@ public interface ISpan { * * @param operation - the operation */ - void setOperation(@Nullable String operation); + void setOperation(@NotNull String operation); /** * Returns the span operation. * * @return the operation */ - @Nullable + @NotNull String getOperation(); /** @@ -118,10 +119,21 @@ public interface ISpan { */ void setTag(@NotNull String key, @NotNull String value); + @Nullable + String getTag(@NotNull String key); + /** * Returns if span has finished. * * @return if span has finished. */ boolean isFinished(); + + /** + * Returns if transaction is sampled. + * + * @return is sampled + */ + @Nullable + Boolean isSampled(); } diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index 641cfa6fad..c898896f79 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -48,14 +48,6 @@ public interface ITransaction extends ISpan { @TestOnly List getSpans(); - /** - * Returns if transaction is sampled. - * - * @return is sampled - */ - @Nullable - Boolean isSampled(); - /** * Returns the latest span that is not finished. * diff --git a/sentry/src/main/java/io/sentry/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java index 5e1cc48559..34aaba2317 100644 --- a/sentry/src/main/java/io/sentry/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -115,19 +115,19 @@ public IHub clone() { @Override public SentryId captureTransaction( - final @NotNull ITransaction transaction, final @Nullable Object hint) { + final @NotNull SentryTransaction transaction, final @Nullable Object hint) { return SentryId.EMPTY_ID; } @Override public @NotNull ITransaction startTransaction(TransactionContext transactionContexts) { - return new SentryTransaction(transactionContexts, NoOpHub.getInstance()); + return NoOpTransaction.getInstance(); } @Override public @NotNull ITransaction startTransaction( TransactionContext transactionContexts, CustomSamplingContext customSamplingContext) { - return new SentryTransaction(transactionContexts, NoOpHub.getInstance()); + return NoOpTransaction.getInstance(); } @Override diff --git a/sentry/src/main/java/io/sentry/NoOpSentryClient.java b/sentry/src/main/java/io/sentry/NoOpSentryClient.java index 703cc9122f..037c2c76bf 100644 --- a/sentry/src/main/java/io/sentry/NoOpSentryClient.java +++ b/sentry/src/main/java/io/sentry/NoOpSentryClient.java @@ -41,7 +41,7 @@ public SentryId captureEnvelope(SentryEnvelope envelope, @Nullable Object hint) } @Override - public SentryId captureTransaction(ITransaction transaction, Scope scope, Object hint) { + public SentryId captureTransaction(SentryTransaction transaction, Scope scope, Object hint) { return SentryId.EMPTY_ID; } } diff --git a/sentry/src/main/java/io/sentry/NoOpSpan.java b/sentry/src/main/java/io/sentry/NoOpSpan.java index 9561997356..c2fd982dd5 100644 --- a/sentry/src/main/java/io/sentry/NoOpSpan.java +++ b/sentry/src/main/java/io/sentry/NoOpSpan.java @@ -76,8 +76,18 @@ public void setThrowable(@Nullable Throwable throwable) {} @Override public void setTag(@NotNull String key, @NotNull String value) {} + @Override + public @Nullable String getTag(@NotNull String key) { + return null; + } + @Override public boolean isFinished() { return false; } + + @Override + public @Nullable Boolean isSampled() { + return null; + } } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index ae1706b3fe..78b944ccd6 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -130,4 +130,9 @@ public void setThrowable(@Nullable Throwable throwable) {} @Override public void setTag(@NotNull String key, @NotNull String value) {} + + @Override + public @Nullable String getTag(@NotNull String key) { + return null; + } } diff --git a/sentry/src/main/java/io/sentry/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java index 6464ba8153..079234bf8a 100644 --- a/sentry/src/main/java/io/sentry/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -341,7 +341,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec @Override public @NotNull SentryId captureTransaction( - final @NotNull ITransaction transaction, + final @NotNull SentryTransaction transaction, final @NotNull Scope scope, final @Nullable Object hint) { Objects.requireNonNull(transaction, "Transaction is required."); @@ -352,26 +352,22 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec SentryId sentryId = transaction.getEventId(); - if (transaction instanceof SentryTransaction) { - final SentryTransaction sentryTransaction = - processTransaction((SentryTransaction) transaction); - try { - final SentryEnvelope envelope = - buildEnvelope(sentryTransaction, filterForTransaction(getAttachmentsFromScope(scope))); - if (envelope != null) { - transport.send(envelope, hint); - } else { - sentryId = SentryId.EMPTY_ID; - } - } catch (IOException e) { - options - .getLogger() - .log(SentryLevel.WARNING, e, "Capturing transaction %s failed.", sentryId); - // if there was an error capturing the event, we return an emptyId + final SentryTransaction sentryTransaction = + processTransaction(transaction); + try { + final SentryEnvelope envelope = + buildEnvelope(sentryTransaction, filterForTransaction(getAttachmentsFromScope(scope))); + if (envelope != null) { + transport.send(envelope, hint); + } else { sentryId = SentryId.EMPTY_ID; } - } else { - options.getLogger().log(SentryLevel.DEBUG, "Captured a NoOpTransaction %s", sentryId); + } catch (IOException e) { + options + .getLogger() + .log(SentryLevel.WARNING, e, "Capturing transaction %s failed.", sentryId); + // if there was an error capturing the event, we return an emptyId + sentryId = SentryId.EMPTY_ID; } return sentryId; diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java index 416ed9aea1..39e00722e4 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java @@ -118,7 +118,7 @@ public final class SentryEnvelopeItem { return new SentryEnvelopeItem(itemHeader, () -> cachedItem.getBytes()); } - public @Nullable ITransaction getTransaction(final @NotNull ISerializer serializer) + public @Nullable SentryTransaction getTransaction(final @NotNull ISerializer serializer) throws Exception { if (header == null || header.getType() != SentryItemType.Transaction) { return null; diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java new file mode 100644 index 0000000000..28077e965e --- /dev/null +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -0,0 +1,234 @@ +package io.sentry; + +import io.sentry.protocol.Contexts; +import io.sentry.protocol.Request; +import io.sentry.protocol.SentryId; +import io.sentry.util.Objects; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicReference; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class SentryTracer implements ITransaction { + private final @NotNull Span root; + private final @NotNull List children = new CopyOnWriteArrayList<>(); + private final @NotNull IHub hub; + + public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { + Objects.requireNonNull(context, "context is required"); + Objects.requireNonNull(hub, "hub is required"); + this.root = new Span(context, this, hub); + this.root.setTag(ISpan.NAME_TAG, context.getName()); + this.hub = hub; + } + + public @NotNull List getChildren() { + return children; + } + + public @NotNull Date getStartTimestamp() { + return this.root.getStartTimestamp(); + } + + public @Nullable Date getTimestamp() { + return this.root.getTimestamp(); + } + + /** + * Starts a child Span with given trace id and parent span id. + * + * @param parentSpanId - parent span id + * @param operation - span operation name + * @param description - span description + * @return a new transaction span + */ + @NotNull + ISpan startChild( + final @NotNull SpanId parentSpanId, + final @NotNull String operation, + final @Nullable String description) { + final ISpan span = startChild(parentSpanId, operation); + span.setDescription(description); + return span; + } + + /** + * Starts a child Span with given trace id and parent span id. + * + * @param parentSpanId - parent span id + * @return a new transaction span + */ + @NotNull + private ISpan startChild(final @NotNull SpanId parentSpanId, final @NotNull String operation) { + Objects.requireNonNull(parentSpanId, "parentSpanId is required"); + Objects.requireNonNull(operation, "operation is required"); + final Span span = new Span(root.getTraceId(), parentSpanId, this, operation, this.hub); + this.children.add(span); + return span; + } + + @Override + public @NotNull ISpan startChild(final @NotNull String operation) { + return root.startChild(operation); + } + + @Override + public @NotNull ISpan startChild( + final @NotNull String operation, final @Nullable String description) { + return root.startChild(operation, description); + } + + @Override + public @NotNull SentryTraceHeader toSentryTrace() { + return root.toSentryTrace(); + } + + @Override + public void finish() { + this.finish(this.getStatus()); + } + + @Override + public void finish(@Nullable SpanStatus status) { + // clear the transaction from the scope atomically + // with manoels api + ((Hub) hub).clearTransaction(this); + root.finish(status); + SentryTransaction transaction = new SentryTransaction(this); + hub.captureTransaction(transaction, this); + } + + @Override + public void setOperation(final @NotNull String operation) { + this.root.setOperation(operation); + } + + @Override + public @NotNull String getOperation() { + return this.root.getOperation(); + } + + @Override + public void setDescription(final @Nullable String description) { + this.root.setDescription(description); + } + + @Override + public @Nullable String getDescription() { + return this.root.getDescription(); + } + + @Override + public void setStatus(final @Nullable SpanStatus status) { + this.root.setStatus(status); + } + + @Override + public @Nullable SpanStatus getStatus() { + return this.root.getStatus(); + } + + @Override + public void setThrowable(final @Nullable Throwable throwable) { + this.root.setThrowable(throwable); + } + + @Override + public @Nullable Throwable getThrowable() { + return this.root.getThrowable(); + } + + @Override + public @NotNull SpanContext getSpanContext() { + return this.root.getSpanContext(); + } + + @Override + public void setTag(final @NotNull String key, final @NotNull String value) { + this.root.setTag(key, value); + } + + @Override + public @Nullable String getTag(final @NotNull String key) { + return this.root.getTag(key); + } + + @Override + public boolean isFinished() { + return this.root.isFinished(); + } + + @Override + public @Nullable Boolean isSampled() { + return this.root.isSampled(); + } + + @Override + public void setName(@NotNull String name) { + this.root.setTag(ISpan.NAME_TAG, name); + } + + @Override + public @NotNull String getName() { + return this.root.getTag(ISpan.NAME_TAG); + } + + @Override + public void setRequest(@Nullable Request request) { + hub.configureScope(scope -> scope.setRequest(request)); + } + + @Override + public @Nullable Request getRequest() { + final AtomicReference contexts = new AtomicReference<>(); + hub.configureScope(scope -> contexts.set(scope.getRequest())); + return contexts.get(); + } + + @Override + public @NotNull Contexts getContexts() { + final AtomicReference contexts = new AtomicReference<>(); + hub.configureScope(scope -> contexts.set(scope.getContexts())); + return contexts.get(); + } + + @Override + public @NotNull List getSpans() { + return this.children; + } + + @Override + public @Nullable Span getLatestActiveSpan() { + final List spans = new ArrayList<>(this.children); + if (!spans.isEmpty()) { + for (int i = spans.size() - 1; i >= 0; i--) { + if (!spans.get(i).isFinished()) { + return spans.get(i); + } + } + } + return null; + } + + @Override + @Deprecated + @ApiStatus.ScheduledForRemoval + public @Nullable SentryId getEventId() { + return null; + } + + @Override + public @Nullable String getTransaction() { + return this.getName(); + } + + @NotNull + Span getRoot() { + return root; + } +} diff --git a/sentry/src/main/java/io/sentry/SentryTransaction.java b/sentry/src/main/java/io/sentry/SentryTransaction.java index 7cff259a63..3a6864103a 100644 --- a/sentry/src/main/java/io/sentry/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/SentryTransaction.java @@ -1,20 +1,18 @@ package io.sentry; -import io.sentry.protocol.SentryId; -import io.sentry.util.Objects; -import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; @ApiStatus.Internal -public final class SentryTransaction extends SentryBaseEvent implements ITransaction { +public final class SentryTransaction extends SentryBaseEvent { /** The transaction name. */ - private @NotNull String transaction; + @SuppressWarnings("UnusedVariable") + private @Nullable String transaction; /** The moment in time when span was started. */ private final @NotNull Date startTimestamp; @@ -24,250 +22,45 @@ public final class SentryTransaction extends SentryBaseEvent implements ITransac /** A list of spans within this transaction. Can be empty. */ private final @NotNull List spans = new CopyOnWriteArrayList<>(); - /** - * A hub this transaction is attached to. Marked as transient to be ignored during JSON - * serialization. - */ - private final transient @NotNull IHub hub; - - private final transient @NotNull SpanContext context; /** The {@code type} property is required in JSON payload sent to Sentry. */ @SuppressWarnings("UnusedVariable") private @NotNull final String type = "transaction"; - /** Creates transaction. */ - SentryTransaction(final @NotNull String name, final @NotNull String operation) { - this(name, new SpanContext(operation), NoOpHub.getInstance()); - } - - SentryTransaction(final @NotNull TransactionContext transactionContext, final @NotNull IHub hub) { - this(transactionContext.getName(), transactionContext, hub); - } - - /** - * Creates transaction with name and contexts. - * - * @param name - transaction name - * @param context - transaction contexts - * @param hub - the hub - */ - @TestOnly - public SentryTransaction( - final @NotNull String name, final @NotNull SpanContext context, final @NotNull IHub hub) { - this.transaction = Objects.requireNonNull(name, "name is required"); - this.startTimestamp = DateUtils.getCurrentDateTime(); - this.hub = Objects.requireNonNull(hub, "hub is required"); - this.context = Objects.requireNonNull(context, "contexts is required"); - } - - /** - * Sets transaction name. - * - * @param name - transaction name - */ - @Override - public void setName(final @NotNull String name) { - Objects.requireNonNull(name, "name is required"); - this.transaction = name; - } - - @Override - public @NotNull String getName() { - return this.transaction; - } - - /** - * Starts a child Span. - * - * @return a new transaction span - */ - @Override - public @NotNull ISpan startChild(final @NotNull String operation) { - return this.startChild(operation, null); - } - - /** - * Starts a child Span. - * - * @param operation - new span operation name - * @param description - new span description name - * @return a new transaction span - */ - @Override - public @NotNull ISpan startChild( - final @NotNull String operation, final @Nullable String description) { - return startChild(getSpanId(), operation, description); - } - - /** - * Starts a child Span with given trace id and parent span id. - * - * @param parentSpanId - parent span id - * @return a new transaction span - */ - @NotNull - private ISpan startChild(final @NotNull SpanId parentSpanId, final @NotNull String operation) { - Objects.requireNonNull(parentSpanId, "parentSpanId is required"); - Objects.requireNonNull(operation, "operation is required"); - final Span span = new Span(getTraceId(), parentSpanId, this, operation, this.hub); - this.spans.add(span); - return span; - } - - /** - * Starts a child Span with given trace id and parent span id. - * - * @param parentSpanId - parent span id - * @param operation - span operation name - * @param description - span description - * @return a new transaction span - */ - @NotNull - ISpan startChild( - final @NotNull SpanId parentSpanId, - final @NotNull String operation, - final @Nullable String description) { - final ISpan span = startChild(parentSpanId, operation); - span.setDescription(description); - return span; - } - - @Override - public @NotNull SentryTraceHeader toSentryTrace() { - return new SentryTraceHeader(getTraceId(), getSpanId(), isSampled()); - } - - @NotNull - SpanId getSpanId() { - return this.context.getSpanId(); - } - - @NotNull - SentryId getTraceId() { - return this.context.getTraceId(); - } - - @Override - public @Nullable Boolean isSampled() { - return this.context.getSampled(); - } - - @Override - public void finish() { + public SentryTransaction(SentryTracer sentryTracer) { + this.spans.addAll(sentryTracer.getChildren()); + this.startTimestamp = sentryTracer.getStartTimestamp(); this.timestamp = DateUtils.getCurrentDateTime(); - if (this.throwable != null) { - hub.setSpanContext(this.throwable, this); - } - this.getContexts().setTrace(this.context); - this.hub.captureTransaction(this, null); - } - - @Override - public void finish(@Nullable SpanStatus status) { - this.setStatus(status); - this.finish(); + this.transaction = sentryTracer.getTag(ISpan.NAME_TAG); + this.getContexts().setTrace(sentryTracer.getSpanContext()); } - /** - * Sets transaction operation. - * - * @param op - operation - */ - @Override - public void setOperation(@Nullable String op) { - this.context.setOperation(op); - } - - @Override - public @Nullable String getOperation() { - return this.context.getOperation(); - } - - /** - * Sets transaction description. - * - * @param description - the description. - */ - @Override - public void setDescription(@Nullable String description) { - this.context.setDescription(description); - } - - @Override - public @Nullable String getDescription() { - return this.context.getDescription(); - } - - @Override - public @NotNull SpanContext getSpanContext() { - return this.context; + public @NotNull List getSpans() { + return spans; } - /** - * Sets transaction status. - * - * @param spanStatus - the status - */ - @Override - public void setStatus(@Nullable SpanStatus spanStatus) { - this.context.setStatus(spanStatus); + public boolean isFinished() { + return this.timestamp != null; } - /** - * Returns the transaction name. - * - * @return transaction name. - */ - @Override - @ApiStatus.Internal public @Nullable String getTransaction() { return transaction; } - @NotNull - Date getStartTimestamp() { + public @NotNull Date getStartTimestamp() { return startTimestamp; } - @Nullable - Date getTimestamp() { + public @Nullable Date getTimestamp() { return timestamp; } - @Override - @Nullable - public SpanStatus getStatus() { - return context.getStatus(); - } - - @Override - @TestOnly - public @NotNull List getSpans() { - return spans; + public @NotNull String getType() { + return type; } - /** @return the latest span that is not finished or null if not found. */ - @Override - public @Nullable Span getLatestActiveSpan() { - final List spans = new ArrayList<>(this.spans); - if (!spans.isEmpty()) { - for (int i = spans.size() - 1; i >= 0; i--) { - if (!spans.get(i).isFinished()) { - return spans.get(i); - } - } - } - return null; - } - - @NotNull - SpanContext getContext() { - return context; - } - - @Override - public boolean isFinished() { - return this.timestamp != null; + public boolean isSampled() { + final SpanContext trace = this.getContexts().getTrace(); + return trace != null && Objects.equals(trace.getSampled(), Boolean.TRUE); } } diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index 0d9d4fdba6..862e3f1fe0 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -3,21 +3,26 @@ import io.sentry.protocol.SentryId; import io.sentry.util.Objects; import java.util.Date; + +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public final class Span extends SpanContext implements ISpan { +@ApiStatus.Internal +public final class Span implements ISpan { /** The moment in time when span was started. */ private final @NotNull Date startTimestamp; /** The moment in time when span has ended. */ private @Nullable Date timestamp; + private final @NotNull SpanContext context; + /** * A transaction this span is attached to. Marked as transient to be ignored during JSON * serialization. */ - private final transient @NotNull SentryTransaction transaction; + private final transient @NotNull SentryTracer transaction; /** A throwable thrown during the execution of the span. */ private transient @Nullable Throwable throwable; @@ -25,17 +30,28 @@ public final class Span extends SpanContext implements ISpan { private final transient @NotNull IHub hub; Span( - final @NotNull SentryId traceId, - final @NotNull SpanId parentSpanId, - final @NotNull SentryTransaction transaction, - final @NotNull String operation, - final @NotNull IHub hub) { - super(traceId, new SpanId(), operation, parentSpanId, transaction.isSampled()); + final @NotNull SentryId traceId, + final @Nullable SpanId parentSpanId, + final @NotNull SentryTracer transaction, + final @NotNull String operation, + final @NotNull IHub hub) { + this.context = + new SpanContext(traceId, new SpanId(), operation, parentSpanId, transaction.isSampled()); this.transaction = Objects.requireNonNull(transaction, "transaction is required"); this.startTimestamp = DateUtils.getCurrentDateTime(); this.hub = Objects.requireNonNull(hub, "hub is required"); } + Span( + final @NotNull TransactionContext context, + final @NotNull SentryTracer sentryTracer, + final @NotNull IHub hub) { + this.context = Objects.requireNonNull(context, "context is required"); + this.transaction = Objects.requireNonNull(sentryTracer, "sentryTracer is required"); + this.hub = Objects.requireNonNull(hub, "hub is required"); + this.startTimestamp = DateUtils.getCurrentDateTime(); + } + public @NotNull Date getStartTimestamp() { return startTimestamp; } @@ -51,13 +67,13 @@ public final class Span extends SpanContext implements ISpan { @Override public @NotNull ISpan startChild( - final @NotNull String operation, final @Nullable String description) { - return transaction.startChild(super.getSpanId(), operation, description); + final @NotNull String operation, final @Nullable String description) { + return transaction.startChild(context.getSpanId(), operation, description); } @Override public @NotNull SentryTraceHeader toSentryTrace() { - return new SentryTraceHeader(getTraceId(), getSpanId(), getSampled()); + return new SentryTraceHeader(context.getTraceId(), context.getSpanId(), context.getSampled()); } @Override @@ -69,14 +85,54 @@ public void finish() { } @Override - public void finish(@Nullable SpanStatus status) { - this.status = status; + public void finish(final @Nullable SpanStatus status) { + this.context.setStatus(status); this.finish(); } + @Override + public void setOperation(final @NotNull String operation) { + this.context.setOperation(operation); + } + + @Override + public @NotNull String getOperation() { + return this.context.getOperation(); + } + + @Override + public void setDescription(final @Nullable String description) { + this.context.setDescription(description); + } + + @Override + public @Nullable String getDescription() { + return this.context.getDescription(); + } + + @Override + public void setStatus(final @Nullable SpanStatus status) { + this.context.setStatus(status); + } + + @Override + public @Nullable SpanStatus getStatus() { + return this.context.getStatus(); + } + @Override public @NotNull SpanContext getSpanContext() { - return this; + return context; + } + + @Override + public void setTag(final @NotNull String key, final @NotNull String value) { + this.context.setTag(key, value); + } + + @Override + public @Nullable String getTag(@NotNull String key) { + return context.getTags().get(key); } @Override @@ -84,6 +140,11 @@ public boolean isFinished() { return this.timestamp != null; } + @Override + public @Nullable Boolean isSampled() { + return context.getSampled(); + } + @Override public void setThrowable(final @Nullable Throwable throwable) { this.throwable = throwable; @@ -93,4 +154,19 @@ public void setThrowable(final @Nullable Throwable throwable) { public @Nullable Throwable getThrowable() { return throwable; } + + @NotNull + SentryId getTraceId() { + return context.getTraceId(); + } + + @NotNull + SpanId getSpanId() { + return context.getSpanId(); + } + + @Nullable + SpanId getParentSpanId() { + return context.getParentSpanId(); + } } diff --git a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt index 4cacd1371c..0b6069d370 100644 --- a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -434,17 +434,17 @@ class GsonSerializerTest { @Test fun `serializes transaction`() { - val trace = SpanContext("http") + val trace = TransactionContext("transaction-name", "http") trace.description = "some request" trace.status = SpanStatus.OK trace.setTag("myTag", "myValue") - val transaction = SentryTransaction("transaction-name", trace, mock()) + val transaction = SentryTracer(trace, mock()) val span = transaction.startChild("child") span.finish() transaction.finish() val stringWriter = StringWriter() - fixture.serializer.serialize(transaction, stringWriter) + fixture.serializer.serialize(SentryTransaction(transaction), stringWriter) val element = JsonParser().parse(stringWriter.toString()).asJsonObject assertEquals("transaction-name", element["transaction"].asString) @@ -554,7 +554,7 @@ class GsonSerializerTest { @Test fun `empty lists are serialized to null`() { - val transaction = SentryTransaction("tx", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("tx", "op"), mock())) val stringWriter = StringWriter() fixture.serializer.serialize(transaction, stringWriter) val element = JsonParser().parse(stringWriter.toString()).asJsonObject diff --git a/sentry/src/test/java/io/sentry/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt index f0aae53ff6..9d8c39c454 100644 --- a/sentry/src/test/java/io/sentry/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -995,7 +995,7 @@ class HubTest { sut.bindClient(mockClient) sut.close() - sut.captureTransaction(SentryTransaction("name", "op"), null) + sut.captureTransaction(SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())), null) verify(mockClient, never()).captureTransaction(any(), any(), any()) } @@ -1009,7 +1009,7 @@ class HubTest { val mockClient = mock() sut.bindClient(mockClient) - sut.captureTransaction(SentryTransaction("name", SpanContext("op", true), NoOpHub.getInstance()), null) + sut.captureTransaction(SentryTransaction(SentryTracer(TransactionContext("name", "op", true), mock())), null) verify(mockClient).captureTransaction(any(), any(), eq(null)) } @@ -1023,7 +1023,7 @@ class HubTest { val mockClient = mock() sut.bindClient(mockClient) - sut.captureTransaction(SentryTransaction("name", SpanContext("op", false), NoOpHub.getInstance()), null) + sut.captureTransaction(SentryTransaction(SentryTracer(TransactionContext("name", "op", false), mock())), null) verify(mockClient, times(0)).captureTransaction(any(), any(), eq(null)) } @@ -1035,9 +1035,11 @@ class HubTest { options.setSerializer(mock()) val sut = Hub(options) - val transaction = SentryTransaction(TransactionContext("name", "op", true), sut) + val transaction = SentryTracer(TransactionContext("name", "op", true), sut) sut.configureScope { it.setTransaction(transaction) } - sut.captureTransaction(transaction, null) + val sentryTransaction = SentryTransaction(transaction) + sut.captureTransaction(sentryTransaction, null) + sut.clearTransaction(transaction) sut.configureScope { assertNull(it.transaction) } @@ -1051,10 +1053,10 @@ class HubTest { options.setSerializer(mock()) val sut = Hub(options) - val transaction = SentryTransaction(TransactionContext("name", "op", true), sut) - val anotherTransaction = SentryTransaction(TransactionContext("name", "op", true), sut) + val transaction = SentryTracer(TransactionContext("name", "op", true), sut) + val anotherTransaction = SentryTracer(TransactionContext("name", "op", true), sut) sut.configureScope { it.setTransaction(anotherTransaction) } - sut.captureTransaction(transaction, null) + sut.captureTransaction(SentryTransaction(transaction), null) sut.configureScope { assertNotNull(it.transaction) assertEquals(anotherTransaction, it.transaction) @@ -1069,8 +1071,8 @@ class HubTest { val contexts = TransactionContext("name", "op") val transaction = hub.startTransaction(contexts) - assertTrue(transaction is SentryTransaction) - assertEquals(contexts, transaction.context) + assertTrue(transaction is SentryTracer) + assertEquals(contexts, transaction.root.spanContext) } @Test diff --git a/sentry/src/test/java/io/sentry/ScopeTest.kt b/sentry/src/test/java/io/sentry/ScopeTest.kt index 1ddc465f6f..074bb49a52 100644 --- a/sentry/src/test/java/io/sentry/ScopeTest.kt +++ b/sentry/src/test/java/io/sentry/ScopeTest.kt @@ -103,7 +103,7 @@ class ScopeTest { scope.setTag("tag", "tag") scope.setExtra("extra", "extra") - val transaction = SentryTransaction("transaction-name", "op") + val transaction = SentryTracer(TransactionContext("transaction-name", "op"), NoOpHub.getInstance()) scope.setTransaction(transaction) val attachment = Attachment("path/log.txt") @@ -120,7 +120,7 @@ class ScopeTest { assertEquals("abc", clone.fingerprint.first()) assertEquals("message", clone.breadcrumbs.first().message) - assertEquals("transaction-name", (clone.span as SentryTransaction).transaction) + assertEquals("transaction-name", (clone.span as Span).getTag(ISpan.NAME_TAG)) assertEquals("tag", clone.tags["tag"]) assertEquals("extra", clone.extras["extra"]) @@ -170,7 +170,7 @@ class ScopeTest { user.id = "456" request.method = "post" - scope.setTransaction(SentryTransaction("newTransaction", "op")) + scope.setTransaction(SentryTracer(TransactionContext("newTransaction", "op"), NoOpHub.getInstance())) // because you can only set a new list to scope val newFingerprints = mutableListOf("def", "ghf") @@ -214,7 +214,7 @@ class ScopeTest { fun `clear scope resets scope to default state`() { val scope = Scope(SentryOptions()) scope.level = SentryLevel.WARNING - scope.setTransaction(SentryTransaction("", "op")) + scope.setTransaction(SentryTracer(TransactionContext("", "op"), NoOpHub.getInstance())) scope.user = User() scope.request = Request() scope.fingerprint = mutableListOf("finger") @@ -635,7 +635,7 @@ class ScopeTest { @Test fun `Scope getTransaction returns the transaction if there is no active span`() { val scope = Scope(SentryOptions()) - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("name", "op"), NoOpHub.getInstance()) scope.setTransaction(transaction) assertEquals(transaction, scope.span) } @@ -643,7 +643,7 @@ class ScopeTest { @Test fun `Scope getTransaction returns the current span if there is an unfinished span`() { val scope = Scope(SentryOptions()) - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("name", "op"), NoOpHub.getInstance()) scope.setTransaction(transaction) val span = transaction.startChild("op") assertEquals(span, scope.span) @@ -652,7 +652,7 @@ class ScopeTest { @Test fun `Scope getTransaction returns the current span if there is a finished span`() { val scope = Scope(SentryOptions()) - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("name", "op"), NoOpHub.getInstance()) scope.setTransaction(transaction) val span = transaction.startChild("op") span.finish() @@ -662,7 +662,7 @@ class ScopeTest { @Test fun `Scope getTransaction returns the latest span if there is a list of active span`() { val scope = Scope(SentryOptions()) - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("name", "op"), NoOpHub.getInstance()) scope.setTransaction(transaction) val span = transaction.startChild("op") val innerSpan = span.startChild("op") @@ -712,7 +712,7 @@ class ScopeTest { @Test fun `when transaction is started, sets transaction name on the transaction object`() { val scope = Scope(SentryOptions()) - val sentryTransaction = SentryTransaction("transaction-name", "op") + val sentryTransaction = SentryTracer(TransactionContext("transaction-name", "op"), NoOpHub.getInstance()) scope.setTransaction(sentryTransaction) assertEquals("transaction-name", scope.transactionName) scope.setTransaction("new-name") @@ -725,7 +725,7 @@ class ScopeTest { fun `when transaction is set after transaction name is set, clearing transaction does not bring back old transaction name`() { val scope = Scope(SentryOptions()) scope.setTransaction("transaction-a") - val sentryTransaction = SentryTransaction("transaction-name", "op") + val sentryTransaction = SentryTracer(TransactionContext("transaction-name", "op"), NoOpHub.getInstance()) scope.setTransaction(sentryTransaction) assertEquals("transaction-name", scope.transactionName) scope.clearTransaction() diff --git a/sentry/src/test/java/io/sentry/SentryClientTest.kt b/sentry/src/test/java/io/sentry/SentryClientTest.kt index 1fe7408304..4b0a302b2a 100644 --- a/sentry/src/test/java/io/sentry/SentryClientTest.kt +++ b/sentry/src/test/java/io/sentry/SentryClientTest.kt @@ -749,7 +749,7 @@ class SentryClientTest { @Test fun `transactions are sent using connection`() { val sut = fixture.getSut() - sut.captureTransaction(SentryTransaction("a-transaction", "op"), mock(), null) + sut.captureTransaction(SentryTransaction(SentryTracer(TransactionContext("a-transaction", "op"), mock())), mock(), null) verify(fixture.transport).send(check { val transaction = it.items.first().getTransaction(fixture.sentryOptions.serializer) assertNotNull(transaction) @@ -760,12 +760,12 @@ class SentryClientTest { @Test fun `when captureTransactions unfinished spans are removed`() { val sut = fixture.getSut() - val transaction = SentryTransaction("a-transaction", "op") + val transaction = SentryTracer(TransactionContext("a-transaction", "op"), mock()) val span1 = transaction.startChild("span1") span1.finish() val span2 = transaction.startChild("span2") - sut.captureTransaction(transaction, mock(), null) + sut.captureTransaction(SentryTransaction(transaction), mock(), null) verify(fixture.transport).send(check { val sentTransaction = it.items.first().getTransaction(fixture.sentryOptions.serializer) assertNotNull(sentTransaction) { tx -> @@ -778,7 +778,7 @@ class SentryClientTest { @Test fun `when captureTransaction with attachments`() { - val transaction = SentryTransaction("a-transaction", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("a-transaction", "op"), mock())) fixture.getSut().captureTransaction(transaction, createScopeWithAttachments(), null) verifyAttachmentsInEnvelope(transaction.eventId) @@ -786,7 +786,7 @@ class SentryClientTest { @Test fun `when captureTransaction with attachments not added to transaction`() { - val transaction = SentryTransaction("a-transaction", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("a-transaction", "op"), mock())) val scope = createScopeWithAttachments() scope.addAttachment(Attachment("hello".toByteArray(), "application/octet-stream")) fixture.getSut().captureTransaction(transaction, scope, null) @@ -799,7 +799,7 @@ class SentryClientTest { val event = SentryEvent() val sut = fixture.getSut() val scope = createScope() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("a-transaction", "op"), mock()) scope.setTransaction(transaction) transaction.finish() sut.captureEvent(event, scope) @@ -812,12 +812,12 @@ class SentryClientTest { val event = SentryEvent() val sut = fixture.getSut() val scope = createScope() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTracer(TransactionContext("a-transaction", "op"), mock()) scope.setTransaction(transaction) val span = transaction.startChild("op") sut.captureEvent(event, scope) assertNotNull(event.contexts.trace) - assertEquals(span, event.contexts.trace) + assertEquals(span.spanContext, event.contexts.trace) } @Test @@ -825,7 +825,7 @@ class SentryClientTest { fixture.sentryOptions.release = "optionsRelease" fixture.sentryOptions.environment = "optionsEnvironment" val sut = fixture.getSut() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("a-transaction", "op"), mock())) sut.captureTransaction(transaction) assertEquals("optionsRelease", transaction.release) assertEquals("optionsEnvironment", transaction.environment) @@ -836,7 +836,7 @@ class SentryClientTest { fixture.sentryOptions.release = "optionsRelease" fixture.sentryOptions.environment = "optionsEnvironment" val sut = fixture.getSut() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())) transaction.release = "transactionRelease" transaction.environment = "transactionEnvironment" sut.captureTransaction(transaction) @@ -848,7 +848,7 @@ class SentryClientTest { fun `when transaction does not have tags, and tags are set on options, options values are applied to transactions`() { fixture.sentryOptions.setTag("tag1", "value1") val sut = fixture.getSut() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())) sut.captureTransaction(transaction) assertEquals(mapOf("tag1" to "value1"), transaction.tags) } @@ -858,7 +858,7 @@ class SentryClientTest { fixture.sentryOptions.setTag("tag1", "value1") fixture.sentryOptions.setTag("tag2", "value2") val sut = fixture.getSut() - val transaction = SentryTransaction("name", "op") + val transaction = SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())) transaction.setTag("tag3", "value3") transaction.setTag("tag2", "transaction-tag") sut.captureTransaction(transaction) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt new file mode 100644 index 0000000000..8fb5f49893 --- /dev/null +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -0,0 +1,179 @@ +package io.sentry + +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.verify +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class SentryTracerTest { + + @Test + fun `when transaction is created, startTimestamp is set`() { + val tracer = createSentryTracer() + assertNotNull(tracer.startTimestamp) + } + + @Test + fun `when transaction is created, timestamp is not set`() { + val tracer = createSentryTracer() + assertNull(tracer.timestamp) + } + + @Test + fun `when transaction is created, context is set`() { + val tracer = createSentryTracer() + assertNotNull(tracer.spanContext) + } + + @Test + fun `when transaction is created, by default is not sampled`() { + val tracer = createSentryTracer() + assertNull(tracer.isSampled) + } + + @Test + fun `when transaction is finished, timestamp is set`() { + val tracer = createSentryTracer() + tracer.finish() + assertNotNull(tracer.timestamp) + } + + @Test + fun `when transaction is finished with status, timestamp and status are set`() { + val tracer = createSentryTracer() + tracer.finish(SpanStatus.ABORTED) + assertNotNull(tracer.timestamp) + assertEquals(SpanStatus.ABORTED, tracer.status) + } + + @Test + fun `when transaction is finished, transaction is captured`() { + val hub = mock() + val tracer = createSentryTracer(hub) + tracer.finish() + verify(hub).captureTransaction(any()) + } + + @Test + fun `when transaction with throwable set is finished, span context is associated with throwable`() { + val hub = mock() + val tracer = createSentryTracer(hub) + val ex = RuntimeException() + tracer.throwable = ex + tracer.finish() + verify(hub).setSpanContext(ex, tracer.root) + } + + @Test + fun `returns sentry-trace header`() { + val tracer = createSentryTracer() + + assertNotNull(tracer.toSentryTrace()) + } + + @Test + fun `starting child creates a new span`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op") as Span + assertNotNull(span) + assertNotNull(span.spanId) + assertNotNull(span.startTimestamp) + } + + @Test + fun `starting child adds a span to transaction`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op") + assertEquals(1, tracer.children.size) + assertEquals(span, tracer.children.first()) + } + + @Test + fun `span created with startChild has parent span id the same as transaction span id`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op") as Span + assertEquals(tracer.root.spanId, span.parentSpanId) + } + + @Test + fun `span created with startChild has the same trace id as transaction`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op") as Span + assertEquals(tracer.root.traceId, span.traceId) + } + + @Test + fun `starting child with operation and description creates a new span`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op", "description") as Span + assertNotNull(span) + assertNotNull(span.spanId) + assertNotNull(span.startTimestamp) + assertEquals("op", span.operation) + assertEquals("description", span.description) + } + + @Test + fun `starting child with operation and description adds a span to transaction`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op", "description") + assertEquals(1, tracer.children.size) + assertEquals(span, tracer.children.first()) + } + + @Test + fun `span created with startChild with operation and description has parent span id the same as transaction span id`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op", "description") as Span + assertEquals(tracer.root.spanId, span.parentSpanId) + } + + @Test + fun `span created with startChild with operation and description has the same trace id as transaction`() { + val tracer = createSentryTracer() + val span = tracer.startChild("op", "description") as Span + assertEquals(tracer.root.traceId, span.traceId) + } + + @Test + fun `setting op sets op on TraceContext`() { + val tracer = createSentryTracer() + tracer.operation = "op" + tracer.finish() + assertEquals("op", tracer.spanContext.operation) + } + + @Test + fun `setting description sets description on TraceContext`() { + val tracer = createSentryTracer() + tracer.description = "desc" + tracer.finish() + assertEquals("desc", tracer.spanContext.description) + } + + @Test + fun `setting status sets status on TraceContext`() { + val tracer = createSentryTracer() + tracer.status = SpanStatus.ALREADY_EXISTS + tracer.finish() + assertEquals(SpanStatus.ALREADY_EXISTS, tracer.spanContext.status) + } + + @Test + fun `when transaction is not finished, status is null`() { + val tracer = createSentryTracer() + assertNull(tracer.status) + } + + @Test + fun `when transaction is not finished, status can be read`() { + val tracer = createSentryTracer() + tracer.status = SpanStatus.ABORTED + assertEquals(SpanStatus.ABORTED, tracer.status) + } + + private fun createSentryTracer(hub: IHub = mock()) = SentryTracer(TransactionContext("name", "op"), hub) +} diff --git a/sentry/src/test/java/io/sentry/SentryTransactionTest.kt b/sentry/src/test/java/io/sentry/SentryTransactionTest.kt deleted file mode 100644 index 9a6440ccfb..0000000000 --- a/sentry/src/test/java/io/sentry/SentryTransactionTest.kt +++ /dev/null @@ -1,183 +0,0 @@ -package io.sentry - -import com.nhaarman.mockitokotlin2.mock -import com.nhaarman.mockitokotlin2.verify -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertNotNull -import kotlin.test.assertNull - -class SentryTransactionTest { - - @Test - fun `when transaction is created, startTimestamp is set`() { - val transaction = SentryTransaction("name", "op") - assertNotNull(transaction.startTimestamp) - } - - @Test - fun `when transaction is created, timestamp is not set`() { - val transaction = SentryTransaction("name", "op") - assertNull(transaction.timestamp) - } - - @Test - fun `when transaction is created, context is set`() { - val transaction = SentryTransaction("name", "op") - assertNotNull(transaction.contexts) - } - - @Test - fun `when transaction is created, by default is not sampled`() { - val transaction = SentryTransaction("name", "op") - assertNull(transaction.isSampled) - } - - @Test - fun `when transaction is finished, timestamp is set`() { - val transaction = SentryTransaction("name", "op") - transaction.finish() - assertNotNull(transaction.timestamp) - } - - @Test - fun `when transaction is finished with status, timestamp and status are set`() { - val transaction = SentryTransaction("name", "op") - transaction.finish(SpanStatus.ABORTED) - assertNotNull(transaction.timestamp) - assertEquals(SpanStatus.ABORTED, transaction.status) - } - - @Test - fun `when transaction is finished, transaction is captured`() { - val hub = mock() - val transaction = SentryTransaction("name", SpanContext("op"), hub) - transaction.finish() - verify(hub).captureTransaction(transaction, null) - } - - @Test - fun `when transaction with throwable set is finished, span context is associated with throwable`() { - val hub = mock() - val transaction = SentryTransaction("name", SpanContext("op"), hub) - val ex = RuntimeException() - transaction.throwable = ex - transaction.finish() - verify(hub).setSpanContext(ex, transaction) - } - - @Test - fun `returns sentry-trace header`() { - val transaction = SentryTransaction("name", "op") - - assertNotNull(transaction.toSentryTrace()) - } - - @Test - fun `starting child creates a new span`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") as Span - assertNotNull(span) - assertNotNull(span.spanId) - assertNotNull(span.startTimestamp) - } - - @Test - fun `starting child adds a span to transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") - assertEquals(1, transaction.spans.size) - assertEquals(span, transaction.spans.first()) - } - - @Test - fun `span created with startChild has parent span id the same as transaction span id`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") as Span - assertEquals(transaction.spanId, span.parentSpanId) - } - - @Test - fun `span created with startChild has the same trace id as transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") as Span - assertEquals(transaction.traceId, span.traceId) - } - - @Test - fun `starting child with operation and description creates a new span`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op", "description") as Span - assertNotNull(span) - assertNotNull(span.spanId) - assertNotNull(span.startTimestamp) - assertEquals("op", span.operation) - assertEquals("description", span.description) - } - - @Test - fun `starting child with operation and description adds a span to transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op", "description") - assertEquals(1, transaction.spans.size) - assertEquals(span, transaction.spans.first()) - } - - @Test - fun `span created with startChild with operation and description has parent span id the same as transaction span id`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op", "description") as Span - assertEquals(transaction.spanId, span.parentSpanId) - } - - @Test - fun `span created with startChild with operation and description has the same trace id as transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op", "description") as Span - assertEquals(transaction.traceId, span.traceId) - } - - @Test - fun `setting op sets op on TraceContext`() { - val transaction = SentryTransaction("name", "op") - transaction.operation = "op" - transaction.finish() - assertEquals("op", transaction.contexts.trace!!.operation) - } - - @Test - fun `setting description sets description on TraceContext`() { - val transaction = SentryTransaction("name", "op") - transaction.description = "desc" - transaction.finish() - assertEquals("desc", transaction.contexts.trace!!.description) - } - - @Test - fun `setting status sets status on TraceContext`() { - val transaction = SentryTransaction("name", "op") - transaction.status = SpanStatus.ALREADY_EXISTS - transaction.finish() - assertEquals(SpanStatus.ALREADY_EXISTS, transaction.contexts.trace!!.status) - } - - @Test - fun `setName overwrites the transaction name`() { - val transaction = SentryTransaction("initial name", "op") - transaction.name = "new name" - assertEquals("new name", transaction.transaction) - } - - @Test - fun `when transaction is not finished, status is null`() { - val transaction = SentryTransaction("name", "op") - assertNull(transaction.status) - } - - @Test - fun `when transaction is not finished, status can be read`() { - val transaction = SentryTransaction("name", "op") - transaction.status = SpanStatus.ABORTED - assertEquals(SpanStatus.ABORTED, transaction.status) - } -} diff --git a/sentry/src/test/java/io/sentry/SpanTest.kt b/sentry/src/test/java/io/sentry/SpanTest.kt index 4c2a242b5d..8f7e1fe033 100644 --- a/sentry/src/test/java/io/sentry/SpanTest.kt +++ b/sentry/src/test/java/io/sentry/SpanTest.kt @@ -11,90 +11,90 @@ import kotlin.test.assertTrue class SpanTest { - @Test - fun `finishing span sets the timestamp`() { - val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) - span.finish() - assertNotNull(span.timestamp) - } - - @Test - fun `finishing span with status sets the timestamp and status`() { - val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) - span.finish(SpanStatus.CANCELLED) - assertNotNull(span.timestamp) - assertEquals(SpanStatus.CANCELLED, span.status) - } - - @Test - fun `starting a child sets parent span id`() { - val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) - val child = span.startChild("op") as Span - assertEquals(span.spanId, child.parentSpanId) - } - - @Test - fun `starting a child adds span to transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") - span.startChild("op") - assertEquals(2, transaction.spans.size) - } - - @Test - fun `starting a child creates a new span`() { - val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "span-op", mock()) - val child = span.startChild("child-op", "description") as Span - assertEquals(span.spanId, child.parentSpanId) - assertEquals("child-op", child.operation) - assertEquals("description", child.description) - } - - @Test - fun `converts to Sentry trace header`() { - val traceId = SentryId() - val parentSpanId = SpanId() - val hub = mock() - val span = Span(traceId, parentSpanId, SentryTransaction(TransactionContext("name", "op", true), hub), "op", hub) - val sentryTrace = span.toSentryTrace() - assertEquals(traceId, sentryTrace.traceId) - assertEquals(span.spanId, sentryTrace.spanId) - assertNotNull(sentryTrace.isSampled) { - assertTrue(it) - } - } - - @Test - fun `starting a child with details adds span to transaction`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("operation", "description") - span.startChild("op") - assertEquals(2, transaction.spans.size) - } - - @Test - fun `when span has no timestamp set, it is considered unfinished`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") as Span - assertFalse(span.isFinished) - } - - @Test - fun `when span has timestamp set, it is considered finished`() { - val transaction = SentryTransaction("name", "op") - val span = transaction.startChild("op") as Span - span.finish() - assertTrue(span.isFinished) - } - - @Test - fun `when span has throwable set set, it assigns itself to throwable on the Hub`() { - val hub = mock() - val transaction = SentryTransaction(TransactionContext("name", "op"), hub) - val span = transaction.startChild("op") - val ex = RuntimeException() - span.throwable = ex - span.finish() - verify(hub).setSpanContext(ex, span) - } +// @Test +// fun `finishing span sets the timestamp`() { +// val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) +// span.finish() +// assertNotNull(span.timestamp) +// } +// +// @Test +// fun `finishing span with status sets the timestamp and status`() { +// val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) +// span.finish(SpanStatus.CANCELLED) +// assertNotNull(span.timestamp) +// assertEquals(SpanStatus.CANCELLED, span.status) +// } +// +// @Test +// fun `starting a child sets parent span id`() { +// val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "op", mock()) +// val child = span.startChild("op") as Span +// assertEquals(span.spanId, child.parentSpanId) +// } +// +// @Test +// fun `starting a child adds span to transaction`() { +// val transaction = SentryTransaction("name", "op") +// val span = transaction.startChild("op") +// span.startChild("op") +// assertEquals(2, transaction.spans.size) +// } +// +// @Test +// fun `starting a child creates a new span`() { +// val span = Span(SentryId(), SpanId(), SentryTransaction("name", "op"), "span-op", mock()) +// val child = span.startChild("child-op", "description") as Span +// assertEquals(span.spanId, child.parentSpanId) +// assertEquals("child-op", child.operation) +// assertEquals("description", child.description) +// } +// +// @Test +// fun `converts to Sentry trace header`() { +// val traceId = SentryId() +// val parentSpanId = SpanId() +// val hub = mock() +// val span = Span(traceId, parentSpanId, SentryTransaction(TransactionContext("name", "op", true), hub), "op", hub) +// val sentryTrace = span.toSentryTrace() +// assertEquals(traceId, sentryTrace.traceId) +// assertEquals(span.spanId, sentryTrace.spanId) +// assertNotNull(sentryTrace.isSampled) { +// assertTrue(it) +// } +// } +// +// @Test +// fun `starting a child with details adds span to transaction`() { +// val transaction = SentryTransaction("name", "op") +// val span = transaction.startChild("operation", "description") +// span.startChild("op") +// assertEquals(2, transaction.spans.size) +// } +// +// @Test +// fun `when span has no timestamp set, it is considered unfinished`() { +// val transaction = SentryTransaction("name", "op") +// val span = transaction.startChild("op") as Span +// assertFalse(span.isFinished) +// } +// +// @Test +// fun `when span has timestamp set, it is considered finished`() { +// val transaction = SentryTransaction("name", "op") +// val span = transaction.startChild("op") as Span +// span.finish() +// assertTrue(span.isFinished) +// } +// +// @Test +// fun `when span has throwable set set, it assigns itself to throwable on the Hub`() { +// val hub = mock() +// val transaction = SentryTransaction(TransactionContext("name", "op"), hub) +// val span = transaction.startChild("op") +// val ex = RuntimeException() +// span.throwable = ex +// span.finish() +// verify(hub).setSpanContext(ex, span) +// } } diff --git a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt index 43dd49ca31..e8d1d7bbcd 100644 --- a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt +++ b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt @@ -8,8 +8,9 @@ import io.sentry.SentryEnvelope import io.sentry.SentryEnvelopeHeader import io.sentry.SentryEnvelopeItem import io.sentry.SentryEvent +import io.sentry.SentryTracer import io.sentry.SentryTransaction -import io.sentry.SpanContext +import io.sentry.TransactionContext import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -47,7 +48,8 @@ class RateLimiterTest { val rateLimiter = fixture.getSUT() whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0) val eventItem = SentryEnvelopeItem.fromEvent(fixture.serializer, SentryEvent()) - val transactionItem = SentryEnvelopeItem.fromEvent(fixture.serializer, SentryTransaction("", SpanContext("op"), mock())) + val transaction = SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())) + val transactionItem = SentryEnvelopeItem.fromEvent(fixture.serializer, transaction) val envelope = SentryEnvelope(SentryEnvelopeHeader(), arrayListOf(eventItem, transactionItem)) rateLimiter.updateRetryAfterLimits("50:transaction:key, 2700:default;error;security:organization", null, 1) @@ -61,7 +63,8 @@ class RateLimiterTest { val rateLimiter = fixture.getSUT() whenever(fixture.currentDateProvider.currentTimeMillis).thenReturn(0, 0, 1001) val eventItem = SentryEnvelopeItem.fromEvent(fixture.serializer, SentryEvent()) - val transactionItem = SentryEnvelopeItem.fromEvent(fixture.serializer, SentryTransaction("", SpanContext("op"), mock())) + val transaction = SentryTransaction(SentryTracer(TransactionContext("name", "op"), mock())) + val transactionItem = SentryEnvelopeItem.fromEvent(fixture.serializer, transaction) val envelope = SentryEnvelope(SentryEnvelopeHeader(), arrayListOf(eventItem, transactionItem)) rateLimiter.updateRetryAfterLimits("1:transaction:key, 1:default;error;security:organization", null, 1) From 9a364ecdc57361998e851d25434e96c8ae65994c Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 09:07:12 +0100 Subject: [PATCH 02/26] Refactor Spring modules. --- .../SentrySpanRestTemplateCustomizerTest.kt | 2 +- .../tracing/SentryTransactionAdvice.java | 14 +--------- .../spring/tracing/SentryTracingFilterTest.kt | 26 +++++++++++++++---- .../tracing/SentryTransactionAdviceTest.kt | 10 +++---- sentry/src/main/java/io/sentry/ISpan.java | 6 +++-- settings.gradle.kts | 4 +-- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt index 7d1f7e6e14..84932d6d52 100644 --- a/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt +++ b/sentry-spring-boot-starter/src/test/kotlin/io/sentry/spring/boot/SentrySpanRestTemplateCustomizerTest.kt @@ -23,7 +23,7 @@ class SentrySpanRestTemplateCustomizerTest { val hub = mock() val restTemplate = RestTemplate() var mockServer = MockRestServiceServer.createServer(restTemplate) - val transaction = SentryTracer(TransactionContext("aTransaction", "op"), hub) + val transaction = SentryTracer(TransactionContext("aTransaction", "op", true), hub) internal val customizer = SentrySpanRestTemplateCustomizer(hub) fun getSut(isTransactionActive: Boolean, status: HttpStatus = HttpStatus.OK): RestTemplate { diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransactionAdvice.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransactionAdvice.java index ccbb68b426..f29884051f 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransactionAdvice.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransactionAdvice.java @@ -2,11 +2,9 @@ import com.jakewharton.nopen.annotation.Open; import io.sentry.IHub; -import io.sentry.ISpan; import io.sentry.ITransaction; import io.sentry.util.Objects; import java.lang.reflect.Method; -import java.util.concurrent.atomic.AtomicBoolean; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.jetbrains.annotations.ApiStatus; @@ -78,16 +76,6 @@ public Object invoke(final @NotNull MethodInvocation invocation) throws Throwabl } private boolean isTransactionActive() { - AtomicBoolean isTransactionActiveRef = new AtomicBoolean(false); - - hub.configureScope( - scope -> { - ISpan span = scope.getSpan(); - - if (span != null) { - isTransactionActiveRef.set(true); - } - }); - return isTransactionActiveRef.get(); + return hub.getSpan() != null; } } diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt index 274dcab747..917b96414a 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTracingFilterTest.kt @@ -10,6 +10,7 @@ import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.verifyZeroInteractions import com.nhaarman.mockitokotlin2.whenever import io.sentry.IHub +import io.sentry.Scope import io.sentry.SentryOptions import io.sentry.SentryTracer import io.sentry.SpanId @@ -49,7 +50,7 @@ class SentryTracingFilterTest { whenever(hub.startTransaction(any(), any())).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, hub) } } response.status = 200 - whenever(hub.startTransaction(any(), any(), any())).thenAnswer { SentryTracer(it.arguments[0] as TransactionContext, hub) } + whenever(hub.startTransaction(any(), any(), any())).thenAnswer { SentryTracer(TransactionContext(it.arguments[0] as String, it.arguments[1] as String), hub) } whenever(hub.isEnabled).thenReturn(isEnabled) return SentryTracingFilter(hub, sentryRequestResolver, transactionNameProvider) } @@ -57,6 +58,22 @@ class SentryTracingFilterTest { private val fixture = Fixture() + @Test + fun `sets the request on the scope`() { + val filter = fixture.getSut() + + filter.doFilter(fixture.request, fixture.response, fixture.chain) + + verify(fixture.chain).doFilter(fixture.request, fixture.response) + verify(fixture.hub).configureScope(check { + val scope = mock() + it.run(scope) + verify(scope).setRequest(check { request -> + assertThat(request.url).isEqualTo("http://localhost/product/12") + }) + }) + } + @Test fun `creates transaction around the request`() { val filter = fixture.getSut() @@ -72,8 +89,7 @@ class SentryTracingFilterTest { assertThat(it.transaction).isEqualTo("POST /product/{id}") assertThat(it.contexts.trace!!.status).isEqualTo(SpanStatus.OK) assertThat(it.contexts.trace!!.operation).isEqualTo("http.server") - assertThat(it.request).isNotNull() - }, eq(null)) + }) } @Test @@ -84,7 +100,7 @@ class SentryTracingFilterTest { verify(fixture.hub).captureTransaction(check { assertThat(it.contexts.trace!!.parentSpanId).isNull() - }, eq(null)) + }) } @Test @@ -96,7 +112,7 @@ class SentryTracingFilterTest { verify(fixture.hub).captureTransaction(check { assertThat(it.contexts.trace!!.parentSpanId).isEqualTo(parentSpanId) - }, eq(null)) + }) } @Test diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt index 9e876913ce..37a00503d9 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt @@ -2,7 +2,6 @@ package io.sentry.spring.tracing import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.check -import com.nhaarman.mockitokotlin2.eq import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify @@ -51,7 +50,7 @@ class SentryTransactionAdviceTest { verify(hub).captureTransaction(check { assertThat(it.transaction).isEqualTo("customName") assertThat(it.contexts.trace!!.operation).isEqualTo("bean") - }, eq(null)) + }) } @Test @@ -60,7 +59,7 @@ class SentryTransactionAdviceTest { verify(hub).captureTransaction(check { assertThat(it.transaction).isEqualTo("SampleService.methodWithoutTransactionNameSet") assertThat(it.contexts.trace!!.operation).isEqualTo("op") - }, eq(null)) + }) } @Test @@ -80,9 +79,10 @@ class SentryTransactionAdviceTest { fun `creates transaction around method in class annotated with @SentryTransaction`() { classAnnotatedSampleService.hello() verify(hub).captureTransaction(check { + println(it) assertThat(it.transaction).isEqualTo("ClassAnnotatedSampleService.hello") assertThat(it.contexts.trace!!.operation).isEqualTo("op") - }, eq(null)) + }) } @Test @@ -91,7 +91,7 @@ class SentryTransactionAdviceTest { verify(hub).captureTransaction(check { assertThat(it.transaction).isEqualTo("ClassAnnotatedWithOperationSampleService.hello") assertThat(it.contexts.trace!!.operation).isEqualTo("my-op") - }, eq(null)) + }) } @Configuration diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index 6259a9e8fa..e6195e614a 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -36,7 +36,8 @@ public interface ISpan { /** * Sets span timestamp marking this span as finished. * - * @return true if transaction has been successfully finished or false if finishing transaction failed + * @return true if transaction has been successfully finished or false if finishing transaction + * failed */ boolean finish(); @@ -44,7 +45,8 @@ public interface ISpan { * Sets span timestamp marking this span as finished. * * @param status - the status - * @return true if transaction has been successfully finished or false if finishing transaction failed + * @return true if transaction has been successfully finished or false if finishing transaction + * failed */ boolean finish(@Nullable SpanStatus status); diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a9c01523f..1f98b11a0b 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -12,8 +12,8 @@ include( "sentry-jul", "sentry-servlet", "sentry-apache-http-client-5", -// "sentry-spring", -// "sentry-spring-boot-starter", + "sentry-spring", + "sentry-spring-boot-starter", // "sentry-android-timber", // "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", From 0445c5dc25305ffd138453416bf366731688679f Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 09:32:51 +0100 Subject: [PATCH 03/26] Deprecate methods. --- .../sentry/spring/tracing/SentryTracingFilter.java | 5 ++++- sentry/src/main/java/io/sentry/ITransaction.java | 14 ++++++++++++++ .../src/main/java/io/sentry/NoOpTransaction.java | 8 ++++++++ sentry/src/main/java/io/sentry/Scope.java | 2 +- sentry/src/main/java/io/sentry/SentryTracer.java | 6 ++++++ 5 files changed, 33 insertions(+), 2 deletions(-) diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java index d973c79f07..22c1a344a9 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java @@ -73,6 +73,10 @@ protected void doFilterInternal( if (hub.isEnabled()) { final String sentryTraceHeader = httpRequest.getHeader(SentryTraceHeader.SENTRY_TRACE_HEADER); + hub.configureScope(scope -> { + scope.setRequest(requestResolver.resolveSentryRequest(httpRequest)); + }); + // at this stage we are not able to get real transaction name final ITransaction transaction = startTransaction(httpRequest, sentryTraceHeader); try { @@ -86,7 +90,6 @@ protected void doFilterInternal( if (transactionName != null) { transaction.setName(transactionName); transaction.setOperation(TRANSACTION_OP); - transaction.setRequest(requestResolver.resolveSentryRequest(httpRequest)); transaction.setStatus(SpanStatus.fromHttpStatusCode(httpResponse.getStatus())); transaction.finish(); } diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index c898896f79..21a0da1133 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -30,15 +30,21 @@ public interface ITransaction extends ISpan { * Attaches request information to the transaction. * * @param request the request + * @deprecated use {@link Scope#setRequest(Request)} */ + @Deprecated + @ApiStatus.ScheduledForRemoval void setRequest(@Nullable Request request); /** * Returns the request information from the transaction * * @return the request or {@code null} if not set + * @deprecated use {@link Scope#getRequest()} */ @Nullable + @Deprecated + @ApiStatus.ScheduledForRemoval Request getRequest(); @NotNull @@ -64,7 +70,15 @@ public interface ITransaction extends ISpan { @Nullable SentryId getEventId(); + /** + * Returns the transaction name. + * + * @deprecated use {@link #getName()} + * @return transaction name + */ @Nullable @ApiStatus.Internal + @Deprecated + @ApiStatus.ScheduledForRemoval String getTransaction(); } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index 9b3a3a0cff..27f21ea64f 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -5,6 +5,8 @@ import io.sentry.protocol.SentryId; import java.util.Collections; import java.util.List; + +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -38,9 +40,13 @@ public void setName(@NotNull String name) {} } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public void setRequest(@Nullable Request request) {} @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @Nullable Request getRequest() { return null; } @@ -76,6 +82,8 @@ public void setRequest(@Nullable Request request) {} } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @Nullable String getTransaction() { return null; } diff --git a/sentry/src/main/java/io/sentry/Scope.java b/sentry/src/main/java/io/sentry/Scope.java index b2042fd5a1..347ee93478 100644 --- a/sentry/src/main/java/io/sentry/Scope.java +++ b/sentry/src/main/java/io/sentry/Scope.java @@ -104,7 +104,7 @@ public void setLevel(final @Nullable SentryLevel level) { */ public @Nullable String getTransactionName() { final ITransaction tx = this.transaction; - return tx != null ? tx.getTransaction() : transactionName; + return tx != null ? tx.getName() : transactionName; } /** diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 784c52664d..72a59bf804 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -189,11 +189,15 @@ public void setName(@NotNull String name) { } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public void setRequest(@Nullable Request request) { hub.configureScope(scope -> scope.setRequest(request)); } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @Nullable Request getRequest() { final AtomicReference contexts = new AtomicReference<>(); hub.configureScope(scope -> contexts.set(scope.getRequest())); @@ -233,6 +237,8 @@ public void setRequest(@Nullable Request request) { } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @Nullable String getTransaction() { return this.getName(); } From 8128e8c7fa5293dbe11b1327e60bc80da2be20aa Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 10:06:32 +0100 Subject: [PATCH 04/26] Polish. --- .../spring/tracing/SentryTracingFilter.java | 7 ++++--- sentry/api/sentry.api | 3 +-- sentry/src/main/java/io/sentry/ISpan.java | 8 -------- sentry/src/main/java/io/sentry/ITransaction.java | 8 ++++++++ sentry/src/main/java/io/sentry/NoOpSpan.java | 5 ----- .../src/main/java/io/sentry/NoOpTransaction.java | 11 +++++------ sentry/src/main/java/io/sentry/Span.java | 1 - settings.gradle.kts | 16 ++++++++-------- 8 files changed, 26 insertions(+), 33 deletions(-) diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java index 22c1a344a9..980dd051bb 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTracingFilter.java @@ -73,9 +73,10 @@ protected void doFilterInternal( if (hub.isEnabled()) { final String sentryTraceHeader = httpRequest.getHeader(SentryTraceHeader.SENTRY_TRACE_HEADER); - hub.configureScope(scope -> { - scope.setRequest(requestResolver.resolveSentryRequest(httpRequest)); - }); + hub.configureScope( + scope -> { + scope.setRequest(requestResolver.resolveSentryRequest(httpRequest)); + }); // at this stage we are not able to get real transaction name final ITransaction transaction = startTransaction(httpRequest, sentryTraceHeader); diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 18550eb70a..fb6e5b240d 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -290,7 +290,6 @@ public abstract interface class io/sentry/ISpan { public abstract fun getTag (Ljava/lang/String;)Ljava/lang/String; public abstract fun getThrowable ()Ljava/lang/Throwable; public abstract fun isFinished ()Z - public abstract fun isSampled ()Ljava/lang/Boolean; public abstract fun setDescription (Ljava/lang/String;)V public abstract fun setOperation (Ljava/lang/String;)V public abstract fun setStatus (Lio/sentry/SpanStatus;)V @@ -309,6 +308,7 @@ public abstract interface class io/sentry/ITransaction : io/sentry/ISpan { public abstract fun getRequest ()Lio/sentry/protocol/Request; public abstract fun getSpans ()Ljava/util/List; public abstract fun getTransaction ()Ljava/lang/String; + public abstract fun isSampled ()Ljava/lang/Boolean; public abstract fun setName (Ljava/lang/String;)V public abstract fun setRequest (Lio/sentry/protocol/Request;)V } @@ -358,7 +358,6 @@ public final class io/sentry/NoOpSpan : io/sentry/ISpan { public fun getTag (Ljava/lang/String;)Ljava/lang/String; public fun getThrowable ()Ljava/lang/Throwable; public fun isFinished ()Z - public fun isSampled ()Ljava/lang/Boolean; public fun setDescription (Ljava/lang/String;)V public fun setOperation (Ljava/lang/String;)V public fun setStatus (Lio/sentry/SpanStatus;)V diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index e6195e614a..23bef60537 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -135,12 +135,4 @@ public interface ISpan { * @return if span has finished. */ boolean isFinished(); - - /** - * Returns if transaction is sampled. - * - * @return is sampled - */ - @Nullable - Boolean isSampled(); } diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index 21a0da1133..a86667a85a 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -54,6 +54,14 @@ public interface ITransaction extends ISpan { @TestOnly List getSpans(); + /** + * Returns if transaction is sampled. + * + * @return is sampled + */ + @Nullable + Boolean isSampled(); + /** * Returns the latest span that is not finished. * diff --git a/sentry/src/main/java/io/sentry/NoOpSpan.java b/sentry/src/main/java/io/sentry/NoOpSpan.java index edb68e1f30..f9975ccdaf 100644 --- a/sentry/src/main/java/io/sentry/NoOpSpan.java +++ b/sentry/src/main/java/io/sentry/NoOpSpan.java @@ -89,9 +89,4 @@ public void setTag(@NotNull String key, @NotNull String value) {} public boolean isFinished() { return false; } - - @Override - public @Nullable Boolean isSampled() { - return null; - } } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index 27f21ea64f..3bda906e31 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -5,7 +5,6 @@ import io.sentry.protocol.SentryId; import java.util.Collections; import java.util.List; - import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -66,11 +65,6 @@ public void setRequest(@Nullable Request request) {} return Collections.emptyList(); } - @Override - public @Nullable Boolean isSampled() { - return null; - } - @Override public @Nullable Span getLatestActiveSpan() { return null; @@ -147,4 +141,9 @@ public void setTag(@NotNull String key, @NotNull String value) {} public @Nullable String getTag(@NotNull String key) { return null; } + + @Override + public @Nullable Boolean isSampled() { + return null; + } } diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index 70d0add4ef..6e1272fe5a 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -148,7 +148,6 @@ public boolean isFinished() { return finished.get(); } - @Override public @Nullable Boolean isSampled() { return context.getSampled(); } diff --git a/settings.gradle.kts b/settings.gradle.kts index 1f98b11a0b..3a819a9880 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,9 +2,9 @@ rootProject.name = "sentry-root" rootProject.buildFileName = "build.gradle.kts" include( -// "sentry-android", -// "sentry-android-ndk", -// "sentry-android-core", + "sentry-android", + "sentry-android-ndk", + "sentry-android-core", "sentry", "sentry-test-support", "sentry-log4j2", @@ -14,12 +14,12 @@ include( "sentry-apache-http-client-5", "sentry-spring", "sentry-spring-boot-starter", -// "sentry-android-timber", -// "sentry-samples:sentry-samples-android", + "sentry-android-timber", + "sentry-samples:sentry-samples-android", "sentry-samples:sentry-samples-console", "sentry-samples:sentry-samples-jul", "sentry-samples:sentry-samples-log4j2", "sentry-samples:sentry-samples-logback", - "sentry-samples:sentry-samples-servlet") -// "sentry-samples:sentry-samples-spring", -// "sentry-samples:sentry-samples-spring-boot") + "sentry-samples:sentry-samples-servlet", + "sentry-samples:sentry-samples-spring", + "sentry-samples:sentry-samples-spring-boot") From e25f34632c415b2c7ade66428f627e207e22723a Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 10:15:50 +0100 Subject: [PATCH 05/26] Revert sentry-native changes --- sentry-android-ndk/sentry-native | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-android-ndk/sentry-native b/sentry-android-ndk/sentry-native index 2327d513d9..3aa9a80fcf 160000 --- a/sentry-android-ndk/sentry-native +++ b/sentry-android-ndk/sentry-native @@ -1 +1 @@ -Subproject commit 2327d513d9cee41c51b09723e477ac1e4850a258 +Subproject commit 3aa9a80fcf0e7b2b00727a75de9544ad8f667f31 From 41a6ba49abf7fee866b8fafa173b6321445940b7 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 11:29:30 +0100 Subject: [PATCH 06/26] Fix android tests. --- .../core/ActivityLifecycleIntegrationTest.kt | 14 ++++++++------ sentry/api/sentry.api | 1 + .../src/main/java/io/sentry/SentryTransaction.java | 8 ++++++-- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index 6457ef48a4..b43142474e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -15,8 +15,10 @@ import io.sentry.Hub import io.sentry.Scope import io.sentry.SentryLevel import io.sentry.SentryOptions +import io.sentry.SentryTracer import io.sentry.SentryTransaction import io.sentry.SpanStatus +import io.sentry.TransactionContext import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -31,7 +33,7 @@ class ActivityLifecycleIntegrationTest { val options = SentryAndroidOptions() val activity = mock() val bundle = mock() - val transaction = SentryTransaction("name", "op", hub) + val transaction = SentryTracer(TransactionContext("name", "op"), hub) fun getSut(): ActivityLifecycleIntegration { whenever(hub.startTransaction(any(), any())).thenReturn(transaction) @@ -256,7 +258,7 @@ class ActivityLifecycleIntegrationTest { whenever(fixture.hub.configureScope(any())).thenAnswer { val scope = Scope(fixture.options) - val previousTransaction = SentryTransaction("name", "op", fixture.hub) + val previousTransaction = SentryTracer(TransactionContext("name", "op"), fixture.hub) scope.setTransaction(previousTransaction) sut.applyScope(scope, fixture.transaction) @@ -278,7 +280,7 @@ class ActivityLifecycleIntegrationTest { verify(fixture.hub).captureTransaction(check { assertEquals(SpanStatus.OK, it.status) - }, eq(null)) + }) } @Test @@ -295,7 +297,7 @@ class ActivityLifecycleIntegrationTest { verify(fixture.hub).captureTransaction(check { assertEquals(SpanStatus.UNKNOWN_ERROR, it.status) - }, eq(null)) + }) } @Test @@ -330,7 +332,7 @@ class ActivityLifecycleIntegrationTest { sut.onActivityPreCreated(fixture.activity, fixture.bundle) sut.onActivityDestroyed(fixture.activity) - verify(fixture.hub).captureTransaction(any(), eq(null)) + verify(fixture.hub).captureTransaction(any()) } @Test @@ -366,6 +368,6 @@ class ActivityLifecycleIntegrationTest { sut.onActivityPreCreated(activity, mock()) sut.onActivityPreCreated(fixture.activity, fixture.bundle) - verify(fixture.hub).captureTransaction(any(), eq(null)) + verify(fixture.hub).captureTransaction(any()) } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index fb6e5b240d..81ad22cb46 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -890,6 +890,7 @@ public final class io/sentry/SentryTransaction : io/sentry/SentryBaseEvent { public fun (Lio/sentry/SentryTracer;)V public fun getSpans ()Ljava/util/List; public fun getStartTimestamp ()Ljava/util/Date; + public fun getStatus ()Lio/sentry/SpanStatus; public fun getTimestamp ()Ljava/util/Date; public fun getTransaction ()Ljava/lang/String; public fun getType ()Ljava/lang/String; diff --git a/sentry/src/main/java/io/sentry/SentryTransaction.java b/sentry/src/main/java/io/sentry/SentryTransaction.java index 3a6864103a..eb7991b2d2 100644 --- a/sentry/src/main/java/io/sentry/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/SentryTransaction.java @@ -2,7 +2,6 @@ import java.util.Date; import java.util.List; -import java.util.Objects; import java.util.concurrent.CopyOnWriteArrayList; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -59,8 +58,13 @@ public boolean isFinished() { return type; } + public @NotNull SpanStatus getStatus() { + final SpanContext trace = this.getContexts().getTrace(); + return trace != null ? trace.getStatus() : null; + } + public boolean isSampled() { final SpanContext trace = this.getContexts().getTrace(); - return trace != null && Objects.equals(trace.getSampled(), Boolean.TRUE); + return trace != null && Boolean.TRUE.equals(trace.getSampled()); } } From 89b311bf21bb52ae8eb725859602c780f81b1004 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 13:15:53 +0100 Subject: [PATCH 07/26] Polish. --- sentry/src/main/java/io/sentry/SentryTransaction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/SentryTransaction.java b/sentry/src/main/java/io/sentry/SentryTransaction.java index eb7991b2d2..29a6e11fc0 100644 --- a/sentry/src/main/java/io/sentry/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/SentryTransaction.java @@ -58,7 +58,7 @@ public boolean isFinished() { return type; } - public @NotNull SpanStatus getStatus() { + public @Nullable SpanStatus getStatus() { final SpanContext trace = this.getContexts().getTrace(); return trace != null ? trace.getStatus() : null; } From f810653cb81d8f7f9e777ca5d891652978660f3f Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 13:16:10 +0100 Subject: [PATCH 08/26] Apply scope to transaction. --- .../src/main/java/io/sentry/SentryClient.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/sentry/src/main/java/io/sentry/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java index c41627353d..a1a63286f2 100644 --- a/sentry/src/main/java/io/sentry/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -341,7 +341,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec @Override public @NotNull SentryId captureTransaction( - final @NotNull SentryTransaction transaction, + @NotNull SentryTransaction transaction, final @NotNull Scope scope, final @Nullable Object hint) { Objects.requireNonNull(transaction, "Transaction is required."); @@ -352,10 +352,19 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec SentryId sentryId = transaction.getEventId(); - final SentryTransaction sentryTransaction = processTransaction(transaction); + if (ApplyScopeUtils.shouldApplyScopeData(hint)) { + transaction = applyScope(transaction, scope); + } else { + options + .getLogger() + .log(SentryLevel.DEBUG, "Transaction was cached so not applying scope: %s", transaction.getEventId()); + } + + transaction = processTransaction(transaction); + try { final SentryEnvelope envelope = - buildEnvelope(sentryTransaction, filterForTransaction(getAttachmentsFromScope(scope))); + buildEnvelope(transaction, filterForTransaction(getAttachmentsFromScope(scope))); if (envelope != null) { transport.send(envelope, hint); } else { @@ -417,6 +426,16 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec return transaction; } + private @NotNull SentryTransaction applyScope( + @NotNull SentryTransaction transaction, final @Nullable Scope scope) { + if (scope != null) { + if (transaction.getRequest() == null) { + transaction.setRequest(scope.getRequest()); + } + } + return transaction; + } + private @Nullable SentryEvent applyScope( @NotNull SentryEvent event, final @Nullable Scope scope, final @Nullable Object hint) { if (scope != null) { From 319ca388e6229116bc568eb42c413cbccf46ee14 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Thu, 4 Mar 2021 13:51:58 +0100 Subject: [PATCH 09/26] Fix Span serialization. --- .../main/java/io/sentry/GsonSerializer.java | 2 ++ sentry/src/main/java/io/sentry/Span.java | 6 ++-- .../adapters/SpanSerializerAdapter.java | 30 +++++++++++++++++++ .../test/java/io/sentry/GsonSerializerTest.kt | 10 ++++++- 4 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java diff --git a/sentry/src/main/java/io/sentry/GsonSerializer.java b/sentry/src/main/java/io/sentry/GsonSerializer.java index 401e96db61..fc50086c9f 100644 --- a/sentry/src/main/java/io/sentry/GsonSerializer.java +++ b/sentry/src/main/java/io/sentry/GsonSerializer.java @@ -17,6 +17,7 @@ import io.sentry.adapters.SentryLevelSerializerAdapter; import io.sentry.adapters.SpanIdDeserializerAdapter; import io.sentry.adapters.SpanIdSerializerAdapter; +import io.sentry.adapters.SpanSerializerAdapter; import io.sentry.adapters.SpanStatusDeserializerAdapter; import io.sentry.adapters.SpanStatusSerializerAdapter; import io.sentry.adapters.TimeZoneDeserializerAdapter; @@ -102,6 +103,7 @@ Device.DeviceOrientation.class, new OrientationDeserializerAdapter(logger)) .registerTypeAdapter(SpanId.class, new SpanIdSerializerAdapter(logger)) .registerTypeAdapter(SpanStatus.class, new SpanStatusDeserializerAdapter(logger)) .registerTypeAdapter(SpanStatus.class, new SpanStatusSerializerAdapter(logger)) + .registerTypeAdapter(Span.class, new SpanSerializerAdapter()) .registerTypeHierarchyAdapter(Collection.class, new CollectionAdapter()) .registerTypeHierarchyAdapter(Map.class, new MapAdapter()) .disableHtmlEscaping() diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index 6e1272fe5a..a72eb85f56 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -163,16 +163,16 @@ public void setThrowable(final @Nullable Throwable throwable) { } @NotNull - SentryId getTraceId() { + public SentryId getTraceId() { return context.getTraceId(); } - @NotNull + public @NotNull SpanId getSpanId() { return context.getSpanId(); } - @Nullable + public @Nullable SpanId getParentSpanId() { return context.getParentSpanId(); } diff --git a/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java new file mode 100644 index 0000000000..4123f813d9 --- /dev/null +++ b/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java @@ -0,0 +1,30 @@ +package io.sentry.adapters; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import io.sentry.Span; + +import java.lang.reflect.Type; + +public final class SpanSerializerAdapter implements JsonSerializer { + @Override + public JsonElement serialize(Span src, Type typeOfSrc, JsonSerializationContext context) { + if (src == null) { + return null; + } + + final JsonObject object = new JsonObject(); + object.add("trace_id", context.serialize(src.getTraceId())); + object.add("span_id", context.serialize(src.getSpanId())); + object.add("parent_span_id", context.serialize(src.getParentSpanId())); + object.add("op", context.serialize(src.getOperation())); + object.add("description", context.serialize(src.getDescription())); + object.add("timestamp", context.serialize(src.getTimestamp())); + object.add("start_timestamp", context.serialize(src.getStartTimestamp())); + object.add("status", context.serialize(src.getStatus())); + + return object; + } +} diff --git a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt index 0b6069d370..d8159996f5 100644 --- a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -440,7 +440,7 @@ class GsonSerializerTest { trace.setTag("myTag", "myValue") val transaction = SentryTracer(trace, mock()) val span = transaction.startChild("child") - span.finish() + span.finish(SpanStatus.OK) transaction.finish() val stringWriter = StringWriter() @@ -452,6 +452,14 @@ class GsonSerializerTest { assertNotNull(element["start_timestamp"].asString) assertNotNull(element["event_id"].asString) assertNotNull(element["spans"].asJsonArray) + val jsonSpan = element["spans"].asJsonArray[0] + assertNotNull(jsonSpan.asJsonObject["trace_id"]) + assertNotNull(jsonSpan.asJsonObject["span_id"]) + assertNotNull(jsonSpan.asJsonObject["parent_span_id"]) + assertNotNull(jsonSpan.asJsonObject["op"]) + assertNotNull(jsonSpan.asJsonObject["status"]) + assertNotNull(jsonSpan.asJsonObject["timestamp"]) + assertNotNull(jsonSpan.asJsonObject["start_timestamp"]) val jsonTrace = element["contexts"].asJsonObject["trace"] assertNotNull(jsonTrace.asJsonObject["trace_id"].asString) assertNotNull(jsonTrace.asJsonObject["span_id"].asString) From 04ee7395cb33a4e128bc204ffddf616410e1202e Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 10:18:57 +0100 Subject: [PATCH 10/26] Create separate protocol class for span. --- .../core/ActivityLifecycleIntegrationTest.kt | 2 +- .../io/sentry/spring/tracing/SentrySpan.java | 5 +- .../spring/tracing/SentryTransaction.java | 2 +- sentry/api/sentry.api | 59 +++++++++----- .../main/java/io/sentry/GsonSerializer.java | 3 +- sentry/src/main/java/io/sentry/Hub.java | 1 + .../src/main/java/io/sentry/HubAdapter.java | 1 + sentry/src/main/java/io/sentry/IHub.java | 1 + .../main/java/io/sentry/ISentryClient.java | 1 + sentry/src/main/java/io/sentry/NoOpHub.java | 1 + .../main/java/io/sentry/NoOpSentryClient.java | 1 + .../main/java/io/sentry/SentryBaseEvent.java | 4 +- .../src/main/java/io/sentry/SentryClient.java | 15 ++-- .../java/io/sentry/SentryEnvelopeItem.java | 1 + .../main/java/io/sentry/SentryItemType.java | 1 + .../src/main/java/io/sentry/SentryTracer.java | 1 + sentry/src/main/java/io/sentry/Span.java | 11 ++- .../adapters/SpanSerializerAdapter.java | 30 ------- .../java/io/sentry/protocol/SentrySpan.java | 78 +++++++++++++++++++ .../{ => protocol}/SentryTransaction.java | 19 +++-- .../test/java/io/sentry/GsonSerializerTest.kt | 1 + sentry/src/test/java/io/sentry/HubTest.kt | 1 + .../test/java/io/sentry/SentryClientTest.kt | 1 + .../io/sentry/transport/RateLimiterTest.kt | 2 +- 24 files changed, 170 insertions(+), 72 deletions(-) delete mode 100644 sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java create mode 100644 sentry/src/main/java/io/sentry/protocol/SentrySpan.java rename sentry/src/main/java/io/sentry/{ => protocol}/SentryTransaction.java (78%) diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt index b43142474e..1c7f9d7909 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/ActivityLifecycleIntegrationTest.kt @@ -16,9 +16,9 @@ import io.sentry.Scope import io.sentry.SentryLevel import io.sentry.SentryOptions import io.sentry.SentryTracer -import io.sentry.SentryTransaction import io.sentry.SpanStatus import io.sentry.TransactionContext +import io.sentry.protocol.SentryTransaction import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpan.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpan.java index 5bf48049cf..eb949d4041 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpan.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentrySpan.java @@ -1,5 +1,6 @@ package io.sentry.spring.tracing; +import io.sentry.protocol.SentryTransaction; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -8,8 +9,8 @@ /** * Makes annotated method execution or a method execution within a class annotated with {@link - * SentrySpan} executed within running {@link io.sentry.SentryTransaction} to get wrapped into - * {@link io.sentry.Span}. + * SentrySpan} executed within running {@link SentryTransaction} to get wrapped into {@link + * io.sentry.Span}. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) diff --git a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransaction.java b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransaction.java index c389d63d9f..1f2e3d3b0a 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransaction.java +++ b/sentry-spring/src/main/java/io/sentry/spring/tracing/SentryTransaction.java @@ -8,7 +8,7 @@ /** * Makes annotated method execution or a method execution within an annotated class to get wrapped - * into {@link io.sentry.SentryTransaction}. + * into {@link io.sentry.protocol.SentryTransaction}. */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 81ad22cb46..0401034118 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -106,7 +106,7 @@ public final class io/sentry/Hub : io/sentry/IHub { public fun captureEvent (Lio/sentry/SentryEvent;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureException (Ljava/lang/Throwable;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun clearBreadcrumbs ()V public fun clone ()Lio/sentry/IHub; @@ -144,7 +144,7 @@ public final class io/sentry/HubAdapter : io/sentry/IHub { public fun captureEvent (Lio/sentry/SentryEvent;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureException (Ljava/lang/Throwable;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun clearBreadcrumbs ()V public fun clone ()Lio/sentry/IHub; @@ -199,8 +199,8 @@ public abstract interface class io/sentry/IHub { public abstract fun captureException (Ljava/lang/Throwable;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureMessage (Ljava/lang/String;)Lio/sentry/protocol/SentryId; public abstract fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;)Lio/sentry/protocol/SentryId; - public fun captureTransaction (Lio/sentry/SentryTransaction;)Lio/sentry/protocol/SentryId; - public abstract fun captureTransaction (Lio/sentry/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;)Lio/sentry/protocol/SentryId; + public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public abstract fun captureUserFeedback (Lio/sentry/UserFeedback;)V public abstract fun clearBreadcrumbs ()V public abstract fun clone ()Lio/sentry/IHub; @@ -263,8 +263,8 @@ public abstract interface class io/sentry/ISentryClient { public fun captureMessage (Ljava/lang/String;Lio/sentry/SentryLevel;Lio/sentry/Scope;)Lio/sentry/protocol/SentryId; public fun captureSession (Lio/sentry/Session;)V public abstract fun captureSession (Lio/sentry/Session;Ljava/lang/Object;)V - public fun captureTransaction (Lio/sentry/SentryTransaction;)Lio/sentry/protocol/SentryId; - public abstract fun captureTransaction (Lio/sentry/SentryTransaction;Lio/sentry/Scope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;)Lio/sentry/protocol/SentryId; + public abstract fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Scope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public abstract fun captureUserFeedback (Lio/sentry/UserFeedback;)V public abstract fun close ()V public abstract fun flush (J)V @@ -564,6 +564,7 @@ public abstract class io/sentry/SentryBaseEvent { public fun getRequest ()Lio/sentry/protocol/Request; public fun getSdk ()Lio/sentry/protocol/SdkVersion; public fun getTag (Ljava/lang/String;)Ljava/lang/String; + public fun getTags ()Ljava/util/Map; public fun getThrowable ()Ljava/lang/Throwable; public fun removeTag (Ljava/lang/String;)V public fun setEnvironment (Ljava/lang/String;)V @@ -580,7 +581,7 @@ public final class io/sentry/SentryClient : io/sentry/ISentryClient { public fun captureEnvelope (Lio/sentry/SentryEnvelope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureEvent (Lio/sentry/SentryEvent;Lio/sentry/Scope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureSession (Lio/sentry/Session;Ljava/lang/Object;)V - public fun captureTransaction (Lio/sentry/SentryTransaction;Lio/sentry/Scope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; + public fun captureTransaction (Lio/sentry/protocol/SentryTransaction;Lio/sentry/Scope;Ljava/lang/Object;)Lio/sentry/protocol/SentryId; public fun captureUserFeedback (Lio/sentry/UserFeedback;)V public fun close ()V public fun flush (J)V @@ -621,7 +622,7 @@ public final class io/sentry/SentryEnvelopeItem { public fun getData ()[B public fun getEvent (Lio/sentry/ISerializer;)Lio/sentry/SentryEvent; public fun getHeader ()Lio/sentry/SentryEnvelopeItemHeader; - public fun getTransaction (Lio/sentry/ISerializer;)Lio/sentry/SentryTransaction; + public fun getTransaction (Lio/sentry/ISerializer;)Lio/sentry/protocol/SentryTransaction; } public final class io/sentry/SentryEnvelopeItemHeader { @@ -886,18 +887,6 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun toSentryTrace ()Lio/sentry/SentryTraceHeader; } -public final class io/sentry/SentryTransaction : io/sentry/SentryBaseEvent { - public fun (Lio/sentry/SentryTracer;)V - public fun getSpans ()Ljava/util/List; - public fun getStartTimestamp ()Ljava/util/Date; - public fun getStatus ()Lio/sentry/SpanStatus; - public fun getTimestamp ()Ljava/util/Date; - public fun getTransaction ()Ljava/lang/String; - public fun getType ()Ljava/lang/String; - public fun isFinished ()Z - public fun isSampled ()Z -} - public final class io/sentry/Session { public fun (Lio/sentry/Session$State;Ljava/util/Date;Ljava/util/Date;ILjava/lang/String;Ljava/util/UUID;Ljava/lang/Boolean;Ljava/lang/Long;Ljava/lang/Double;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V public fun (Ljava/lang/String;Lio/sentry/protocol/User;Ljava/lang/String;Ljava/lang/String;)V @@ -950,12 +939,16 @@ public final class io/sentry/Span : io/sentry/ISpan { public fun finish (Lio/sentry/SpanStatus;)Z public fun getDescription ()Ljava/lang/String; public fun getOperation ()Ljava/lang/String; + public fun getParentSpanId ()Lio/sentry/SpanId; public fun getSpanContext ()Lio/sentry/SpanContext; + public fun getSpanId ()Lio/sentry/SpanId; public fun getStartTimestamp ()Ljava/util/Date; public fun getStatus ()Lio/sentry/SpanStatus; public fun getTag (Ljava/lang/String;)Ljava/lang/String; + public fun getTags ()Ljava/util/Map; public fun getThrowable ()Ljava/lang/Throwable; public fun getTimestamp ()Ljava/util/Date; + public fun getTraceId ()Lio/sentry/protocol/SentryId; public fun isFinished ()Z public fun isSampled ()Ljava/lang/Boolean; public fun setDescription (Ljava/lang/String;)V @@ -1611,6 +1604,20 @@ public final class io/sentry/protocol/SentryRuntime : io/sentry/IUnknownProperti public fun setVersion (Ljava/lang/String;)V } +public final class io/sentry/protocol/SentrySpan { + public fun (Lio/sentry/Span;)V + public fun getDescription ()Ljava/lang/String; + public fun getOp ()Ljava/lang/String; + public fun getParentSpanId ()Lio/sentry/SpanId; + public fun getSpanId ()Lio/sentry/SpanId; + public fun getStartTimestamp ()Ljava/util/Date; + public fun getStatus ()Lio/sentry/SpanStatus; + public fun getTags ()Ljava/util/Map; + public fun getTimestamp ()Ljava/util/Date; + public fun getTraceId ()Lio/sentry/protocol/SentryId; + public fun isFinished ()Z +} + public final class io/sentry/protocol/SentryStackFrame : io/sentry/IUnknownPropertiesConsumer { public fun ()V public fun acceptUnknownProperties (Ljava/util/Map;)V @@ -1687,6 +1694,18 @@ public final class io/sentry/protocol/SentryThread : io/sentry/IUnknownPropertie public fun setState (Ljava/lang/String;)V } +public final class io/sentry/protocol/SentryTransaction : io/sentry/SentryBaseEvent { + public fun (Lio/sentry/SentryTracer;)V + public fun getSpans ()Ljava/util/List; + public fun getStartTimestamp ()Ljava/util/Date; + public fun getStatus ()Lio/sentry/SpanStatus; + public fun getTimestamp ()Ljava/util/Date; + public fun getTransaction ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun isFinished ()Z + public fun isSampled ()Z +} + public final class io/sentry/protocol/User : io/sentry/IUnknownPropertiesConsumer, java/lang/Cloneable { public fun ()V public fun acceptUnknownProperties (Ljava/util/Map;)V diff --git a/sentry/src/main/java/io/sentry/GsonSerializer.java b/sentry/src/main/java/io/sentry/GsonSerializer.java index fc50086c9f..8d69e0580e 100644 --- a/sentry/src/main/java/io/sentry/GsonSerializer.java +++ b/sentry/src/main/java/io/sentry/GsonSerializer.java @@ -17,7 +17,6 @@ import io.sentry.adapters.SentryLevelSerializerAdapter; import io.sentry.adapters.SpanIdDeserializerAdapter; import io.sentry.adapters.SpanIdSerializerAdapter; -import io.sentry.adapters.SpanSerializerAdapter; import io.sentry.adapters.SpanStatusDeserializerAdapter; import io.sentry.adapters.SpanStatusSerializerAdapter; import io.sentry.adapters.TimeZoneDeserializerAdapter; @@ -103,7 +102,6 @@ Device.DeviceOrientation.class, new OrientationDeserializerAdapter(logger)) .registerTypeAdapter(SpanId.class, new SpanIdSerializerAdapter(logger)) .registerTypeAdapter(SpanStatus.class, new SpanStatusDeserializerAdapter(logger)) .registerTypeAdapter(SpanStatus.class, new SpanStatusSerializerAdapter(logger)) - .registerTypeAdapter(Span.class, new SpanSerializerAdapter()) .registerTypeHierarchyAdapter(Collection.class, new CollectionAdapter()) .registerTypeHierarchyAdapter(Map.class, new MapAdapter()) .disableHtmlEscaping() @@ -147,6 +145,7 @@ public void serialize(final @NotNull T entity, final @NotNull Writer writer) throws IOException { Objects.requireNonNull(entity, "The entity is required."); Objects.requireNonNull(writer, "The Writer object is required."); + System.out.println("Serializing object: " + gson.toJson(entity)); if (logger.isEnabled(SentryLevel.DEBUG)) { logger.log(SentryLevel.DEBUG, "Serializing object: %s", gson.toJson(entity)); diff --git a/sentry/src/main/java/io/sentry/Hub.java b/sentry/src/main/java/io/sentry/Hub.java index f5c9c4ca41..41e8ac38d3 100644 --- a/sentry/src/main/java/io/sentry/Hub.java +++ b/sentry/src/main/java/io/sentry/Hub.java @@ -4,6 +4,7 @@ import io.sentry.hints.SessionEndHint; import io.sentry.hints.SessionStartHint; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import io.sentry.util.Objects; import java.io.Closeable; diff --git a/sentry/src/main/java/io/sentry/HubAdapter.java b/sentry/src/main/java/io/sentry/HubAdapter.java index 51d9964fc3..f1c936f6d6 100644 --- a/sentry/src/main/java/io/sentry/HubAdapter.java +++ b/sentry/src/main/java/io/sentry/HubAdapter.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry/src/main/java/io/sentry/IHub.java b/sentry/src/main/java/io/sentry/IHub.java index 2094db725e..1dd68404b5 100644 --- a/sentry/src/main/java/io/sentry/IHub.java +++ b/sentry/src/main/java/io/sentry/IHub.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.ApiStatus; diff --git a/sentry/src/main/java/io/sentry/ISentryClient.java b/sentry/src/main/java/io/sentry/ISentryClient.java index 5353505f65..b92ef21b74 100644 --- a/sentry/src/main/java/io/sentry/ISentryClient.java +++ b/sentry/src/main/java/io/sentry/ISentryClient.java @@ -2,6 +2,7 @@ import io.sentry.protocol.Message; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import org.jetbrains.annotations.Nullable; /** Sentry Client interface */ diff --git a/sentry/src/main/java/io/sentry/NoOpHub.java b/sentry/src/main/java/io/sentry/NoOpHub.java index 34aaba2317..df0d942cd1 100644 --- a/sentry/src/main/java/io/sentry/NoOpHub.java +++ b/sentry/src/main/java/io/sentry/NoOpHub.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import io.sentry.protocol.User; import java.util.List; import org.jetbrains.annotations.NotNull; diff --git a/sentry/src/main/java/io/sentry/NoOpSentryClient.java b/sentry/src/main/java/io/sentry/NoOpSentryClient.java index 037c2c76bf..5119980f75 100644 --- a/sentry/src/main/java/io/sentry/NoOpSentryClient.java +++ b/sentry/src/main/java/io/sentry/NoOpSentryClient.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import org.jetbrains.annotations.Nullable; final class NoOpSentryClient implements ISentryClient { diff --git a/sentry/src/main/java/io/sentry/SentryBaseEvent.java b/sentry/src/main/java/io/sentry/SentryBaseEvent.java index 096219b9b3..6ebb11e912 100644 --- a/sentry/src/main/java/io/sentry/SentryBaseEvent.java +++ b/sentry/src/main/java/io/sentry/SentryBaseEvent.java @@ -7,6 +7,7 @@ import io.sentry.protocol.SentryId; import java.util.HashMap; import java.util.Map; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -131,7 +132,8 @@ public void setThrowable(final @Nullable Throwable throwable) { this.throwable = throwable; } - Map getTags() { + @ApiStatus.Internal + public Map getTags() { return tags; } diff --git a/sentry/src/main/java/io/sentry/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java index a1a63286f2..13d3788b6c 100644 --- a/sentry/src/main/java/io/sentry/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -2,6 +2,8 @@ import io.sentry.hints.DiskFlushNotification; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentrySpan; +import io.sentry.protocol.SentryTransaction; import io.sentry.transport.ITransport; import io.sentry.util.ApplyScopeUtils; import io.sentry.util.Objects; @@ -356,8 +358,11 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec transaction = applyScope(transaction, scope); } else { options - .getLogger() - .log(SentryLevel.DEBUG, "Transaction was cached so not applying scope: %s", transaction.getEventId()); + .getLogger() + .log( + SentryLevel.DEBUG, + "Transaction was cached so not applying scope: %s", + transaction.getEventId()); } transaction = processTransaction(transaction); @@ -411,8 +416,8 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec } } } - final List unfinishedSpans = new ArrayList<>(); - for (Span span : transaction.getSpans()) { + final List unfinishedSpans = new ArrayList<>(); + for (SentrySpan span : transaction.getSpans()) { if (!span.isFinished()) { unfinishedSpans.add(span); } @@ -427,7 +432,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec } private @NotNull SentryTransaction applyScope( - @NotNull SentryTransaction transaction, final @Nullable Scope scope) { + @NotNull SentryTransaction transaction, final @Nullable Scope scope) { if (scope != null) { if (transaction.getRequest() == null) { transaction.setRequest(scope.getRequest()); diff --git a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java index 39e00722e4..28a24999e6 100644 --- a/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java +++ b/sentry/src/main/java/io/sentry/SentryEnvelopeItem.java @@ -1,6 +1,7 @@ package io.sentry; import io.sentry.exception.SentryEnvelopeException; +import io.sentry.protocol.SentryTransaction; import io.sentry.util.Objects; import java.io.BufferedInputStream; import java.io.BufferedReader; diff --git a/sentry/src/main/java/io/sentry/SentryItemType.java b/sentry/src/main/java/io/sentry/SentryItemType.java index edb7d0f184..3ae083588e 100644 --- a/sentry/src/main/java/io/sentry/SentryItemType.java +++ b/sentry/src/main/java/io/sentry/SentryItemType.java @@ -1,5 +1,6 @@ package io.sentry; +import io.sentry.protocol.SentryTransaction; import org.jetbrains.annotations.ApiStatus; @ApiStatus.Internal diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 72a59bf804..de98de19e8 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -3,6 +3,7 @@ import io.sentry.protocol.Contexts; import io.sentry.protocol.Request; import io.sentry.protocol.SentryId; +import io.sentry.protocol.SentryTransaction; import io.sentry.util.Objects; import java.util.ArrayList; import java.util.Date; diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index a72eb85f56..fbc2257425 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -3,6 +3,7 @@ import io.sentry.protocol.SentryId; import io.sentry.util.Objects; import java.util.Date; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -167,13 +168,15 @@ public SentryId getTraceId() { return context.getTraceId(); } - public @NotNull - SpanId getSpanId() { + public @NotNull SpanId getSpanId() { return context.getSpanId(); } - public @Nullable - SpanId getParentSpanId() { + public @Nullable SpanId getParentSpanId() { return context.getParentSpanId(); } + + public Map getTags() { + return context.getTags(); + } } diff --git a/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java b/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java deleted file mode 100644 index 4123f813d9..0000000000 --- a/sentry/src/main/java/io/sentry/adapters/SpanSerializerAdapter.java +++ /dev/null @@ -1,30 +0,0 @@ -package io.sentry.adapters; - -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonSerializationContext; -import com.google.gson.JsonSerializer; -import io.sentry.Span; - -import java.lang.reflect.Type; - -public final class SpanSerializerAdapter implements JsonSerializer { - @Override - public JsonElement serialize(Span src, Type typeOfSrc, JsonSerializationContext context) { - if (src == null) { - return null; - } - - final JsonObject object = new JsonObject(); - object.add("trace_id", context.serialize(src.getTraceId())); - object.add("span_id", context.serialize(src.getSpanId())); - object.add("parent_span_id", context.serialize(src.getParentSpanId())); - object.add("op", context.serialize(src.getOperation())); - object.add("description", context.serialize(src.getDescription())); - object.add("timestamp", context.serialize(src.getTimestamp())); - object.add("start_timestamp", context.serialize(src.getStartTimestamp())); - object.add("status", context.serialize(src.getStatus())); - - return object; - } -} diff --git a/sentry/src/main/java/io/sentry/protocol/SentrySpan.java b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java new file mode 100644 index 0000000000..88970701ee --- /dev/null +++ b/sentry/src/main/java/io/sentry/protocol/SentrySpan.java @@ -0,0 +1,78 @@ +package io.sentry.protocol; + +import io.sentry.Span; +import io.sentry.SpanId; +import io.sentry.SpanStatus; +import io.sentry.util.CollectionUtils; +import io.sentry.util.Objects; +import java.util.Date; +import java.util.Map; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +@ApiStatus.Internal +public final class SentrySpan { + private final @NotNull Date startTimestamp; + private final @Nullable Date timestamp; + private final @NotNull SentryId traceId; + private final @NotNull SpanId spanId; + private final @Nullable SpanId parentSpanId; + private final @NotNull String op; + private final @Nullable String description; + private final @Nullable SpanStatus status; + private final @NotNull Map tags; + + public SentrySpan(final @NotNull Span span) { + Objects.requireNonNull(span, "span is required"); + this.description = span.getDescription(); + this.op = span.getOperation(); + this.spanId = span.getSpanId(); + this.parentSpanId = span.getParentSpanId(); + this.traceId = span.getTraceId(); + this.status = span.getStatus(); + this.tags = CollectionUtils.shallowCopy(span.getTags()); + this.timestamp = span.getTimestamp(); + this.startTimestamp = span.getStartTimestamp(); + } + + public boolean isFinished() { + return this.timestamp != null; + } + + public @NotNull Date getStartTimestamp() { + return startTimestamp; + } + + public @Nullable Date getTimestamp() { + return timestamp; + } + + public @NotNull SentryId getTraceId() { + return traceId; + } + + public @NotNull SpanId getSpanId() { + return spanId; + } + + public @NotNull SpanId getParentSpanId() { + return parentSpanId; + } + + public @NotNull String getOp() { + return op; + } + + public @Nullable String getDescription() { + return description; + } + + public @Nullable SpanStatus getStatus() { + return status; + } + + public @NotNull Map getTags() { + return tags; + } +} diff --git a/sentry/src/main/java/io/sentry/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java similarity index 78% rename from sentry/src/main/java/io/sentry/SentryTransaction.java rename to sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 29a6e11fc0..4a5193e3ef 100644 --- a/sentry/src/main/java/io/sentry/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -1,8 +1,15 @@ -package io.sentry; +package io.sentry.protocol; +import io.sentry.DateUtils; +import io.sentry.ISpan; +import io.sentry.SentryBaseEvent; +import io.sentry.SentryTracer; +import io.sentry.Span; +import io.sentry.SpanContext; +import io.sentry.SpanStatus; +import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,21 +27,23 @@ public final class SentryTransaction extends SentryBaseEvent { private @Nullable Date timestamp; /** A list of spans within this transaction. Can be empty. */ - private final @NotNull List spans = new CopyOnWriteArrayList<>(); + private final @NotNull List spans = new ArrayList<>(); /** The {@code type} property is required in JSON payload sent to Sentry. */ @SuppressWarnings("UnusedVariable") private @NotNull final String type = "transaction"; public SentryTransaction(SentryTracer sentryTracer) { - this.spans.addAll(sentryTracer.getChildren()); this.startTimestamp = sentryTracer.getStartTimestamp(); this.timestamp = DateUtils.getCurrentDateTime(); this.transaction = sentryTracer.getTag(ISpan.NAME_TAG); + for (final Span span : sentryTracer.getChildren()) { + this.spans.add(new SentrySpan(span)); + } this.getContexts().setTrace(sentryTracer.getSpanContext()); } - public @NotNull List getSpans() { + public @NotNull List getSpans() { return spans; } diff --git a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt index d8159996f5..ce1694f3b0 100644 --- a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -12,6 +12,7 @@ import io.sentry.exception.SentryEnvelopeException import io.sentry.protocol.Device import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryId +import io.sentry.protocol.SentryTransaction import java.io.BufferedWriter import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream diff --git a/sentry/src/test/java/io/sentry/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt index 188cacfa78..63f570fc15 100644 --- a/sentry/src/test/java/io/sentry/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -18,6 +18,7 @@ import io.sentry.exception.InvalidDsnException import io.sentry.hints.SessionEndHint import io.sentry.hints.SessionStartHint import io.sentry.protocol.SentryId +import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import java.io.File import java.nio.file.Files diff --git a/sentry/src/test/java/io/sentry/SentryClientTest.kt b/sentry/src/test/java/io/sentry/SentryClientTest.kt index 640cae82f4..6f953e1626 100644 --- a/sentry/src/test/java/io/sentry/SentryClientTest.kt +++ b/sentry/src/test/java/io/sentry/SentryClientTest.kt @@ -21,6 +21,7 @@ import io.sentry.protocol.Request import io.sentry.protocol.SdkVersion import io.sentry.protocol.SentryException import io.sentry.protocol.SentryId +import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import io.sentry.transport.ITransport import io.sentry.transport.ITransportGate diff --git a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt index e8d1d7bbcd..2caaf8f67a 100644 --- a/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt +++ b/sentry/src/test/java/io/sentry/transport/RateLimiterTest.kt @@ -9,8 +9,8 @@ import io.sentry.SentryEnvelopeHeader import io.sentry.SentryEnvelopeItem import io.sentry.SentryEvent import io.sentry.SentryTracer -import io.sentry.SentryTransaction import io.sentry.TransactionContext +import io.sentry.protocol.SentryTransaction import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull From 0f6d9a50770a4f2108f550a585ac3a5fe2317854 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 10:24:01 +0100 Subject: [PATCH 11/26] Polish. --- sentry/src/main/java/io/sentry/GsonSerializer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/GsonSerializer.java b/sentry/src/main/java/io/sentry/GsonSerializer.java index 8d69e0580e..401e96db61 100644 --- a/sentry/src/main/java/io/sentry/GsonSerializer.java +++ b/sentry/src/main/java/io/sentry/GsonSerializer.java @@ -145,7 +145,6 @@ public void serialize(final @NotNull T entity, final @NotNull Writer writer) throws IOException { Objects.requireNonNull(entity, "The entity is required."); Objects.requireNonNull(writer, "The Writer object is required."); - System.out.println("Serializing object: " + gson.toJson(entity)); if (logger.isEnabled(SentryLevel.DEBUG)) { logger.log(SentryLevel.DEBUG, "Serializing object: %s", gson.toJson(entity)); From a053914242494e8e4ff746dbe60a83bcf98e4333 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 10:24:01 +0100 Subject: [PATCH 12/26] Polish. --- sentry/src/main/java/io/sentry/GsonSerializer.java | 1 - sentry/src/main/java/io/sentry/ISpan.java | 8 ++++---- .../main/java/io/sentry/protocol/SentryTransaction.java | 4 +++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/sentry/src/main/java/io/sentry/GsonSerializer.java b/sentry/src/main/java/io/sentry/GsonSerializer.java index 8d69e0580e..401e96db61 100644 --- a/sentry/src/main/java/io/sentry/GsonSerializer.java +++ b/sentry/src/main/java/io/sentry/GsonSerializer.java @@ -145,7 +145,6 @@ public void serialize(final @NotNull T entity, final @NotNull Writer writer) throws IOException { Objects.requireNonNull(entity, "The entity is required."); Objects.requireNonNull(writer, "The Writer object is required."); - System.out.println("Serializing object: " + gson.toJson(entity)); if (logger.isEnabled(SentryLevel.DEBUG)) { logger.log(SentryLevel.DEBUG, "Serializing object: %s", gson.toJson(entity)); diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index 23bef60537..c374f1f1f9 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -36,8 +36,8 @@ public interface ISpan { /** * Sets span timestamp marking this span as finished. * - * @return true if transaction has been successfully finished or false if finishing transaction - * failed + * @return true if transaction has been successfully finished or false if span has been already + * finished */ boolean finish(); @@ -45,8 +45,8 @@ public interface ISpan { * Sets span timestamp marking this span as finished. * * @param status - the status - * @return true if transaction has been successfully finished or false if finishing transaction - * failed + * @return true if transaction has been successfully finished or false if span has been already + * finished */ boolean finish(@Nullable SpanStatus status); diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 4a5193e3ef..5f96df230e 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -7,6 +7,7 @@ import io.sentry.Span; import io.sentry.SpanContext; import io.sentry.SpanStatus; +import io.sentry.util.Objects; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -33,7 +34,8 @@ public final class SentryTransaction extends SentryBaseEvent { @SuppressWarnings("UnusedVariable") private @NotNull final String type = "transaction"; - public SentryTransaction(SentryTracer sentryTracer) { + public SentryTransaction(final @NotNull SentryTracer sentryTracer) { + Objects.requireNonNull(sentryTracer, "sentryTracer is required"); this.startTimestamp = sentryTracer.getStartTimestamp(); this.timestamp = DateUtils.getCurrentDateTime(); this.transaction = sentryTracer.getTag(ISpan.NAME_TAG); From 95831791fe5c8c3622057916f5b26a209ecada89 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 10:40:01 +0100 Subject: [PATCH 13/26] Remove transient modifier from Span fields. --- sentry/src/main/java/io/sentry/Span.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index e37c7fba0c..27e851e014 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -23,14 +23,14 @@ public final class Span implements ISpan { * A transaction this span is attached to. Marked as transient to be ignored during JSON * serialization. */ - private final transient @NotNull SentryTracer transaction; + private final @NotNull SentryTracer transaction; /** A throwable thrown during the execution of the span. */ - private transient @Nullable Throwable throwable; + private @Nullable Throwable throwable; - private final transient @NotNull IHub hub; + private final @NotNull IHub hub; - private final transient @NotNull AtomicBoolean finished = new AtomicBoolean(false); + private final @NotNull AtomicBoolean finished = new AtomicBoolean(false); Span( final @NotNull SentryId traceId, From e5dcd7b6022ad7d46494e97c279e5d71ae5956a1 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 11:00:53 +0100 Subject: [PATCH 14/26] Add serialization tests. --- .../test/java/io/sentry/GsonSerializerTest.kt | 66 +++++++++++++------ 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt index ce1694f3b0..5fc0aba45b 100644 --- a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -439,13 +439,13 @@ class GsonSerializerTest { trace.description = "some request" trace.status = SpanStatus.OK trace.setTag("myTag", "myValue") - val transaction = SentryTracer(trace, mock()) - val span = transaction.startChild("child") + val tracer = SentryTracer(trace, mock()) + val span = tracer.startChild("child") span.finish(SpanStatus.OK) - transaction.finish() + tracer.finish() val stringWriter = StringWriter() - fixture.serializer.serialize(SentryTransaction(transaction), stringWriter) + fixture.serializer.serialize(SentryTransaction(tracer), stringWriter) val element = JsonParser().parse(stringWriter.toString()).asJsonObject assertEquals("transaction-name", element["transaction"].asString) @@ -453,21 +453,23 @@ class GsonSerializerTest { assertNotNull(element["start_timestamp"].asString) assertNotNull(element["event_id"].asString) assertNotNull(element["spans"].asJsonArray) - val jsonSpan = element["spans"].asJsonArray[0] - assertNotNull(jsonSpan.asJsonObject["trace_id"]) - assertNotNull(jsonSpan.asJsonObject["span_id"]) - assertNotNull(jsonSpan.asJsonObject["parent_span_id"]) - assertNotNull(jsonSpan.asJsonObject["op"]) - assertNotNull(jsonSpan.asJsonObject["status"]) - assertNotNull(jsonSpan.asJsonObject["timestamp"]) - assertNotNull(jsonSpan.asJsonObject["start_timestamp"]) - val jsonTrace = element["contexts"].asJsonObject["trace"] - assertNotNull(jsonTrace.asJsonObject["trace_id"].asString) - assertNotNull(jsonTrace.asJsonObject["span_id"].asString) - assertEquals("http", jsonTrace.asJsonObject["op"].asString) - assertEquals("some request", jsonTrace.asJsonObject["description"].asString) - assertEquals("ok", jsonTrace.asJsonObject["status"].asString) - assertEquals("myValue", jsonTrace.asJsonObject["tags"].asJsonObject["myTag"].asString) + + val jsonSpan = element["spans"].asJsonArray[0].asJsonObject + assertNotNull(jsonSpan["trace_id"]) + assertNotNull(jsonSpan["span_id"]) + assertNotNull(jsonSpan["parent_span_id"]) + assertEquals("child", jsonSpan["op"].asString) + assertNotNull("ok", jsonSpan["status"].asString) + assertNotNull(jsonSpan["timestamp"]) + assertNotNull(jsonSpan["start_timestamp"]) + + val jsonTrace = element["contexts"].asJsonObject["trace"].asJsonObject + assertNotNull(jsonTrace["trace_id"].asString) + assertNotNull(jsonTrace["span_id"].asString) + assertEquals("http", jsonTrace["op"].asString) + assertEquals("some request", jsonTrace["description"].asString) + assertEquals("ok", jsonTrace["status"].asString) + assertEquals("myValue", jsonTrace["tags"].asJsonObject["myTag"].asString) } @Test @@ -487,7 +489,19 @@ class GsonSerializerTest { "custom": { "some-key": "some-value" } - } + }, + "spans": [ + { + "start_timestamp": "2021-03-05T08:51:12.838Z", + "timestamp": "2021-03-05T08:51:12.949Z", + "trace_id": "2b099185293344a5bfdd7ad89ebf9416", + "span_id": "5b95c29a5ded4281", + "parent_span_id": "a3b2d1d58b344b07", + "op": "PersonService.create", + "description": "desc", + "status": "aborted" + } + ] }""" val transaction = fixture.serializer.deserialize(StringReader(json), SentryTransaction::class.java) assertNotNull(transaction) @@ -501,6 +515,18 @@ class GsonSerializerTest { assertEquals("http", transaction.contexts.trace!!.operation) assertNotNull(transaction.contexts["custom"]) assertEquals("some-value", (transaction.contexts["custom"] as Map<*, *>)["some-key"]) + + assertNotNull(transaction.spans) + assertEquals(1, transaction.spans.size) + val span = transaction.spans[0] + assertNotNull(span.startTimestamp) + assertNotNull(span.timestamp) + assertEquals("2b099185293344a5bfdd7ad89ebf9416", span.traceId.toString()) + assertEquals("5b95c29a5ded4281", span.spanId.toString()) + assertEquals("a3b2d1d58b344b07", span.parentSpanId.toString()) + assertEquals("PersonService.create", span.op) + assertEquals(SpanStatus.ABORTED, span.status) + assertEquals("desc", span.description) } @Test From 395e5a2e09b1d165622e2677283b76ab0283f112 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 11:58:27 +0100 Subject: [PATCH 15/26] Add tests. --- sentry/src/main/java/io/sentry/SentryClient.java | 2 +- sentry/src/test/java/io/sentry/GsonSerializerTest.kt | 11 +++++++++-- sentry/src/test/java/io/sentry/HubTest.kt | 9 +++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/sentry/src/main/java/io/sentry/SentryClient.java b/sentry/src/main/java/io/sentry/SentryClient.java index 13d3788b6c..e7b18050bb 100644 --- a/sentry/src/main/java/io/sentry/SentryClient.java +++ b/sentry/src/main/java/io/sentry/SentryClient.java @@ -365,7 +365,7 @@ public void captureSession(final @NotNull Session session, final @Nullable Objec transaction.getEventId()); } - transaction = processTransaction(transaction); + processTransaction(transaction); try { final SentryEnvelope envelope = diff --git a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt index 5fc0aba45b..5b450ea91e 100644 --- a/sentry/src/test/java/io/sentry/GsonSerializerTest.kt +++ b/sentry/src/test/java/io/sentry/GsonSerializerTest.kt @@ -484,7 +484,8 @@ class GsonSerializerTest { "trace": { "trace_id": "b156a475de54423d9c1571df97ec7eb6", "span_id": "0a53026963414893", - "op": "http" + "op": "http", + "status": "ok" }, "custom": { "some-key": "some-value" @@ -499,7 +500,10 @@ class GsonSerializerTest { "parent_span_id": "a3b2d1d58b344b07", "op": "PersonService.create", "description": "desc", - "status": "aborted" + "status": "aborted", + "tags": { + "name": "value" + } } ] }""" @@ -510,6 +514,8 @@ class GsonSerializerTest { assertNotNull(transaction.timestamp) assertNotNull(transaction.contexts) assertNotNull(transaction.contexts.trace) + assertEquals(SpanStatus.OK, transaction.status) + assertEquals("transaction", transaction.type) assertEquals("b156a475de54423d9c1571df97ec7eb6", transaction.contexts.trace!!.traceId.toString()) assertEquals("0a53026963414893", transaction.contexts.trace!!.spanId.toString()) assertEquals("http", transaction.contexts.trace!!.operation) @@ -527,6 +533,7 @@ class GsonSerializerTest { assertEquals("PersonService.create", span.op) assertEquals(SpanStatus.ABORTED, span.status) assertEquals("desc", span.description) + assertEquals(mapOf("name" to "value"), span.tags) } @Test diff --git a/sentry/src/test/java/io/sentry/HubTest.kt b/sentry/src/test/java/io/sentry/HubTest.kt index 63f570fc15..c86eefd355 100644 --- a/sentry/src/test/java/io/sentry/HubTest.kt +++ b/sentry/src/test/java/io/sentry/HubTest.kt @@ -1131,12 +1131,17 @@ class HubTest { //region setSpanContext @Test fun `associates span context with throwable`() { - val hub = generateHub() as Hub + val (hub, mockClient) = getEnabledHub() val transaction = hub.startTransaction("aTransaction", "op") val span = transaction.startChild("op") val exception = RuntimeException() + hub.setSpanContext(exception, span) - assertEquals(span.spanContext, hub.getSpanContext(exception)) + hub.captureEvent(SentryEvent(exception)) + + verify(mockClient).captureEvent(check { + assertEquals(span.spanContext, it.contexts.trace) + }, anyOrNull(), anyOrNull()) } @Test From e9b00f16d974b53594553b9c7082b2fcac7bf6b9 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 12:10:33 +0100 Subject: [PATCH 16/26] Deprecate `ITransaction#getContexts`. --- sentry/src/main/java/io/sentry/ITransaction.java | 2 ++ sentry/src/main/java/io/sentry/NoOpTransaction.java | 2 ++ sentry/src/main/java/io/sentry/SentryTracer.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index a86667a85a..56ed42adb5 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -48,6 +48,8 @@ public interface ITransaction extends ISpan { Request getRequest(); @NotNull + @Deprecated + @ApiStatus.ScheduledForRemoval Contexts getContexts(); @NotNull diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index 3bda906e31..47df331944 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -51,6 +51,8 @@ public void setRequest(@Nullable Request request) {} } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @NotNull Contexts getContexts() { return new Contexts(); } diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index de98de19e8..bd89a8d35f 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -206,6 +206,8 @@ public void setRequest(@Nullable Request request) { } @Override + @Deprecated + @ApiStatus.ScheduledForRemoval public @NotNull Contexts getContexts() { final AtomicReference contexts = new AtomicReference<>(); hub.configureScope(scope -> contexts.set(scope.getContexts())); From 63f75d6577a21a3114d4c00d35462a9fcbe53646 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 12:14:43 +0100 Subject: [PATCH 17/26] Changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e13d284864..eaab29df48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Fix: Initialize Sentry in Logback appender when DSN is not set in XML config (#1296) * Fix: Fix JUL integration SDK name (#1293) * Feat: Activity tracing auto instrumentation +* Ref: Separate user facing and protocol classes in the Performance feature (#1304) # 4.2.0 From 791bdaa04777005b029d3dd3ca34519710117f94 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 13:15:24 +0100 Subject: [PATCH 18/26] Fix clearing transaction. --- sentry/src/main/java/io/sentry/SentryTracer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index bd89a8d35f..8373fc4d9d 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -97,7 +97,7 @@ public boolean finish() { @Override public boolean finish(@Nullable SpanStatus status) { if (root.finish(status)) { - hub.withScope( + hub.configureScope( scope -> { scope.withTransaction( transaction -> { From 27f80a1a035d3de2b478ddb4507ef005d2c3696d Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 13:31:16 +0100 Subject: [PATCH 19/26] Add test for fixing clearing transaction. --- .../test/java/io/sentry/SentryTracerTest.kt | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index 45bdeca74f..d738c28bc8 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -3,6 +3,7 @@ package io.sentry import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.spy import com.nhaarman.mockitokotlin2.verify import kotlin.test.Test import kotlin.test.assertEquals @@ -14,7 +15,14 @@ import kotlin.test.assertTrue class SentryTracerTest { private class Fixture { - val hub = mock() + val hub: Hub + + init { + val options = SentryOptions() + options.dsn = "https://key@sentry.io/proj" + hub = spy(Hub(options)) + hub.bindClient(mock()) + } fun getSut(): SentryTracer { return SentryTracer(TransactionContext("name", "op"), hub) @@ -69,6 +77,14 @@ class SentryTracerTest { verify(fixture.hub).captureTransaction(any()) } + @Test + fun `when transaction is finished, transaction is cleared from the scope`() { + val tracer = fixture.getSut() + fixture.hub.configureScope { it.setTransaction(tracer) } + tracer.finish() + assertNull(fixture.hub.span) + } + @Test fun `when transaction with throwable set is finished, span context is associated with throwable`() { val tracer = fixture.getSut() From 5cdee1e98d4e8432b5040c980b9edc2efc4c4867 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Fri, 5 Mar 2021 15:29:22 +0100 Subject: [PATCH 20/26] Polish --- sentry/api/sentry.api | 3 - .../src/main/java/io/sentry/ITransaction.java | 58 +++++++++---------- .../main/java/io/sentry/NoOpTransaction.java | 11 +--- .../src/main/java/io/sentry/SentryTracer.java | 14 +---- .../io/sentry/protocol/SentryTransaction.java | 1 + 5 files changed, 32 insertions(+), 55 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 0401034118..6442b969e9 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -307,7 +307,6 @@ public abstract interface class io/sentry/ITransaction : io/sentry/ISpan { public abstract fun getName ()Ljava/lang/String; public abstract fun getRequest ()Lio/sentry/protocol/Request; public abstract fun getSpans ()Ljava/util/List; - public abstract fun getTransaction ()Ljava/lang/String; public abstract fun isSampled ()Ljava/lang/Boolean; public abstract fun setName (Ljava/lang/String;)V public abstract fun setRequest (Lio/sentry/protocol/Request;)V @@ -384,7 +383,6 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { public fun getStatus ()Lio/sentry/SpanStatus; public fun getTag (Ljava/lang/String;)Ljava/lang/String; public fun getThrowable ()Ljava/lang/Throwable; - public fun getTransaction ()Ljava/lang/String; public fun isFinished ()Z public fun isSampled ()Ljava/lang/Boolean; public fun setDescription (Ljava/lang/String;)V @@ -872,7 +870,6 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun getTag (Ljava/lang/String;)Ljava/lang/String; public fun getThrowable ()Ljava/lang/Throwable; public fun getTimestamp ()Ljava/util/Date; - public fun getTransaction ()Ljava/lang/String; public fun isFinished ()Z public fun isSampled ()Ljava/lang/Boolean; public fun setDescription (Ljava/lang/String;)V diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index 56ed42adb5..355dcd2276 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -26,32 +26,6 @@ public interface ITransaction extends ISpan { @NotNull String getName(); - /** - * Attaches request information to the transaction. - * - * @param request the request - * @deprecated use {@link Scope#setRequest(Request)} - */ - @Deprecated - @ApiStatus.ScheduledForRemoval - void setRequest(@Nullable Request request); - - /** - * Returns the request information from the transaction - * - * @return the request or {@code null} if not set - * @deprecated use {@link Scope#getRequest()} - */ - @Nullable - @Deprecated - @ApiStatus.ScheduledForRemoval - Request getRequest(); - - @NotNull - @Deprecated - @ApiStatus.ScheduledForRemoval - Contexts getContexts(); - @NotNull @TestOnly List getSpans(); @@ -77,18 +51,38 @@ public interface ITransaction extends ISpan { * * @return the event id */ - @Nullable + @NotNull SentryId getEventId(); /** - * Returns the transaction name. + * Attaches request information to the transaction. * - * @deprecated use {@link #getName()} - * @return transaction name + * @param request the request + * @deprecated use {@link Scope#setRequest(Request)} + */ + @Deprecated + @ApiStatus.ScheduledForRemoval + void setRequest(@Nullable Request request); + + /** + * Returns the request information from the transaction + * + * @return the request or {@code null} if not set + * @deprecated use {@link Scope#getRequest()} */ @Nullable - @ApiStatus.Internal @Deprecated @ApiStatus.ScheduledForRemoval - String getTransaction(); + Request getRequest(); + + /** + * Returns contexts asociated with the transaction. + * + * @return the contexts + * @deprecated use {@link Scope#getContexts()} + */ + @NotNull + @Deprecated + @ApiStatus.ScheduledForRemoval + Contexts getContexts(); } diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index 47df331944..ee0e306a22 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -73,15 +73,8 @@ public void setRequest(@Nullable Request request) {} } @Override - public @Nullable SentryId getEventId() { - return null; - } - - @Override - @Deprecated - @ApiStatus.ScheduledForRemoval - public @Nullable String getTransaction() { - return null; + public @NotNull SentryId getEventId() { + return SentryId.EMPTY_ID; } @Override diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 8373fc4d9d..421271434f 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -16,6 +16,7 @@ @ApiStatus.Internal public final class SentryTracer implements ITransaction { + private final @NotNull SentryId eventId = new SentryId(); private final @NotNull Span root; private final @NotNull List children = new CopyOnWriteArrayList<>(); private final @NotNull IHub hub; @@ -233,17 +234,8 @@ public void setRequest(@Nullable Request request) { } @Override - @Deprecated - @ApiStatus.ScheduledForRemoval - public @Nullable SentryId getEventId() { - return null; - } - - @Override - @Deprecated - @ApiStatus.ScheduledForRemoval - public @Nullable String getTransaction() { - return this.getName(); + public @NotNull SentryId getEventId() { + return eventId; } @NotNull diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 5f96df230e..1e44e827d7 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -35,6 +35,7 @@ public final class SentryTransaction extends SentryBaseEvent { private @NotNull final String type = "transaction"; public SentryTransaction(final @NotNull SentryTracer sentryTracer) { + super(sentryTracer.getEventId()); Objects.requireNonNull(sentryTracer, "sentryTracer is required"); this.startTimestamp = sentryTracer.getStartTimestamp(); this.timestamp = DateUtils.getCurrentDateTime(); From 389f90991551191a708805eab64e30ac742a87b9 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 8 Mar 2021 11:59:44 +0100 Subject: [PATCH 21/26] Put request and contexts on SentryTracer. --- .../src/main/java/io/sentry/SentryTracer.java | 15 +++---- .../io/sentry/protocol/SentryTransaction.java | 10 ++++- .../test/java/io/sentry/SentryTracerTest.kt | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 421271434f..5e2f04e650 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -9,7 +9,6 @@ import java.util.Date; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicReference; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -20,6 +19,8 @@ public final class SentryTracer implements ITransaction { private final @NotNull Span root; private final @NotNull List children = new CopyOnWriteArrayList<>(); private final @NotNull IHub hub; + private @Nullable Request request; + private @NotNull Contexts contexts = new Contexts(); public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { Objects.requireNonNull(context, "context is required"); @@ -193,26 +194,22 @@ public void setName(@NotNull String name) { @Override @Deprecated @ApiStatus.ScheduledForRemoval - public void setRequest(@Nullable Request request) { - hub.configureScope(scope -> scope.setRequest(request)); + public void setRequest(final @Nullable Request request) { + this.request = request; } @Override @Deprecated @ApiStatus.ScheduledForRemoval public @Nullable Request getRequest() { - final AtomicReference contexts = new AtomicReference<>(); - hub.configureScope(scope -> contexts.set(scope.getRequest())); - return contexts.get(); + return this.request; } @Override @Deprecated @ApiStatus.ScheduledForRemoval public @NotNull Contexts getContexts() { - final AtomicReference contexts = new AtomicReference<>(); - hub.configureScope(scope -> contexts.set(scope.getContexts())); - return contexts.get(); + return this.contexts; } @Override diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 1e44e827d7..27135ed6dc 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -11,6 +11,8 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Map; + import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -34,6 +36,7 @@ public final class SentryTransaction extends SentryBaseEvent { @SuppressWarnings("UnusedVariable") private @NotNull final String type = "transaction"; + @SuppressWarnings("deprecation") public SentryTransaction(final @NotNull SentryTracer sentryTracer) { super(sentryTracer.getEventId()); Objects.requireNonNull(sentryTracer, "sentryTracer is required"); @@ -43,7 +46,12 @@ public SentryTransaction(final @NotNull SentryTracer sentryTracer) { for (final Span span : sentryTracer.getChildren()) { this.spans.add(new SentrySpan(span)); } - this.getContexts().setTrace(sentryTracer.getSpanContext()); + final Contexts contexts = this.getContexts(); + for(Map.Entry entry : sentryTracer.getContexts().entrySet()) { + contexts.put(entry.getKey(), entry.getValue()); + } + contexts.setTrace(sentryTracer.getSpanContext()); + this.setRequest(sentryTracer.getRequest()); } public @NotNull List getSpans() { diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index d738c28bc8..671a199dfa 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -5,9 +5,12 @@ import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.spy import com.nhaarman.mockitokotlin2.verify +import io.sentry.protocol.App +import io.sentry.protocol.Request import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotEquals import kotlin.test.assertNotNull import kotlin.test.assertNull import kotlin.test.assertTrue @@ -94,6 +97,45 @@ class SentryTracerTest { verify(fixture.hub).setSpanContext(ex, tracer.root) } + @Test + fun `when transaction with request set is finished, request is set on the transaction`() { + val tracer = fixture.getSut() + val request = Request() + tracer.request = request + tracer.finish() + verify(fixture.hub).captureTransaction(check { + assertEquals(request, it.request) + }) + } + + @Test + fun `when transaction with contexts is finished, contexts are set on the transaction`() { + val tracer = fixture.getSut() + val contexts = tracer.contexts + val app = App() + contexts.setApp(app) + contexts["custom"] = "value" + tracer.finish() + verify(fixture.hub).captureTransaction(check { + assertEquals(app, it.contexts.app) + assertEquals("value", it.contexts["custom"]) + assertEquals(tracer.spanContext, it.contexts.trace) + }) + } + + @Test + fun `when transaction with contexts has overwritten trace, tracer span context is applied to transaction`() { + val tracer = fixture.getSut() + val contexts = tracer.contexts + val spanContext = SpanContext("op") + contexts.trace = spanContext + tracer.finish() + verify(fixture.hub).captureTransaction(check { + assertNotEquals(spanContext, it.contexts.trace) + assertEquals(tracer.spanContext, it.contexts.trace) + }) + } + @Test fun `returns sentry-trace header`() { val tracer = fixture.getSut() From ed3e6fb5dac43891e3d1382fd714e7d2e3d74b5e Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 8 Mar 2021 12:15:48 +0100 Subject: [PATCH 22/26] Polish Javadocs. --- sentry/src/main/java/io/sentry/ITransaction.java | 2 +- sentry/src/main/java/io/sentry/NoOpTransaction.java | 3 +++ sentry/src/main/java/io/sentry/protocol/SentryTransaction.java | 3 +-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sentry/src/main/java/io/sentry/ITransaction.java b/sentry/src/main/java/io/sentry/ITransaction.java index 355dcd2276..dec6878acc 100644 --- a/sentry/src/main/java/io/sentry/ITransaction.java +++ b/sentry/src/main/java/io/sentry/ITransaction.java @@ -76,7 +76,7 @@ public interface ITransaction extends ISpan { Request getRequest(); /** - * Returns contexts asociated with the transaction. + * Returns contexts associated with the transaction. * * @return the contexts * @deprecated use {@link Scope#getContexts()} diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index ee0e306a22..6a302f405a 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -38,11 +38,13 @@ public void setName(@NotNull String name) {} return NoOpSpan.getInstance(); } + /** @deprecated use {@link Scope#setRequest(Request)} */ @Override @Deprecated @ApiStatus.ScheduledForRemoval public void setRequest(@Nullable Request request) {} + /** @deprecated use {@link Scope#getRequest()} */ @Override @Deprecated @ApiStatus.ScheduledForRemoval @@ -50,6 +52,7 @@ public void setRequest(@Nullable Request request) {} return null; } + /** @deprecated use {@link Scope#getContexts()} */ @Override @Deprecated @ApiStatus.ScheduledForRemoval diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index 27135ed6dc..d38127c08e 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -12,7 +12,6 @@ import java.util.Date; import java.util.List; import java.util.Map; - import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -47,7 +46,7 @@ public SentryTransaction(final @NotNull SentryTracer sentryTracer) { this.spans.add(new SentrySpan(span)); } final Contexts contexts = this.getContexts(); - for(Map.Entry entry : sentryTracer.getContexts().entrySet()) { + for (Map.Entry entry : sentryTracer.getContexts().entrySet()) { contexts.put(entry.getKey(), entry.getValue()); } contexts.setTrace(sentryTracer.getSpanContext()); From eeb8ed5de22f83c938c34cc7056556e8a633ce1b Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Mon, 8 Mar 2021 14:45:17 +0100 Subject: [PATCH 23/26] Make finish return void. --- sentry/api/sentry.api | 20 +++++++++---------- sentry/src/main/java/io/sentry/ISpan.java | 13 +++--------- sentry/src/main/java/io/sentry/NoOpSpan.java | 8 ++------ .../main/java/io/sentry/NoOpTransaction.java | 8 ++------ .../src/main/java/io/sentry/SentryTracer.java | 12 +++++------ sentry/src/main/java/io/sentry/Span.java | 9 ++++----- 6 files changed, 26 insertions(+), 44 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 6442b969e9..5a4166bb57 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -281,8 +281,8 @@ public abstract interface class io/sentry/ISerializer { public abstract interface class io/sentry/ISpan { public static final field NAME_TAG Ljava/lang/String; - public abstract fun finish ()Z - public abstract fun finish (Lio/sentry/SpanStatus;)Z + public abstract fun finish ()V + public abstract fun finish (Lio/sentry/SpanStatus;)V public abstract fun getDescription ()Ljava/lang/String; public abstract fun getOperation ()Ljava/lang/String; public abstract fun getSpanContext ()Lio/sentry/SpanContext; @@ -347,8 +347,8 @@ public final class io/sentry/NoOpLogger : io/sentry/ILogger { } public final class io/sentry/NoOpSpan : io/sentry/ISpan { - public fun finish ()Z - public fun finish (Lio/sentry/SpanStatus;)Z + public fun finish ()V + public fun finish (Lio/sentry/SpanStatus;)V public fun getDescription ()Ljava/lang/String; public static fun getInstance ()Lio/sentry/NoOpSpan; public fun getOperation ()Ljava/lang/String; @@ -368,8 +368,8 @@ public final class io/sentry/NoOpSpan : io/sentry/ISpan { } public final class io/sentry/NoOpTransaction : io/sentry/ITransaction { - public fun finish ()Z - public fun finish (Lio/sentry/SpanStatus;)Z + public fun finish ()V + public fun finish (Lio/sentry/SpanStatus;)V public fun getContexts ()Lio/sentry/protocol/Contexts; public fun getDescription ()Ljava/lang/String; public fun getEventId ()Lio/sentry/protocol/SentryId; @@ -853,8 +853,8 @@ public final class io/sentry/SentryTraceHeader { public final class io/sentry/SentryTracer : io/sentry/ITransaction { public fun (Lio/sentry/TransactionContext;Lio/sentry/IHub;)V - public fun finish ()Z - public fun finish (Lio/sentry/SpanStatus;)Z + public fun finish ()V + public fun finish (Lio/sentry/SpanStatus;)V public fun getChildren ()Ljava/util/List; public fun getContexts ()Lio/sentry/protocol/Contexts; public fun getDescription ()Ljava/lang/String; @@ -932,8 +932,8 @@ public final class io/sentry/ShutdownHookIntegration : io/sentry/Integration { } public final class io/sentry/Span : io/sentry/ISpan { - public fun finish ()Z - public fun finish (Lio/sentry/SpanStatus;)Z + public fun finish ()V + public fun finish (Lio/sentry/SpanStatus;)V public fun getDescription ()Ljava/lang/String; public fun getOperation ()Ljava/lang/String; public fun getParentSpanId ()Lio/sentry/SpanId; diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index c374f1f1f9..c0a2721a43 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -33,22 +33,15 @@ public interface ISpan { @NotNull SentryTraceHeader toSentryTrace(); - /** - * Sets span timestamp marking this span as finished. - * - * @return true if transaction has been successfully finished or false if span has been already - * finished - */ - boolean finish(); + /** Sets span timestamp marking this span as finished. */ + void finish(); /** * Sets span timestamp marking this span as finished. * * @param status - the status - * @return true if transaction has been successfully finished or false if span has been already - * finished */ - boolean finish(@Nullable SpanStatus status); + void finish(@Nullable SpanStatus status); /** * Sets span operation. diff --git a/sentry/src/main/java/io/sentry/NoOpSpan.java b/sentry/src/main/java/io/sentry/NoOpSpan.java index f9975ccdaf..75f44ff085 100644 --- a/sentry/src/main/java/io/sentry/NoOpSpan.java +++ b/sentry/src/main/java/io/sentry/NoOpSpan.java @@ -31,14 +31,10 @@ public static NoOpSpan getInstance() { } @Override - public boolean finish() { - return true; - } + public void finish() {} @Override - public boolean finish(@Nullable SpanStatus status) { - return true; - } + public void finish(@Nullable SpanStatus status) {} @Override public void setOperation(@NotNull String operation) {} diff --git a/sentry/src/main/java/io/sentry/NoOpTransaction.java b/sentry/src/main/java/io/sentry/NoOpTransaction.java index 6a302f405a..7afe6e0b8e 100644 --- a/sentry/src/main/java/io/sentry/NoOpTransaction.java +++ b/sentry/src/main/java/io/sentry/NoOpTransaction.java @@ -91,14 +91,10 @@ public boolean isFinished() { } @Override - public boolean finish() { - return true; - } + public void finish() {} @Override - public boolean finish(@Nullable SpanStatus status) { - return true; - } + public void finish(@Nullable SpanStatus status) {} @Override public void setOperation(@NotNull String operation) {} diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 5e2f04e650..274b445790 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -92,13 +92,14 @@ private ISpan startChild(final @NotNull SpanId parentSpanId, final @NotNull Stri } @Override - public boolean finish() { - return this.finish(this.getStatus()); + public void finish() { + this.finish(this.getStatus()); } @Override - public boolean finish(@Nullable SpanStatus status) { - if (root.finish(status)) { + public void finish(@Nullable SpanStatus status) { + if (!root.isFinished()) { + root.finish(status); hub.configureScope( scope -> { scope.withTransaction( @@ -110,9 +111,6 @@ public boolean finish(@Nullable SpanStatus status) { }); SentryTransaction transaction = new SentryTransaction(this); hub.captureTransaction(transaction); - return true; - } else { - return false; } } diff --git a/sentry/src/main/java/io/sentry/Span.java b/sentry/src/main/java/io/sentry/Span.java index 27e851e014..62d5dafb8c 100644 --- a/sentry/src/main/java/io/sentry/Span.java +++ b/sentry/src/main/java/io/sentry/Span.java @@ -80,15 +80,15 @@ public final class Span implements ISpan { } @Override - public boolean finish() { - return this.finish(this.context.getStatus()); + public void finish() { + this.finish(this.context.getStatus()); } @Override - public boolean finish(@Nullable SpanStatus status) { + public void finish(@Nullable SpanStatus status) { // the span can be finished only once if (!finished.compareAndSet(false, true)) { - return false; + return; } this.context.setStatus(status); @@ -96,7 +96,6 @@ public boolean finish(@Nullable SpanStatus status) { if (throwable != null) { hub.setSpanContext(throwable, this); } - return true; } @Override From 1dc5e6e70086448ec2d32f6f0c26414ed25fd66c Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 9 Mar 2021 09:01:03 +0100 Subject: [PATCH 24/26] Remove tag created for keeping transaction name. --- sentry/api/sentry.api | 1 - sentry/src/main/java/io/sentry/ISpan.java | 1 - sentry/src/main/java/io/sentry/SentryTracer.java | 9 +++++---- .../main/java/io/sentry/protocol/SentryTransaction.java | 3 +-- sentry/src/test/java/io/sentry/ScopeTest.kt | 2 +- sentry/src/test/java/io/sentry/SentryTracerTest.kt | 4 +++- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 5a4166bb57..ce359ba366 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -280,7 +280,6 @@ public abstract interface class io/sentry/ISerializer { } public abstract interface class io/sentry/ISpan { - public static final field NAME_TAG Ljava/lang/String; public abstract fun finish ()V public abstract fun finish (Lio/sentry/SpanStatus;)V public abstract fun getDescription ()Ljava/lang/String; diff --git a/sentry/src/main/java/io/sentry/ISpan.java b/sentry/src/main/java/io/sentry/ISpan.java index c0a2721a43..145423a85a 100644 --- a/sentry/src/main/java/io/sentry/ISpan.java +++ b/sentry/src/main/java/io/sentry/ISpan.java @@ -5,7 +5,6 @@ /** Represents performance monitoring Span. */ public interface ISpan { - String NAME_TAG = "sentry-name"; /** * Starts a child Span. * diff --git a/sentry/src/main/java/io/sentry/SentryTracer.java b/sentry/src/main/java/io/sentry/SentryTracer.java index 274b445790..af7c98ff35 100644 --- a/sentry/src/main/java/io/sentry/SentryTracer.java +++ b/sentry/src/main/java/io/sentry/SentryTracer.java @@ -19,14 +19,15 @@ public final class SentryTracer implements ITransaction { private final @NotNull Span root; private final @NotNull List children = new CopyOnWriteArrayList<>(); private final @NotNull IHub hub; + private final @NotNull Contexts contexts = new Contexts(); private @Nullable Request request; - private @NotNull Contexts contexts = new Contexts(); + private @NotNull String name; public SentryTracer(final @NotNull TransactionContext context, final @NotNull IHub hub) { Objects.requireNonNull(context, "context is required"); Objects.requireNonNull(hub, "hub is required"); this.root = new Span(context, this, hub); - this.root.setTag(ISpan.NAME_TAG, context.getName()); + this.name = context.getName(); this.hub = hub; } @@ -181,12 +182,12 @@ public boolean isFinished() { @Override public void setName(@NotNull String name) { - this.root.setTag(ISpan.NAME_TAG, name); + this.name = name; } @Override public @NotNull String getName() { - return this.root.getTag(ISpan.NAME_TAG); + return this.name; } @Override diff --git a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java index d38127c08e..0004ee899f 100644 --- a/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java +++ b/sentry/src/main/java/io/sentry/protocol/SentryTransaction.java @@ -1,7 +1,6 @@ package io.sentry.protocol; import io.sentry.DateUtils; -import io.sentry.ISpan; import io.sentry.SentryBaseEvent; import io.sentry.SentryTracer; import io.sentry.Span; @@ -41,7 +40,7 @@ public SentryTransaction(final @NotNull SentryTracer sentryTracer) { Objects.requireNonNull(sentryTracer, "sentryTracer is required"); this.startTimestamp = sentryTracer.getStartTimestamp(); this.timestamp = DateUtils.getCurrentDateTime(); - this.transaction = sentryTracer.getTag(ISpan.NAME_TAG); + this.transaction = sentryTracer.getName(); for (final Span span : sentryTracer.getChildren()) { this.spans.add(new SentrySpan(span)); } diff --git a/sentry/src/test/java/io/sentry/ScopeTest.kt b/sentry/src/test/java/io/sentry/ScopeTest.kt index cbe3753dd7..f990dd806b 100644 --- a/sentry/src/test/java/io/sentry/ScopeTest.kt +++ b/sentry/src/test/java/io/sentry/ScopeTest.kt @@ -120,7 +120,7 @@ class ScopeTest { assertEquals("abc", clone.fingerprint.first()) assertEquals("message", clone.breadcrumbs.first().message) - assertEquals("transaction-name", (clone.span as SentryTracer).getTag(ISpan.NAME_TAG)) + assertEquals("transaction-name", (clone.span as SentryTracer).name) assertEquals("tag", clone.tags["tag"]) assertEquals("extra", clone.extras["extra"]) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index 671a199dfa..8fb61c23ce 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -77,7 +77,9 @@ class SentryTracerTest { fun `when transaction is finished, transaction is captured`() { val tracer = fixture.getSut() tracer.finish() - verify(fixture.hub).captureTransaction(any()) + verify(fixture.hub).captureTransaction(check { + assertEquals(it.transaction, tracer.name) + }) } @Test From e495ba3cd24471a442f59b103fb9e3c2d8f7cf4c Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 9 Mar 2021 09:09:18 +0100 Subject: [PATCH 25/26] Spotless. --- sentry/src/test/java/io/sentry/SentryTracerTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index 8fb61c23ce..7deee28dfb 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -1,6 +1,5 @@ package io.sentry -import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.check import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.spy From f2ff5b0725f537e0e1a3e8d1ccc5cad39d989295 Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Tue, 9 Mar 2021 16:57:08 +0100 Subject: [PATCH 26/26] Polish. --- .../io/sentry/spring/tracing/SentryTransactionAdviceTest.kt | 1 - sentry/src/test/java/io/sentry/SentryTracerTest.kt | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt index 37a00503d9..3db548f61d 100644 --- a/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt +++ b/sentry-spring/src/test/kotlin/io/sentry/spring/tracing/SentryTransactionAdviceTest.kt @@ -79,7 +79,6 @@ class SentryTransactionAdviceTest { fun `creates transaction around method in class annotated with @SentryTransaction`() { classAnnotatedSampleService.hello() verify(hub).captureTransaction(check { - println(it) assertThat(it.transaction).isEqualTo("ClassAnnotatedSampleService.hello") assertThat(it.contexts.trace!!.operation).isEqualTo("op") }) diff --git a/sentry/src/test/java/io/sentry/SentryTracerTest.kt b/sentry/src/test/java/io/sentry/SentryTracerTest.kt index 7deee28dfb..6bfb8dfad1 100644 --- a/sentry/src/test/java/io/sentry/SentryTracerTest.kt +++ b/sentry/src/test/java/io/sentry/SentryTracerTest.kt @@ -85,6 +85,7 @@ class SentryTracerTest { fun `when transaction is finished, transaction is cleared from the scope`() { val tracer = fixture.getSut() fixture.hub.configureScope { it.setTransaction(tracer) } + assertNotNull(fixture.hub.span) tracer.finish() assertNull(fixture.hub.span) }