Skip to content

Commit ca2e488

Browse files
committed
Merge branch 'main' into feat/profiling-remove-vendored-code
2 parents 5e7443c + 591b401 commit ca2e488

File tree

35 files changed

+861
-49
lines changed

35 files changed

+861
-49
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
- Only set `DefaultReplayBreadcrumbConverter` if replay is available ([#4888](https://github.com/getsentry/sentry-java/pull/4888))
1616
- Session Replay: Cache connection status instead of using blocking calls ([#4891](https://github.com/getsentry/sentry-java/pull/4891))
1717
- Fix log count in client reports ([#4869](https://github.com/getsentry/sentry-java/pull/4869))
18+
- Fix profilerId propagation ([#4833](https://github.com/getsentry/sentry-java/pull/4833))
19+
- Fix profiling init for Spring and Spring Boot w Agent auto-init ([#4815](https://github.com/getsentry/sentry-java/pull/4815))
1820

1921
### Improvements
2022

sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/provider/AsyncProfilerProfileConverterProvider.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import io.sentry.profiling.JavaProfileConverterProvider;
66
import org.jetbrains.annotations.ApiStatus;
77
import org.jetbrains.annotations.NotNull;
8-
import org.jetbrains.annotations.Nullable;
98

109
/**
1110
* AsyncProfiler implementation of {@link JavaProfileConverterProvider}. This provider integrates
@@ -15,7 +14,7 @@
1514
public final class AsyncProfilerProfileConverterProvider implements JavaProfileConverterProvider {
1615

1716
@Override
18-
public @Nullable IProfileConverter getProfileConverter() {
17+
public @NotNull IProfileConverter getProfileConverter() {
1918
return new AsyncProfilerProfileConverter();
2019
}
2120

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package io.sentry.asyncprofiler.init
2+
3+
import io.sentry.ILogger
4+
import io.sentry.ISentryExecutorService
5+
import io.sentry.NoOpContinuousProfiler
6+
import io.sentry.NoOpProfileConverter
7+
import io.sentry.SentryOptions
8+
import io.sentry.asyncprofiler.profiling.JavaContinuousProfiler
9+
import io.sentry.asyncprofiler.provider.AsyncProfilerProfileConverterProvider
10+
import io.sentry.util.InitUtil
11+
import kotlin.test.Test
12+
import kotlin.test.assertNotNull
13+
import kotlin.test.assertSame
14+
import org.mockito.kotlin.mock
15+
16+
class AsyncProfilerInitUtilTest {
17+
18+
@Test
19+
fun `initialize Profiler returns no-op profiler if profiling disabled`() {
20+
val options = SentryOptions()
21+
val profiler = InitUtil.initializeProfiler(options)
22+
assert(profiler is NoOpContinuousProfiler)
23+
}
24+
25+
@Test
26+
fun `initialize Converter returns no-op converter if profiling disabled`() {
27+
val options = SentryOptions()
28+
val converter = InitUtil.initializeProfileConverter(options)
29+
assert(converter is NoOpProfileConverter)
30+
}
31+
32+
@Test
33+
fun `initialize profiler returns the existing profiler from options if already initialized`() {
34+
val initialProfiler =
35+
JavaContinuousProfiler(mock<ILogger>(), "", 10, mock<ISentryExecutorService>())
36+
val options =
37+
SentryOptions().also {
38+
it.setProfileSessionSampleRate(1.0)
39+
it.setContinuousProfiler(initialProfiler)
40+
}
41+
42+
val profiler = InitUtil.initializeProfiler(options)
43+
assertSame(initialProfiler, profiler)
44+
}
45+
46+
@Test
47+
fun `initialize converter returns the existing converter from options if already initialized`() {
48+
val initialConverter = AsyncProfilerProfileConverterProvider.AsyncProfilerProfileConverter()
49+
val options =
50+
SentryOptions().also {
51+
it.setProfileSessionSampleRate(1.0)
52+
it.profilerConverter = initialConverter
53+
}
54+
55+
val converter = InitUtil.initializeProfileConverter(options)
56+
assertSame(initialConverter, converter)
57+
}
58+
59+
@Test
60+
fun `initialize Profiler returns JavaContinuousProfiler if profiling enabled but profiler not yet initialized`() {
61+
val options = SentryOptions().also { it.setProfileSessionSampleRate(1.0) }
62+
val profiler = InitUtil.initializeProfiler(options)
63+
assertSame(profiler, options.continuousProfiler)
64+
assert(profiler is JavaContinuousProfiler)
65+
}
66+
67+
@Test
68+
fun `initialize Converter returns AsyncProfilerProfileConverterProvider if profiling enabled but profiler not yet initialized`() {
69+
val options = SentryOptions().also { it.setProfileSessionSampleRate(1.0) }
70+
val converter = InitUtil.initializeProfileConverter(options)
71+
assertSame(converter, options.profilerConverter)
72+
assert(converter is AsyncProfilerProfileConverterProvider.AsyncProfilerProfileConverter)
73+
}
74+
75+
@Test
76+
fun `initialize profiler uses existing profilingTracesDirPath when set`() {
77+
val customPath = "/custom/path/to/traces"
78+
val options =
79+
SentryOptions().also {
80+
it.setProfileSessionSampleRate(1.0)
81+
it.profilingTracesDirPath = customPath
82+
}
83+
val profiler = InitUtil.initializeProfiler(options)
84+
assert(profiler is JavaContinuousProfiler)
85+
assertSame(customPath, options.profilingTracesDirPath)
86+
}
87+
88+
@Test
89+
fun `initialize profiler creates and sets profilingTracesDirPath when null`() {
90+
val options = SentryOptions().also { it.setProfileSessionSampleRate(1.0) }
91+
val profiler = InitUtil.initializeProfiler(options)
92+
assert(profiler is JavaContinuousProfiler)
93+
assertNotNull(options.profilingTracesDirPath)
94+
assert(options.profilingTracesDirPath!!.contains("sentry_profiling_traces"))
95+
}
96+
}

sentry-opentelemetry/sentry-opentelemetry-core/src/main/java/io/sentry/opentelemetry/SentrySpanExporter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ private void transferSpanDetails(
297297
@NotNull TransactionNameSource transactionNameSource = spanInfo.getTransactionNameSource();
298298
@Nullable SpanId parentSpanId = null;
299299
@Nullable Baggage baggage = null;
300+
@NotNull SentryId profilerId = SentryId.EMPTY_ID;
300301

301302
if (sentrySpanMaybe != null) {
302303
final @NotNull IOtelSpanWrapper sentrySpan = sentrySpanMaybe;
@@ -312,6 +313,7 @@ private void transferSpanDetails(
312313
final @NotNull SpanContext spanContext = sentrySpan.getSpanContext();
313314
parentSpanId = spanContext.getParentSpanId();
314315
baggage = spanContext.getBaggage();
316+
profilerId = spanContext.getProfilerId();
315317
}
316318

317319
final @NotNull TransactionContext transactionContext =
@@ -324,6 +326,7 @@ private void transferSpanDetails(
324326
transactionContext.setTransactionNameSource(transactionNameSource);
325327
transactionContext.setOperation(spanInfo.getOp());
326328
transactionContext.setInstrumenter(Instrumenter.SENTRY);
329+
transactionContext.setProfilerId(profilerId);
327330
if (sentrySpanMaybe != null) {
328331
transactionContext.setSamplingDecision(sentrySpanMaybe.getSamplingDecision());
329332
transactionOptions.setOrigin(sentrySpanMaybe.getSpanContext().getOrigin());

sentry-spring-7/api/sentry-spring-7.api

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public class io/sentry/spring7/SentryInitBeanPostProcessor : org/springframework
4242
public fun setApplicationContext (Lorg/springframework/context/ApplicationContext;)V
4343
}
4444

45+
public class io/sentry/spring7/SentryProfilerConfiguration {
46+
public fun <init> ()V
47+
public fun sentryOpenTelemetryProfilerConfiguration ()Lio/sentry/IContinuousProfiler;
48+
public fun sentryOpenTelemetryProfilerConverterConfiguration ()Lio/sentry/IProfileConverter;
49+
}
50+
4551
public class io/sentry/spring7/SentryRequestHttpServletRequestProcessor : io/sentry/EventProcessor {
4652
public fun <init> (Lio/sentry/spring7/tracing/TransactionNameProvider;Ljakarta/servlet/http/HttpServletRequest;)V
4753
public fun getOrder ()Ljava/lang/Long;
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.sentry.spring7;
2+
3+
import com.jakewharton.nopen.annotation.Open;
4+
import io.sentry.IContinuousProfiler;
5+
import io.sentry.IProfileConverter;
6+
import io.sentry.NoOpContinuousProfiler;
7+
import io.sentry.NoOpProfileConverter;
8+
import io.sentry.Sentry;
9+
import io.sentry.SentryOptions;
10+
import io.sentry.util.InitUtil;
11+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
12+
import org.springframework.context.annotation.Bean;
13+
import org.springframework.context.annotation.Configuration;
14+
15+
/**
16+
* Handles late initialization of the profiler if the application is run with the Opentelemetry
17+
* Agent in auto-init mode. In that case the agent cannot initialize the profiler yet and falls back
18+
* to No-Op implementations. This Configuration sets the profiler and converter on the options if
19+
* that was the case.
20+
*/
21+
@Configuration(proxyBeanMethods = false)
22+
@Open
23+
public class SentryProfilerConfiguration {
24+
25+
@Bean
26+
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConfiguration")
27+
public IContinuousProfiler sentryOpenTelemetryProfilerConfiguration() {
28+
SentryOptions options = Sentry.getGlobalScope().getOptions();
29+
IContinuousProfiler profiler = NoOpContinuousProfiler.getInstance();
30+
31+
if (Sentry.isEnabled()) {
32+
return InitUtil.initializeProfiler(options);
33+
} else {
34+
return profiler;
35+
}
36+
}
37+
38+
@Bean
39+
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConverterConfiguration")
40+
public IProfileConverter sentryOpenTelemetryProfilerConverterConfiguration() {
41+
SentryOptions options = Sentry.getGlobalScope().getOptions();
42+
IProfileConverter converter = NoOpProfileConverter.getInstance();
43+
44+
if (Sentry.isEnabled()) {
45+
return InitUtil.initializeProfileConverter(options);
46+
} else {
47+
return converter;
48+
}
49+
}
50+
}

sentry-spring-boot-4/api/sentry-spring-boot-4.api

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public class io/sentry/spring/boot4/SentryLogbackInitializer : org/springframewo
2424
public fun supportsEventType (Lorg/springframework/core/ResolvableType;)Z
2525
}
2626

27+
public class io/sentry/spring/boot4/SentryProfilerAutoConfiguration {
28+
public fun <init> ()V
29+
}
30+
2731
public class io/sentry/spring/boot4/SentryProperties : io/sentry/SentryOptions {
2832
public fun <init> ()V
2933
public fun getExceptionResolverOrder ()I

sentry-spring-boot-4/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ dependencies {
8585
testImplementation(libs.okhttp.mockwebserver)
8686
testImplementation(libs.otel)
8787
testImplementation(libs.otel.extension.autoconfigure.spi)
88+
testImplementation(projects.sentryAsyncProfiler)
8889
/**
8990
* Adding a version of opentelemetry-spring-boot-starter that doesn't support Spring Boot 4 causes
9091
* java.lang.IllegalArgumentException: Could not find class
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.sentry.spring.boot4;
2+
3+
import com.jakewharton.nopen.annotation.Open;
4+
import io.sentry.spring7.SentryProfilerConfiguration;
5+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.context.annotation.Import;
8+
9+
@Configuration(proxyBeanMethods = false)
10+
@ConditionalOnClass(
11+
name = {
12+
"io.sentry.opentelemetry.agent.AgentMarker",
13+
"io.sentry.asyncprofiler.profiling.JavaContinuousProfiler"
14+
})
15+
@Open
16+
@Import(SentryProfilerConfiguration.class)
17+
public class SentryProfilerAutoConfiguration {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
io.sentry.spring.boot4.SentryAutoConfiguration
2+
io.sentry.spring.boot4.SentryProfilerAutoConfiguration
23
io.sentry.spring.boot4.SentryLogbackAppenderAutoConfiguration
34
io.sentry.spring.boot4.SentryWebfluxAutoConfiguration

0 commit comments

Comments
 (0)