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 @@ -5,6 +5,7 @@
### Performance

- Remove an unused lock from `SentryPerformanceProvider`, which was allocated on every cold start in `ContentProvider.onCreate` without ever being acquired ([#5871](https://github.com/getsentry/sentry-java/pull/5871))
- Parse the app start profiling config with only the deserializer it needs instead of building a full `JsonSerializer` and `SentryOptions`, cutting 188 of 221 allocations on the main thread before `Application.onCreate` ([#5867](https://github.com/getsentry/sentry-java/pull/5867))

## 8.51.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
import io.sentry.ILogger;
import io.sentry.ISentryLifecycleToken;
import io.sentry.ITransactionProfiler;
import io.sentry.JsonSerializer;
import io.sentry.JsonObjectReader;
import io.sentry.SentryAppStartProfilingOptions;
import io.sentry.SentryExecutorService;
import io.sentry.SentryLevel;
Expand Down Expand Up @@ -117,8 +117,7 @@ private void launchAppStartProfiler(final @NotNull AppStartMetrics appStartMetri
try (final @NotNull Reader reader =
new BufferedReader(new InputStreamReader(new FileInputStream(configFile)))) {
final @Nullable SentryAppStartProfilingOptions profilingOptions =
new JsonSerializer(SentryOptions.empty())
.deserialize(reader, SentryAppStartProfilingOptions.class);
deserializeProfilingConfig(reader);

if (profilingOptions == null) {
logger.log(
Expand Down Expand Up @@ -166,6 +165,25 @@ private void launchAppStartProfiler(final @NotNull AppStartMetrics appStartMetri
}
}

/**
* Parses the app start profiling config with only the deserializer it needs. Going through {@link
* io.sentry.JsonSerializer} would allocate a full {@link SentryOptions} plus every registered
* deserializer on the main thread before {@code Application.onCreate}, to use exactly one of
* them.
*
* <p>Returns null on malformed input, matching what {@code JsonSerializer.deserialize} did, so
* callers keep reporting it as a deserialization failure rather than a read error.
*/
private @Nullable SentryAppStartProfilingOptions deserializeProfilingConfig(
final @NotNull Reader reader) {
try (final @NotNull JsonObjectReader jsonReader = new JsonObjectReader(reader)) {
return new SentryAppStartProfilingOptions.Deserializer().deserialize(jsonReader, logger);
} catch (Exception e) {
logger.log(SentryLevel.ERROR, "Error when deserializing", e);
return null;
}
}

private void createAndStartContinuousProfiler(
final @NotNull Context context,
final @NotNull SentryAppStartProfilingOptions profilingOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,21 @@ class SentryPerformanceProviderTest {
)
}

@Test
fun `when config file is malformed, profiler is not started`() {
fixture.getSut { config -> config.writeText("{\"profile_sampled\": tru") }
assertNull(AppStartMetrics.getInstance().appStartProfiler)
assertNull(AppStartMetrics.getInstance().appStartContinuousProfiler)
verify(fixture.logger).log(eq(SentryLevel.ERROR), eq("Error when deserializing"), any())
verify(fixture.logger)
.log(
eq(SentryLevel.WARNING),
eq(
"Unable to deserialize the SentryAppStartProfilingOptions. App start profiling will not start."
),
)
}

@Test
fun `when profiling is disabled, profiler is not started`() {
fixture.getSut { config ->
Expand Down
Loading