Skip to content

Conversation

@lbloder
Copy link
Collaborator

@lbloder lbloder commented Oct 20, 2025

📜 Description

Add @Configuration classes to initialize the profiler when running in OTEL Agent auto-init mode.

💡 Motivation and Context

Fixes #4855

💚 How did you test it?

📝 Checklist

  • I added GH Issue ID & Linear ID
  • I added tests to verify the changes.
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled.
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • Review from the native team if needed.
  • No breaking change or entry added to the changelog.
  • No breaking change for hybrid SDKs or communicated to hybrid SDKs.

🔮 Next steps

…options, add configuration class to load the profiler and converter after spring boot starts in agent mode
import org.springframework.context.annotation.Import;

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = {"io.sentry.opentelemetry.agent.AgentMarker"})
Copy link
Collaborator Author

@lbloder lbloder Oct 20, 2025

Choose a reason for hiding this comment

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

Make it conditional on the async profiler class too?

Copy link
Member

Choose a reason for hiding this comment

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

Sounds good, I see no reason to run this if profiler isn't there.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 20, 2025

Performance metrics 🚀

  Plain With Sentry Diff
Startup time 388.73 ms 462.98 ms 74.24 ms
Size 1.58 MiB 2.12 MiB 552.68 KiB

Baseline results on branch: main

Startup times

Revision Plain With Sentry Diff
2124a46 319.19 ms 415.04 ms 95.85 ms
b3d8889 420.46 ms 453.71 ms 33.26 ms
d217708 409.83 ms 474.72 ms 64.89 ms
3d205d0 352.15 ms 432.53 ms 80.38 ms
fcec2f2 357.47 ms 447.32 ms 89.85 ms
889ecea 367.58 ms 437.52 ms 69.94 ms
1df7eb6 397.04 ms 429.64 ms 32.60 ms
ce0a49e 532.00 ms 609.96 ms 77.96 ms
ee747ae 357.79 ms 421.84 ms 64.05 ms
b750b96 408.98 ms 480.32 ms 71.34 ms

App size

Revision Plain With Sentry Diff
2124a46 1.58 MiB 2.12 MiB 551.51 KiB
b3d8889 1.58 MiB 2.10 MiB 535.07 KiB
d217708 1.58 MiB 2.10 MiB 532.97 KiB
3d205d0 1.58 MiB 2.10 MiB 532.97 KiB
fcec2f2 1.58 MiB 2.12 MiB 551.50 KiB
889ecea 1.58 MiB 2.11 MiB 539.75 KiB
1df7eb6 1.58 MiB 2.10 MiB 532.97 KiB
ce0a49e 1.58 MiB 2.10 MiB 532.94 KiB
ee747ae 1.58 MiB 2.10 MiB 530.95 KiB
b750b96 1.58 MiB 2.10 MiB 533.19 KiB

Previous results on branch: feat/profiling-w-spring-otel-agent

Startup times

Revision Plain With Sentry Diff
2b6b804 312.35 ms 370.80 ms 58.45 ms
913e482 313.91 ms 378.00 ms 64.09 ms
30b9948 314.20 ms 354.71 ms 40.51 ms
db75a56 331.37 ms 402.82 ms 71.45 ms
3832729 297.73 ms 353.21 ms 55.48 ms
b59fc8e 399.24 ms 444.62 ms 45.38 ms
d76029f 339.65 ms 357.82 ms 18.17 ms
c4729d6 315.52 ms 362.84 ms 47.32 ms
c773a3a 406.73 ms 491.63 ms 84.90 ms

App size

Revision Plain With Sentry Diff
2b6b804 1.58 MiB 2.12 MiB 551.86 KiB
913e482 1.58 MiB 2.12 MiB 552.67 KiB
30b9948 1.58 MiB 2.12 MiB 551.90 KiB
db75a56 1.58 MiB 2.12 MiB 551.94 KiB
3832729 1.58 MiB 2.12 MiB 551.94 KiB
b59fc8e 1.58 MiB 2.11 MiB 539.90 KiB
d76029f 1.58 MiB 2.12 MiB 549.52 KiB
c4729d6 1.58 MiB 2.12 MiB 548.31 KiB
c773a3a 1.58 MiB 2.12 MiB 549.51 KiB


@Bean
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConfiguration")
public IContinuousProfiler sentryOpenTelemetryProfilerConfiguration() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Extract init into util to streamline initialization code


@Bean
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConverterConfiguration")
public IProfileConverter sentryOpenTelemetryProfilerConverterConfiguration() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Extract init into util to streamline initialization code

@lbloder
Copy link
Collaborator Author

lbloder commented Nov 3, 2025

@sentry review

@lbloder
Copy link
Collaborator Author

lbloder commented Nov 3, 2025

@cursor review

@lbloder lbloder mentioned this pull request Nov 3, 2025
16 tasks
cursor[bot]

This comment was marked as outdated.

@lbloder lbloder marked this pull request as ready for review November 3, 2025 13:29
cursor[bot]

This comment was marked as outdated.

}

@Test
fun `initialize converter returns no-op converter if converter already initialized`() {
Copy link
Member

Choose a reason for hiding this comment

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

m should it simply return the existing one instead of noop that potentially causes profiling to break?


@Bean
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConfiguration")
public IContinuousProfiler sentryOpenTelemetryProfilerConfiguration() {
Copy link
Member

Choose a reason for hiding this comment

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

Is there an expected order to these bean evaluations?

contextRunner
.withPropertyValues(
"sentry.dsn=http://key@localhost/proj",
"sentry.traces-sample-rate=1.0",
Copy link
Member

Choose a reason for hiding this comment

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

Should this also have "sentry.profile-session-sample-rate=1.0",?

"debug=true",
)
.run {
assertThat(it).hasSingleBean(IContinuousProfiler::class.java)
Copy link
Member

Choose a reason for hiding this comment

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

Is this currently simply asserting it has noop instances?

import org.springframework.context.annotation.Import;

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = {"io.sentry.opentelemetry.agent.AgentMarker"})
Copy link
Member

Choose a reason for hiding this comment

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

Sounds good, I see no reason to run this if profiler isn't there.

return previousOptions.getInitPriority().ordinal() <= newOptions.getInitPriority().ordinal();
}

public static IContinuousProfiler initializeProfiler(@NotNull SentryOptions options) {
Copy link
Member

Choose a reason for hiding this comment

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

m should we instead check if options already have a profiler / converter set (that's not noop) and return that?
IMO that makes it easier to reason about SDK init.
Looking at the tests it seems we're potentially replacing a working profiler / converter with noop (if misusing this util).

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

assertThat(it).hasSingleBean(IContinuousProfiler::class.java)
assertThat(it).hasSingleBean(IProfileConverter::class.java)
}
}
Copy link

Choose a reason for hiding this comment

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

Bug: Continuous Profiling Test Lacks Required Sample Rate

The test "when AgentMarker is on the classpath and ContinuousProfiling is enabled..." doesn't actually enable continuous profiling. It's missing the sentry.profile-session-sample-rate=1.0 property, which results in NoOp profiler beans being created instead of functional ones. This makes the test misleading about verifying actual continuous profiling setup, especially since the companion test correctly includes this property.

Additional Locations (2)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Profiler is not initialized when using spring-boot or spring with OTEL Agent

4 participants