Skip to content
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Features

- Continuous Profiling - stop when app goes in background ([#4311](https://github.com/getsentry/sentry-java/pull/4311))
- Continuous Profiling - Add delayed stop ([#4293](https://github.com/getsentry/sentry-java/pull/4293))
- Continuous Profiling - Out of Experimental ([#4310](https://github.com/getsentry/sentry-java/pull/4310))

Expand Down
2 changes: 1 addition & 1 deletion sentry-android-core/api/sentry-android-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public final class io/sentry/android/core/ActivityLifecycleIntegration : android

public class io/sentry/android/core/AndroidContinuousProfiler : io/sentry/IContinuousProfiler, io/sentry/transport/RateLimiter$IRateLimitObserver {
public fun <init> (Lio/sentry/android/core/BuildInfoProvider;Lio/sentry/android/core/internal/util/SentryFrameMetricsCollector;Lio/sentry/ILogger;Ljava/lang/String;ILio/sentry/ISentryExecutorService;)V
public fun close ()V
public fun close (Z)V
public fun getProfilerId ()Lio/sentry/protocol/SentryId;
public fun getRootSpanCounter ()I
public fun isRunning ()Z
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,15 @@ public void reevaluateSampling() {
shouldSample = true;
}

public void close() {
@Override
public void close(final boolean isTerminating) {
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
rootSpanCounter = 0;
shouldStop = true;
stop(false);
isClosed.set(true);
if (isTerminating) {
stop(false);
isClosed.set(true);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ private static void setupProfiler(
// This is a safeguard, but it should never happen, as the app start profiler should be the
// continuous one.
if (appStartContinuousProfiler != null) {
appStartContinuousProfiler.close();
appStartContinuousProfiler.close(true);
}
if (appStartTransactionProfiler != null) {
options.setTransactionProfiler(appStartTransactionProfiler);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public void run() {
scopes.endSession();
}
scopes.getOptions().getReplayController().stop();
scopes.getOptions().getContinuousProfiler().close(false);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void shutdown() {
final @Nullable IContinuousProfiler appStartContinuousProfiler =
AppStartMetrics.getInstance().getAppStartContinuousProfiler();
if (appStartContinuousProfiler != null) {
appStartContinuousProfiler.close();
appStartContinuousProfiler.close(true);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public void clear() {
}
appStartProfiler = null;
if (appStartContinuousProfiler != null) {
appStartContinuousProfiler.close();
appStartContinuousProfiler.close(true);
}
appStartContinuousProfiler = null;
appStartSamplingDecision = null;
Expand Down Expand Up @@ -333,7 +333,7 @@ private void checkCreateTimeOnMain() {
appStartProfiler = null;
}
if (appStartContinuousProfiler != null && appStartContinuousProfiler.isRunning()) {
appStartContinuousProfiler.close();
appStartContinuousProfiler.close(true);
appStartContinuousProfiler = null;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class AndroidContinuousProfilerTest {
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
assertTrue(profiler.isRunning)

profiler.close()
profiler.close(true)
assertFalse(profiler.isRunning)

// The timeout scheduled job should be cleared
Expand Down Expand Up @@ -470,14 +470,31 @@ class AndroidContinuousProfilerTest {
verify(fixture.scopes).captureProfileChunk(any())
}

@Test
fun `close without terminating stops all profiles after chunk is finished`() {
val profiler = fixture.getSut()
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
profiler.startProfiler(ProfileLifecycle.TRACE, fixture.mockTracesSampler)
assertTrue(profiler.isRunning)
// We are scheduling the profiler to stop at the end of the chunk, so it should still be running
profiler.close(false)
assertTrue(profiler.isRunning)
// However, close() already resets the rootSpanCounter
assertEquals(0, profiler.rootSpanCounter)

// We run the executor service to trigger the chunk finish, and the profiler shouldn't restart
fixture.executor.runAll()
assertFalse(profiler.isRunning)
}

@Test
fun `profiler does not send chunks after close`() {
val profiler = fixture.getSut()
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
assertTrue(profiler.isRunning)

// We close the profiler, which should prevent sending additional chunks
profiler.close()
profiler.close(true)

// The executor used to send the chunk doesn't do anything
fixture.executor.runAll()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ class AndroidOptionsInitializerTest {
assertEquals(fixture.sentryOptions.continuousProfiler, NoOpContinuousProfiler.getInstance())

// app start profiler is closed, because it will never be used
verify(appStartContinuousProfiler).close()
verify(appStartContinuousProfiler).close(eq(true))

// AppStartMetrics should be cleared
assertNull(AppStartMetrics.getInstance().appStartProfiler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.sentry.android.core
import androidx.lifecycle.LifecycleOwner
import io.sentry.Breadcrumb
import io.sentry.DateUtils
import io.sentry.IContinuousProfiler
import io.sentry.IScope
import io.sentry.IScopes
import io.sentry.ReplayController
Expand All @@ -15,6 +16,7 @@ import io.sentry.transport.ICurrentDateProvider
import org.mockito.ArgumentCaptor
import org.mockito.kotlin.any
import org.mockito.kotlin.check
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.timeout
Expand All @@ -38,6 +40,7 @@ class LifecycleWatcherTest {
val dateProvider = mock<ICurrentDateProvider>()
val options = SentryOptions()
val replayController = mock<ReplayController>()
val continuousProfiler = mock<IContinuousProfiler>()

fun getSUT(
sessionIntervalMillis: Long = 0L,
Expand All @@ -52,6 +55,7 @@ class LifecycleWatcherTest {
argumentCaptor.value.run(scope)
}
options.setReplayController(replayController)
options.setContinuousProfiler(continuousProfiler)
whenever(scopes.options).thenReturn(options)

return LifecycleWatcher(
Expand Down Expand Up @@ -106,6 +110,7 @@ class LifecycleWatcherTest {
watcher.onStop(fixture.ownerMock)
verify(fixture.scopes, timeout(10000)).endSession()
verify(fixture.replayController, timeout(10000)).stop()
verify(fixture.continuousProfiler, timeout(10000)).close(eq(false))
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import io.sentry.android.core.SentryAndroidOptions
import io.sentry.android.core.SentryShadowProcess
import org.junit.Before
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
Expand Down Expand Up @@ -273,7 +274,7 @@ class AppStartMetricsTest {
// Job on main thread checks if activity was launched
Shadows.shadowOf(Looper.getMainLooper()).idle()

verify(profiler).close()
verify(profiler).close(eq(true))
}

@Test
Expand Down Expand Up @@ -301,7 +302,7 @@ class AppStartMetricsTest {
// Job on main thread checks if activity was launched
Shadows.shadowOf(Looper.getMainLooper()).idle()

verify(profiler, never()).close()
verify(profiler, never()).close(any())
}

@Test
Expand Down
4 changes: 2 additions & 2 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -747,7 +747,7 @@ public abstract interface class io/sentry/IConnectionStatusProvider$IConnectionS
}

public abstract interface class io/sentry/IContinuousProfiler {
public abstract fun close ()V
public abstract fun close (Z)V
public abstract fun getProfilerId ()Lio/sentry/protocol/SentryId;
public abstract fun isRunning ()Z
public abstract fun reevaluateSampling ()V
Expand Down Expand Up @@ -1439,7 +1439,7 @@ public final class io/sentry/NoOpConnectionStatusProvider : io/sentry/IConnectio
}

public final class io/sentry/NoOpContinuousProfiler : io/sentry/IContinuousProfiler {
public fun close ()V
public fun close (Z)V
public static fun getInstance ()Lio/sentry/NoOpContinuousProfiler;
public fun getProfilerId ()Lio/sentry/protocol/SentryId;
public fun isRunning ()Z
Expand Down
8 changes: 6 additions & 2 deletions sentry/src/main/java/io/sentry/IContinuousProfiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ void startProfiler(

void stopProfiler(final @NotNull ProfileLifecycle profileLifecycle);

/** Cancel the profiler and stops it. Used on SDK close. */
void close();
/**
* Cancel the profiler and stops it.
*
* @param isTerminating whether the profiler is terminating and won't be restarted or not.
*/
void close(final boolean isTerminating);

void reevaluateSampling();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void startProfiler(
final @NotNull TracesSampler tracesSampler) {}

@Override
public void close() {}
public void close(final boolean isTerminating) {}

@Override
public void reevaluateSampling() {}
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/main/java/io/sentry/Scopes.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ public void close(final boolean isRestarting) {
configureScope(ScopeType.ISOLATION, scope -> scope.clear());
getOptions().getBackpressureMonitor().close();
getOptions().getTransactionProfiler().close();
getOptions().getContinuousProfiler().close();
getOptions().getContinuousProfiler().close(true);
getOptions().getCompositePerformanceCollector().close();
final @NotNull ISentryExecutorService executorService = getOptions().getExecutorService();
if (isRestarting) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class NoOpContinuousProfilerTest {

@Test
fun `close does not throw`() =
profiler.close()
profiler.close(true)

@Test
fun `getProfilerId returns Empty SentryId`() {
Expand Down
2 changes: 1 addition & 1 deletion sentry/src/test/java/io/sentry/ScopesTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1826,7 +1826,7 @@ class ScopesTest {
verify(backpressureMonitorMock).close()
verify(executor).close(any())
verify(profiler).close()
verify(continuousProfiler).close()
verify(continuousProfiler).close(eq(true))
verify(performanceCollector).close()
}

Expand Down
Loading