Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,12 @@ public final class io/sentry/HubScopesWrapper : io/sentry/IHub {
public fun withScope (Lio/sentry/ScopeCallback;)V
}

public abstract interface class io/sentry/IAppStartExtender {
public abstract fun extendAppStart ()V
public abstract fun finishAppStart ()V
public abstract fun getExtendedAppStartSpan ()Lio/sentry/ISpan;
}

public abstract interface class io/sentry/IConnectionStatusProvider : java/io/Closeable {
public abstract fun addConnectionStatusObserver (Lio/sentry/IConnectionStatusProvider$IConnectionStatusObserver;)Z
public abstract fun getConnectionStatus ()Lio/sentry/IConnectionStatusProvider$ConnectionStatus;
Expand Down Expand Up @@ -1543,6 +1549,13 @@ public final class io/sentry/MonitorScheduleUnit : java/lang/Enum {
public static fun values ()[Lio/sentry/MonitorScheduleUnit;
}

public final class io/sentry/NoOpAppStartExtender : io/sentry/IAppStartExtender {
public fun extendAppStart ()V
public fun finishAppStart ()V
public fun getExtendedAppStartSpan ()Lio/sentry/ISpan;
public static fun getInstance ()Lio/sentry/NoOpAppStartExtender;
}

public final class io/sentry/NoOpCompositePerformanceCollector : io/sentry/CompositePerformanceCollector {
public fun close ()V
public static fun getInstance ()Lio/sentry/NoOpCompositePerformanceCollector;
Expand Down Expand Up @@ -3603,6 +3616,7 @@ public class io/sentry/SentryOptions {
public fun addScopeObserver (Lio/sentry/IScopeObserver;)V
public static fun empty ()Lio/sentry/SentryOptions;
public fun findPersistingScopeObserver ()Lio/sentry/cache/PersistingScopeObserver;
public fun getAppStartExtender ()Lio/sentry/IAppStartExtender;
public fun getBackpressureMonitor ()Lio/sentry/backpressure/IBackpressureMonitor;
public fun getBeforeBreadcrumb ()Lio/sentry/SentryOptions$BeforeBreadcrumbCallback;
public fun getBeforeEnvelopeCallback ()Lio/sentry/SentryOptions$BeforeEnvelopeCallback;
Expand Down Expand Up @@ -3749,6 +3763,7 @@ public class io/sentry/SentryOptions {
public fun isTraceSampling ()Z
public fun isTracingEnabled ()Z
public fun merge (Lio/sentry/ExternalOptions;)V
public fun setAppStartExtender (Lio/sentry/IAppStartExtender;)V
public fun setAttachServerName (Z)V
public fun setAttachStacktrace (Z)V
public fun setAttachThreads (Z)V
Expand Down
34 changes: 34 additions & 0 deletions sentry/src/main/java/io/sentry/IAppStartExtender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.sentry;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

/**
* Bridges the {@code Sentry.extendAppStart()} / {@code Sentry.finishAppStart()} / {@code
* Sentry.getExtendedAppStartSpan()} static API to the Android implementation. The default
* implementation ({@link NoOpAppStartExtender}) does nothing, so the API is a no-op on platforms
* that don't provide an app start measurement.
*/
@ApiStatus.Internal
public interface IAppStartExtender {

/**
* Begins extending the app start. Intended to be called from {@code Application.onCreate} right
* after SDK init. No-ops if the app start already finished, none is in progress, or it was
* already extended (first call wins).
*/
void extendAppStart();

/**
* Finishes the extended app start, allowing the app start transaction to complete. No-ops if the
* app start was not extended or this was already called.
*/
void finishAppStart();

/**
* Returns the active extended app start span to attach child spans to, or a no-op span when no
* extension is active.
*/
@NotNull
ISpan getExtendedAppStartSpan();
}
27 changes: 27 additions & 0 deletions sentry/src/main/java/io/sentry/NoOpAppStartExtender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.sentry;

import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;

@ApiStatus.Internal
public final class NoOpAppStartExtender implements IAppStartExtender {
Comment thread
buenaflor marked this conversation as resolved.

private static final @NotNull NoOpAppStartExtender instance = new NoOpAppStartExtender();

private NoOpAppStartExtender() {}

public static @NotNull NoOpAppStartExtender getInstance() {
return instance;
}

@Override
public void extendAppStart() {}

@Override
public void finishAppStart() {}

@Override
public @NotNull ISpan getExtendedAppStartSpan() {
return NoOpSpan.getInstance();
}
}
18 changes: 18 additions & 0 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,9 @@ public class SentryOptions {
private @NotNull FullyDisplayedReporter fullyDisplayedReporter =
FullyDisplayedReporter.getInstance();

/** Bridges the app start extension API to the Android implementation. */
private @NotNull IAppStartExtender appStartExtender = NoOpAppStartExtender.getInstance();

private @NotNull IConnectionStatusProvider connectionStatusProvider =
new NoOpConnectionStatusProvider();

Expand Down Expand Up @@ -2653,6 +2656,21 @@ public void setFullyDisplayedReporter(
this.fullyDisplayedReporter = fullyDisplayedReporter;
}

/**
* Gets the app start extender, which bridges the app start extension API to its implementation.
*
* @return the app start extender.
*/
@ApiStatus.Internal
public @NotNull IAppStartExtender getAppStartExtender() {
return appStartExtender;
}

@ApiStatus.Internal
public void setAppStartExtender(final @NotNull IAppStartExtender appStartExtender) {
this.appStartExtender = appStartExtender;
}

/**
* Whether OPTIONS requests should be traced.
*
Expand Down
17 changes: 17 additions & 0 deletions sentry/src/test/java/io/sentry/NoOpAppStartExtenderTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.sentry

import kotlin.test.Test
import kotlin.test.assertSame

class NoOpAppStartExtenderTest {
private val extender = NoOpAppStartExtender.getInstance()

@Test fun `extendAppStart does not throw`() = extender.extendAppStart()

@Test fun `finishAppStart does not throw`() = extender.finishAppStart()

@Test
fun `getExtendedAppStartSpan returns NoOpSpan`() {
assertSame(NoOpSpan.getInstance(), extender.extendedAppStartSpan)
}
}
Comment on lines +6 to +17

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

following conventions of existing no-op class tests, lmk if we dont need this

20 changes: 20 additions & 0 deletions sentry/src/test/java/io/sentry/SentryOptionsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,26 @@ class SentryOptionsTest {
assertEquals(FullyDisplayedReporter.getInstance(), SentryOptions().fullyDisplayedReporter)
}

@Test
fun `when options are initialized, appStartExtender defaults to noop`() {
assertEquals(NoOpAppStartExtender.getInstance(), SentryOptions().appStartExtender)
}

@Test
fun `when appStartExtender is set, it's returned as well`() {
val options = SentryOptions()
val customExtender =
object : IAppStartExtender {
override fun extendAppStart() = Unit

override fun finishAppStart() = Unit

override fun getExtendedAppStartSpan(): ISpan = NoOpSpan.getInstance()
}
options.appStartExtender = customExtender
assertEquals(customExtender, options.appStartExtender)
}

@Test
fun `when options are initialized, connectionStatusProvider is not null and default to noop`() {
assertNotNull(SentryOptions().connectionStatusProvider)
Expand Down
Loading