Skip to content

Commit

Permalink
Merge branch 'feat/7.0.0' into feat/observe-network
Browse files Browse the repository at this point in the history
  • Loading branch information
romtsn committed Sep 28, 2023
2 parents d911aa8 + 72e23fc commit 932b404
Show file tree
Hide file tree
Showing 16 changed files with 239 additions and 30 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Breaking changes:

- Measure AppStart time till First Draw instead of `onResume` ([#2851](https://github.com/getsentry/sentry-java/pull/2851))
- Do not overwrite UI transaction status if set by the user ([#2852](https://github.com/getsentry/sentry-java/pull/2852))
- Capture unfinished transaction on Scope with status `aborted` in case a crash happens ([#2938](https://github.com/getsentry/sentry-java/pull/2938))
- This will fix the link between transactions and corresponding crashes, you'll be able to see them in a single trace

Breaking changes:
- Move enableNdk from SentryOptions to SentryAndroidOptions ([#2793](https://github.com/getsentry/sentry-java/pull/2793))
Expand Down
2 changes: 2 additions & 0 deletions sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ public class io/sentry/android/core/AnrV2Integration : io/sentry/Integration, ja
public final class io/sentry/android/core/AnrV2Integration$AnrV2Hint : io/sentry/hints/BlockingFlushHint, io/sentry/hints/AbnormalExit, io/sentry/hints/Backfillable {
public fun <init> (JLio/sentry/ILogger;JZZ)V
public fun ignoreCurrentThread ()Z
public fun isFlushable (Lio/sentry/protocol/SentryId;)Z
public fun mechanism ()Ljava/lang/String;
public fun setFlushable (Lio/sentry/protocol/SentryId;)V
public fun shouldEnrich ()Z
public fun timestamp ()Ljava/lang/Long;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,14 @@ public boolean shouldEnrich() {
public String mechanism() {
return isBackgroundAnr ? "anr_background" : "anr_foreground";
}

@Override
public boolean isFlushable(@Nullable SentryId eventId) {
return true;

Check warning on line 392 in sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java

View check run for this annotation

Codecov / codecov/patch

sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java#L392

Added line #L392 was not covered by tests
}

@Override
public void setFlushable(@NotNull SentryId eventId) {}

Check warning on line 396 in sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java

View check run for this annotation

Codecov / codecov/patch

sentry-android-core/src/main/java/io/sentry/android/core/AnrV2Integration.java#L396

Added line #L396 was not covered by tests
}

static final class ParseResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1465,7 +1465,7 @@ class ActivityLifecycleIntegrationTest {
val activity = mock<Activity>()
sut.onActivityCreated(activity, fixture.bundle)

fixture.transaction.forceFinish(OK, false)
fixture.transaction.forceFinish(OK, false, null)
verify(fixture.activityFramesTracker).setMetrics(activity, fixture.transaction.eventId)
}

Expand Down
18 changes: 11 additions & 7 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -667,8 +667,8 @@ public abstract interface class io/sentry/ISpan {
}

public abstract interface class io/sentry/ITransaction : io/sentry/ISpan {
public abstract fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;Z)V
public abstract fun forceFinish (Lio/sentry/SpanStatus;Z)V
public abstract fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;ZLio/sentry/Hint;)V
public abstract fun forceFinish (Lio/sentry/SpanStatus;ZLio/sentry/Hint;)V
public abstract fun getContexts ()Lio/sentry/protocol/Contexts;
public abstract fun getEventId ()Lio/sentry/protocol/SentryId;
public abstract fun getLatestActiveSpan ()Lio/sentry/Span;
Expand Down Expand Up @@ -987,8 +987,8 @@ public final class io/sentry/NoOpTransaction : io/sentry/ITransaction {
public fun finish ()V
public fun finish (Lio/sentry/SpanStatus;)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;Z)V
public fun forceFinish (Lio/sentry/SpanStatus;Z)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;ZLio/sentry/Hint;)V
public fun forceFinish (Lio/sentry/SpanStatus;ZLio/sentry/Hint;)V
public fun getContexts ()Lio/sentry/protocol/Contexts;
public fun getData (Ljava/lang/String;)Ljava/lang/Object;
public fun getDescription ()Ljava/lang/String;
Expand Down Expand Up @@ -2061,8 +2061,8 @@ public final class io/sentry/SentryTracer : io/sentry/ITransaction {
public fun finish ()V
public fun finish (Lio/sentry/SpanStatus;)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;Z)V
public fun forceFinish (Lio/sentry/SpanStatus;Z)V
public fun finish (Lio/sentry/SpanStatus;Lio/sentry/SentryDate;ZLio/sentry/Hint;)V
public fun forceFinish (Lio/sentry/SpanStatus;ZLio/sentry/Hint;)V
public fun getChildren ()Ljava/util/List;
public fun getContexts ()Lio/sentry/protocol/Contexts;
public fun getData ()Ljava/util/Map;
Expand Down Expand Up @@ -2509,8 +2509,10 @@ public final class io/sentry/UncaughtExceptionHandlerIntegration : io/sentry/Int
public fun uncaughtException (Ljava/lang/Thread;Ljava/lang/Throwable;)V
}

public class io/sentry/UncaughtExceptionHandlerIntegration$UncaughtExceptionHint : io/sentry/hints/BlockingFlushHint, io/sentry/hints/SessionEnd {
public class io/sentry/UncaughtExceptionHandlerIntegration$UncaughtExceptionHint : io/sentry/hints/BlockingFlushHint, io/sentry/hints/SessionEnd, io/sentry/hints/TransactionEnd {
public fun <init> (JLio/sentry/ILogger;)V
public fun isFlushable (Lio/sentry/protocol/SentryId;)Z
public fun setFlushable (Lio/sentry/protocol/SentryId;)V
}

public final class io/sentry/UserFeedback : io/sentry/JsonSerializable, io/sentry/JsonUnknown {
Expand Down Expand Up @@ -2763,7 +2765,9 @@ public abstract interface class io/sentry/hints/Cached {
}

public abstract interface class io/sentry/hints/DiskFlushNotification {
public abstract fun isFlushable (Lio/sentry/protocol/SentryId;)Z
public abstract fun markFlushed ()V
public abstract fun setFlushable (Lio/sentry/protocol/SentryId;)V
}

public abstract interface class io/sentry/hints/Enqueable {
Expand Down
8 changes: 6 additions & 2 deletions sentry/src/main/java/io/sentry/ITransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,17 @@ ISpan startChild(
* @param dropIfNoChildren true, if the transaction should be dropped when it e.g. contains no
* child spans. Usually true, but can be set to falseS for situations were the transaction and
* profile provide crucial context (e.g. ANRs)
* @param hint An optional hint to pass down to the client/transport layer
*/
@ApiStatus.Internal
void forceFinish(@NotNull final SpanStatus status, boolean dropIfNoChildren);
void forceFinish(@NotNull final SpanStatus status, boolean dropIfNoChildren, @Nullable Hint hint);

@ApiStatus.Internal
void finish(
@Nullable SpanStatus status, @Nullable SentryDate timestamp, boolean dropIfNoChildren);
@Nullable SpanStatus status,
@Nullable SentryDate timestamp,
boolean dropIfNoChildren,
@Nullable Hint hint);

@ApiStatus.Internal
void setContext(@NotNull String key, @NotNull Object context);
Expand Down
8 changes: 6 additions & 2 deletions sentry/src/main/java/io/sentry/NoOpTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,15 @@ public void setName(@NotNull String name, @NotNull TransactionNameSource transac
public void scheduleFinish() {}

@Override
public void forceFinish(@NotNull SpanStatus status, boolean dropIfNoChildren) {}
public void forceFinish(
@NotNull SpanStatus status, boolean dropIfNoChildren, @Nullable Hint hint) {}

@Override
public void finish(
@Nullable SpanStatus status, @Nullable SentryDate timestamp, boolean dropIfNoChildren) {}
@Nullable SpanStatus status,
@Nullable SentryDate timestamp,
boolean dropIfNoChildren,
@Nullable Hint hint) {}

@Override
public boolean isFinished() {
Expand Down
14 changes: 10 additions & 4 deletions sentry/src/main/java/io/sentry/SentryClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.sentry.exception.SentryEnvelopeException;
import io.sentry.hints.AbnormalExit;
import io.sentry.hints.Backfillable;
import io.sentry.hints.DiskFlushNotification;
import io.sentry.hints.TransactionEnd;
import io.sentry.protocol.Contexts;
import io.sentry.protocol.SentryId;
Expand Down Expand Up @@ -210,14 +211,19 @@ private boolean shouldApplyScopeData(
sentryId = SentryId.EMPTY_ID;
}

// if we encountered an abnormal exit finish tracing in order to persist and send
// if we encountered a crash/abnormal exit finish tracing in order to persist and send
// any running transaction / profiling data
if (scope != null) {
@Nullable ITransaction transaction = scope.getTransaction();
final @Nullable ITransaction transaction = scope.getTransaction();
if (transaction != null) {
// TODO if we want to do the same for crashes, e.g. check for event.isCrashed()
if (HintUtils.hasType(hint, TransactionEnd.class)) {
transaction.forceFinish(SpanStatus.ABORTED, false);
final Object sentrySdkHint = HintUtils.getSentrySdkHint(hint);
if (sentrySdkHint instanceof DiskFlushNotification) {
((DiskFlushNotification) sentrySdkHint).setFlushable(transaction.getEventId());
transaction.forceFinish(SpanStatus.ABORTED, false, hint);
} else {
transaction.forceFinish(SpanStatus.ABORTED, false, null);
}
}
}
}
Expand Down
17 changes: 11 additions & 6 deletions sentry/src/main/java/io/sentry/SentryTracer.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,14 @@ private void onDeadlineTimeoutReached() {
final @Nullable SpanStatus status = getStatus();
forceFinish(
(status != null) ? status : SpanStatus.DEADLINE_EXCEEDED,
transactionOptions.getIdleTimeout() != null);
transactionOptions.getIdleTimeout() != null,
null);
isDeadlineTimerRunning.set(false);
}

@Override
public @NotNull void forceFinish(@NotNull SpanStatus status, boolean dropIfNoChildren) {
public @NotNull void forceFinish(
final @NotNull SpanStatus status, final boolean dropIfNoChildren, final @Nullable Hint hint) {
if (isFinished()) {
return;
}
Expand All @@ -168,12 +170,15 @@ private void onDeadlineTimeoutReached() {
span.setSpanFinishedCallback(null);
span.finish(status, finishTimestamp);
}
finish(status, finishTimestamp, dropIfNoChildren);
finish(status, finishTimestamp, dropIfNoChildren, hint);
}

@Override
public void finish(
@Nullable SpanStatus status, @Nullable SentryDate finishDate, boolean dropIfNoChildren) {
@Nullable SpanStatus status,
@Nullable SentryDate finishDate,
boolean dropIfNoChildren,
@Nullable Hint hint) {
// try to get the high precision timestamp from the root span
SentryDate finishTimestamp = root.getFinishDate();

Expand Down Expand Up @@ -259,7 +264,7 @@ public void finish(
}

transaction.getMeasurements().putAll(measurements);
hub.captureTransaction(transaction, traceContext(), null, profilingTraceData);
hub.captureTransaction(transaction, traceContext(), hint, profilingTraceData);
}
}

Expand Down Expand Up @@ -537,7 +542,7 @@ public void finish(@Nullable SpanStatus status) {
@Override
@ApiStatus.Internal
public void finish(@Nullable SpanStatus status, @Nullable SentryDate finishDate) {
finish(status, finishDate, true);
finish(status, finishDate, true, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
import io.sentry.hints.BlockingFlushHint;
import io.sentry.hints.EventDropReason;
import io.sentry.hints.SessionEnd;
import io.sentry.hints.TransactionEnd;
import io.sentry.protocol.Mechanism;
import io.sentry.protocol.SentryId;
import io.sentry.util.HintUtils;
import io.sentry.util.Objects;
import java.io.Closeable;
import java.util.concurrent.atomic.AtomicReference;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -97,6 +99,11 @@ public void uncaughtException(Thread thread, Throwable thrown) {
final SentryEvent event = new SentryEvent(throwable);
event.setLevel(SentryLevel.FATAL);

final ITransaction transaction = hub.getTransaction();
if (transaction == null && event.getEventId() != null) {
// if there's no active transaction on scope, this event can trigger flush notification
exceptionHint.setFlushable(event.getEventId());
}
final Hint hint = HintUtils.createWithTypeCheckHint(exceptionHint);

final @NotNull SentryId sentryId = hub.captureEvent(event, hint);
Expand Down Expand Up @@ -156,10 +163,24 @@ public void close() {

@Open // open for tests
@ApiStatus.Internal
public static class UncaughtExceptionHint extends BlockingFlushHint implements SessionEnd {
public static class UncaughtExceptionHint extends BlockingFlushHint
implements SessionEnd, TransactionEnd {

private final AtomicReference<SentryId> flushableEventId = new AtomicReference<>();

public UncaughtExceptionHint(final long flushTimeoutMillis, final @NotNull ILogger logger) {
super(flushTimeoutMillis, logger);
}

@Override
public boolean isFlushable(final @Nullable SentryId eventId) {
final SentryId unwrapped = flushableEventId.get();
return unwrapped != null && unwrapped.equals(eventId);
}

@Override
public void setFlushable(final @NotNull SentryId eventId) {
flushableEventId.set(eventId);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package io.sentry.hints;

import io.sentry.protocol.SentryId;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public interface DiskFlushNotification {
void markFlushed();

boolean isFlushable(@Nullable SentryId eventId);

void setFlushable(@NotNull SentryId eventId);
}
12 changes: 10 additions & 2 deletions sentry/src/main/java/io/sentry/transport/AsyncHttpTransport.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,8 +244,16 @@ public void run() {
hint,
DiskFlushNotification.class,
(diskFlushNotification) -> {
diskFlushNotification.markFlushed();
options.getLogger().log(SentryLevel.DEBUG, "Disk flush envelope fired");
if (diskFlushNotification.isFlushable(envelope.getHeader().getEventId())) {
diskFlushNotification.markFlushed();
options.getLogger().log(SentryLevel.DEBUG, "Disk flush envelope fired");
} else {
options
.getLogger()
.log(
SentryLevel.DEBUG,
"Not firing envelope flush as there's an ongoing transaction");
}
});

if (transportGate.isConnected()) {
Expand Down
46 changes: 45 additions & 1 deletion sentry/src/test/java/io/sentry/SentryClientTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.sentry.hints.AbnormalExit
import io.sentry.hints.ApplyScopeData
import io.sentry.hints.Backfillable
import io.sentry.hints.Cached
import io.sentry.hints.DiskFlushNotification
import io.sentry.hints.TransactionEnd
import io.sentry.protocol.Contexts
import io.sentry.protocol.Mechanism
Expand Down Expand Up @@ -2170,7 +2171,50 @@ class SentryClientTest {

sut.captureEvent(SentryEvent(), scope, transactionEndHint)

verify(transaction).forceFinish(SpanStatus.ABORTED, false)
verify(transaction).forceFinish(SpanStatus.ABORTED, false, null)
verify(fixture.transport).send(
check {
assertEquals(1, it.items.count())
},
any()
)
}

@Test
fun `when event has DiskFlushNotification, TransactionEnds set transaction id as flushable`() {
val sut = fixture.getSut()

// build up a running transaction
val spanContext = SpanContext("op.load")
val transaction = mock<ITransaction>()
whenever(transaction.name).thenReturn("transaction")
whenever(transaction.eventId).thenReturn(SentryId())
whenever(transaction.spanContext).thenReturn(spanContext)

// scope
val scope = mock<Scope>()
whenever(scope.transaction).thenReturn(transaction)
whenever(scope.breadcrumbs).thenReturn(LinkedList<Breadcrumb>())
whenever(scope.extras).thenReturn(emptyMap())
whenever(scope.contexts).thenReturn(Contexts())
val scopePropagationContext = PropagationContext()
whenever(scope.propagationContext).thenReturn(scopePropagationContext)
doAnswer { (it.arguments[0] as IWithPropagationContext).accept(scopePropagationContext); scopePropagationContext }.whenever(scope).withPropagationContext(any())

var capturedEventId: SentryId? = null
val transactionEnd = object : TransactionEnd, DiskFlushNotification {
override fun markFlushed() {}
override fun isFlushable(eventId: SentryId?): Boolean = true
override fun setFlushable(eventId: SentryId) {
capturedEventId = eventId
}
}
val transactionEndHint = HintUtils.createWithTypeCheckHint(transactionEnd)

sut.captureEvent(SentryEvent(), scope, transactionEndHint)

assertEquals(transaction.eventId, capturedEventId)
verify(transaction).forceFinish(SpanStatus.ABORTED, false, transactionEndHint)
verify(fixture.transport).send(
check {
assertEquals(1, it.items.count())
Expand Down
Loading

0 comments on commit 932b404

Please sign in to comment.