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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Features

- Continuous Profiling - Out of Experimental ([#4310](https://github.com/getsentry/sentry-java/pull/4310))

## 8.6.0

### Behavioral Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ static void applyMetadata(
final double profileSessionSampleRate =
readDouble(metadata, logger, PROFILE_SESSION_SAMPLE_RATE);
if (profileSessionSampleRate != -1) {
options.getExperimental().setProfileSessionSampleRate(profileSessionSampleRate);
options.setProfileSessionSampleRate(profileSessionSampleRate);
}
}

Expand All @@ -346,20 +346,16 @@ static void applyMetadata(
PROFILE_LIFECYCLE,
options.getProfileLifecycle().name().toLowerCase(Locale.ROOT));
if (profileLifecycle != null) {
options
.getExperimental()
.setProfileLifecycle(
ProfileLifecycle.valueOf(profileLifecycle.toUpperCase(Locale.ROOT)));
options.setProfileLifecycle(
ProfileLifecycle.valueOf(profileLifecycle.toUpperCase(Locale.ROOT)));
}

options
.getExperimental()
.setStartProfilerOnAppStart(
readBool(
metadata,
logger,
PROFILER_START_ON_APP_START,
options.isStartProfilerOnAppStart()));
options.setStartProfilerOnAppStart(
readBool(
metadata,
logger,
PROFILER_START_ON_APP_START,
options.isStartProfilerOnAppStart()));

options.setEnableUserInteractionTracing(
readBool(metadata, logger, TRACES_UI_ENABLE, options.isEnableUserInteractionTracing()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,8 @@ private void createAndStartContinuousProfiler(
logger.log(SentryLevel.DEBUG, "App start continuous profiling started.");
SentryOptions sentryOptions = SentryOptions.empty();
// Let's fake a sampler to accept the sampling decision that was calculated on last run
sentryOptions
.getExperimental()
.setProfileSessionSampleRate(profilingOptions.isContinuousProfileSampled() ? 1.0 : 0.0);
sentryOptions.setProfileSessionSampleRate(
profilingOptions.isContinuousProfileSampled() ? 1.0 : 0.0);
appStartContinuousProfiler.startProfiler(
profilingOptions.getProfileLifecycle(), new TracesSampler(sentryOptions));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,7 +826,7 @@ class ManifestMetadataReaderTest {
fun `applyMetadata does not override profileSessionSampleRate from options`() {
// Arrange
val expectedSampleRate = 0.99f
fixture.options.experimental.profileSessionSampleRate = expectedSampleRate.toDouble()
fixture.options.profileSessionSampleRate = expectedSampleRate.toDouble()
val bundle = bundleOf(ManifestMetadataReader.PROFILE_SESSION_SAMPLE_RATE to 0.1f)
val context = fixture.getContext(metaData = bundle)

Expand Down
9 changes: 3 additions & 6 deletions sentry/api/sentry.api
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,6 @@ public abstract interface class io/sentry/EventProcessor {

public final class io/sentry/ExperimentalOptions {
public fun <init> (ZLio/sentry/protocol/SdkVersion;)V
public fun getProfileLifecycle ()Lio/sentry/ProfileLifecycle;
public fun getProfileSessionSampleRate ()Ljava/lang/Double;
public fun isStartProfilerOnAppStart ()Z
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
public fun setStartProfilerOnAppStart (Z)V
}

public final class io/sentry/ExternalOptions {
Expand Down Expand Up @@ -3222,6 +3216,8 @@ public class io/sentry/SentryOptions {
public fun setModulesLoader (Lio/sentry/internal/modules/IModulesLoader;)V
public fun setOpenTelemetryMode (Lio/sentry/SentryOpenTelemetryMode;)V
public fun setPrintUncaughtStackTrace (Z)V
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
public fun setProfilesSampleRate (Ljava/lang/Double;)V
public fun setProfilesSampler (Lio/sentry/SentryOptions$ProfilesSamplerCallback;)V
public fun setProfilingTracesHz (I)V
Expand All @@ -3245,6 +3241,7 @@ public class io/sentry/SentryOptions {
public fun setSpanFactory (Lio/sentry/ISpanFactory;)V
public fun setSpotlightConnectionUrl (Ljava/lang/String;)V
public fun setSslSocketFactory (Ljavax/net/ssl/SSLSocketFactory;)V
public fun setStartProfilerOnAppStart (Z)V
public fun setTag (Ljava/lang/String;Ljava/lang/String;)V
public fun setThreadChecker (Lio/sentry/util/thread/IThreadChecker;)V
public fun setTraceOptionsRequests (Z)V
Expand Down
72 changes: 0 additions & 72 deletions sentry/src/main/java/io/sentry/ExperimentalOptions.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package io.sentry;

import io.sentry.protocol.SdkVersion;
import io.sentry.util.SampleRateUtils;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
Expand All @@ -14,74 +11,5 @@
*/
public final class ExperimentalOptions {

/**
* Indicates the percentage in which the profiles for the session will be created. Specifying 0
* means never, 1.0 means always. The value needs to be >= 0.0 and <= 1.0 The default is null
* (disabled).
*/
private @Nullable Double profileSessionSampleRate;

/**
* Whether the profiling lifecycle is controlled manually or based on the trace lifecycle.
* Defaults to {@link ProfileLifecycle#MANUAL}.
*/
private @NotNull ProfileLifecycle profileLifecycle = ProfileLifecycle.MANUAL;

/**
* Whether profiling can automatically be started as early as possible during the app lifecycle,
* to capture more of app startup. If {@link ExperimentalOptions#profileLifecycle} is {@link
* ProfileLifecycle#MANUAL} Profiling is started automatically on startup and stopProfiler must be
* called manually whenever the app startup is completed If {@link
* ExperimentalOptions#profileLifecycle} is {@link ProfileLifecycle#TRACE} Profiling is started
* automatically on startup, and will automatically be stopped when the root span that is
* associated with app startup ends
*/
private boolean startProfilerOnAppStart = false;

public ExperimentalOptions(final boolean empty, final @Nullable SdkVersion sdkVersion) {}

/**
* Returns whether the profiling cycle is controlled manually or based on the trace lifecycle.
* Defaults to {@link ProfileLifecycle#MANUAL}.
*
* @return the profile lifecycle
*/
@ApiStatus.Experimental
public @NotNull ProfileLifecycle getProfileLifecycle() {
return profileLifecycle;
}

/** Sets the profiling lifecycle. */
@ApiStatus.Experimental
public void setProfileLifecycle(final @NotNull ProfileLifecycle profileLifecycle) {
// TODO (when moved to SentryOptions): we should log a message if the user sets this to TRACE
// and tracing is disabled
this.profileLifecycle = profileLifecycle;
}

@ApiStatus.Experimental
public @Nullable Double getProfileSessionSampleRate() {
return profileSessionSampleRate;
}

@ApiStatus.Experimental
public void setProfileSessionSampleRate(final @Nullable Double profileSessionSampleRate) {
if (!SampleRateUtils.isValidContinuousProfilesSampleRate(profileSessionSampleRate)) {
throw new IllegalArgumentException(
"The value "
+ profileSessionSampleRate
+ " is not valid. Use values between 0.0 and 1.0.");
}
this.profileSessionSampleRate = profileSessionSampleRate;
}

@ApiStatus.Experimental
public boolean isStartProfilerOnAppStart() {
return startProfilerOnAppStart;
}

@ApiStatus.Experimental
public void setStartProfilerOnAppStart(boolean startProfilerOnAppStart) {
this.startProfilerOnAppStart = startProfilerOnAppStart;
}
}
72 changes: 62 additions & 10 deletions sentry/src/main/java/io/sentry/SentryOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,30 @@ public class SentryOptions {
@ApiStatus.Experimental private boolean captureOpenTelemetryEvents = false;

private @NotNull IVersionDetector versionDetector = NoopVersionDetector.getInstance();

/**
* Indicates the percentage in which the profiles for the session will be created. Specifying 0
* means never, 1.0 means always. The value needs to be >= 0.0 and <= 1.0 The default is null
* (disabled).
*/
private @Nullable Double profileSessionSampleRate;

/**
* Whether the profiling lifecycle is controlled manually or based on the trace lifecycle.
* Defaults to {@link ProfileLifecycle#MANUAL}.
*/
private @NotNull ProfileLifecycle profileLifecycle = ProfileLifecycle.MANUAL;

/**
* Whether profiling can automatically be started as early as possible during the app lifecycle,
* to capture more of app startup. If {@link SentryOptions#profileLifecycle} is {@link
* ProfileLifecycle#MANUAL} Profiling is started automatically on startup and stopProfiler must be
* called manually whenever the app startup is completed If {@link SentryOptions#profileLifecycle}
* is {@link ProfileLifecycle#TRACE} Profiling is started automatically on startup, and will
* automatically be stopped when the root span that is associated with app startup ends
*/
private boolean startProfilerOnAppStart = false;

/**
* Adds an event processor
*
Expand Down Expand Up @@ -1821,7 +1845,6 @@ public void setTransactionProfiler(final @Nullable ITransactionProfiler transact
*
* @return the continuous profiler.
*/
@ApiStatus.Experimental
public @NotNull IContinuousProfiler getContinuousProfiler() {
return continuousProfiler;
}
Expand All @@ -1831,7 +1854,6 @@ public void setTransactionProfiler(final @Nullable ITransactionProfiler transact
*
* @param continuousProfiler - the continuous profiler
*/
@ApiStatus.Experimental
public void setContinuousProfiler(final @Nullable IContinuousProfiler continuousProfiler) {
// We allow to set the profiler only if it was not set before, and we don't allow to unset it.
if (this.continuousProfiler == NoOpContinuousProfiler.getInstance()
Expand Down Expand Up @@ -1859,8 +1881,8 @@ public boolean isProfilingEnabled() {
public boolean isContinuousProfilingEnabled() {
return profilesSampleRate == null
&& profilesSampler == null
&& experimental.getProfileSessionSampleRate() != null
&& experimental.getProfileSessionSampleRate() > 0;
&& profileSessionSampleRate != null
&& profileSessionSampleRate > 0;
}

/**
Expand Down Expand Up @@ -1914,9 +1936,23 @@ public void setProfilesSampleRate(final @Nullable Double profilesSampleRate) {
*
* @return the sample rate
*/
@ApiStatus.Experimental
public @Nullable Double getProfileSessionSampleRate() {
return experimental.getProfileSessionSampleRate();
return profileSessionSampleRate;
}

/**
* Set the session sample rate. Default is null (disabled). ProfilesSampleRate takes precedence
* over this. To enable continuous profiling, don't set profilesSampleRate or profilesSampler, or
* set them to null.
*/
public void setProfileSessionSampleRate(final @Nullable Double profileSessionSampleRate) {
if (!SampleRateUtils.isValidContinuousProfilesSampleRate(profileSessionSampleRate)) {
throw new IllegalArgumentException(
"The value "
+ profileSessionSampleRate
+ " is not valid. Use values between 0.0 and 1.0.");
}
this.profileSessionSampleRate = profileSessionSampleRate;
}

/**
Expand All @@ -1925,17 +1961,33 @@ public void setProfilesSampleRate(final @Nullable Double profilesSampleRate) {
*
* @return the profile lifecycle
*/
@ApiStatus.Experimental
public @NotNull ProfileLifecycle getProfileLifecycle() {
return experimental.getProfileLifecycle();
return profileLifecycle;
}

/** Sets the profiling lifecycle. */
public void setProfileLifecycle(final @NotNull ProfileLifecycle profileLifecycle) {
this.profileLifecycle = profileLifecycle;
if (profileLifecycle == ProfileLifecycle.TRACE && !isTracingEnabled()) {
logger.log(
SentryLevel.WARNING,
"Profiling lifecycle is set to TRACE but tracing is disabled. "
+ "Profiling will not be started automatically.");
}
}

/**
* Whether profiling can automatically be started as early as possible during the app lifecycle.
*/
@ApiStatus.Experimental
public boolean isStartProfilerOnAppStart() {
return experimental.isStartProfilerOnAppStart();
return startProfilerOnAppStart;
}

/**
* Set if profiling can automatically be started as early as possible during the app lifecycle.
*/
public void setStartProfilerOnAppStart(final boolean startProfilerOnAppStart) {
this.startProfilerOnAppStart = startProfilerOnAppStart;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions sentry/src/test/java/io/sentry/ScopeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ class ScopeTest {
val options = SentryOptions().apply {
release = "0.0.1"
setContinuousProfiler(profiler)
experimental.profileSessionSampleRate = 1.0
profileSessionSampleRate = 1.0
}

val scope = Scope(options)
Expand All @@ -419,7 +419,7 @@ class ScopeTest {
val options = SentryOptions().apply {
release = "0.0.1"
setContinuousProfiler(profiler)
experimental.profileSessionSampleRate = 1.0
profileSessionSampleRate = 1.0
}

val scope = Scope(options)
Expand All @@ -435,7 +435,7 @@ class ScopeTest {
val options = SentryOptions().apply {
release = "0.0.1"
setContinuousProfiler(profiler)
experimental.profileSessionSampleRate = 1.0
profileSessionSampleRate = 1.0
}

val scope = Scope(options)
Expand Down
Loading
Loading