Skip to content

Commit b59fc8e

Browse files
authored
Merge a4ce01a into b9ea522
2 parents b9ea522 + a4ce01a commit b59fc8e

File tree

15 files changed

+189
-15
lines changed

15 files changed

+189
-15
lines changed

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

sentry-spring-boot-jakarta/api/sentry-spring-boot-jakarta.api

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

27+
public class io/sentry/spring/boot/jakarta/SentryProfilerAutoConfiguration {
28+
public fun <init> ()V
29+
}
30+
2731
public class io/sentry/spring/boot/jakarta/SentryProperties : io/sentry/SentryOptions {
2832
public fun <init> ()V
2933
public fun getExceptionResolverOrder ()I
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.sentry.spring.boot.jakarta;
2+
3+
import com.jakewharton.nopen.annotation.Open;
4+
import io.sentry.spring.jakarta.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(name = {"io.sentry.opentelemetry.agent.AgentMarker"})
11+
@Open
12+
@Import(SentryProfilerConfiguration.class)
13+
public class SentryProfilerAutoConfiguration {}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
io.sentry.spring.boot.jakarta.SentryAutoConfiguration
2+
io.sentry.spring.boot.jakarta.SentryProfilerAutoConfiguration
23
io.sentry.spring.boot.jakarta.SentryLogbackAppenderAutoConfiguration
34
io.sentry.spring.boot.jakarta.SentryWebfluxAutoConfiguration

sentry-spring-jakarta/api/sentry-spring-jakarta.api

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

45+
public class io/sentry/spring/jakarta/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/spring/jakarta/SentryRequestHttpServletRequestProcessor : io/sentry/EventProcessor {
4652
public fun <init> (Lio/sentry/spring/jakarta/tracing/TransactionNameProvider;Ljakarta/servlet/http/HttpServletRequest;)V
4753
public fun getOrder ()Ljava/lang/Long;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package io.sentry.spring.jakarta;
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.SentryLevel;
10+
import io.sentry.SentryOptions;
11+
import io.sentry.profiling.ProfilingServiceLoader;
12+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
13+
import org.springframework.context.annotation.Bean;
14+
import org.springframework.context.annotation.Configuration;
15+
16+
/**
17+
* Handles late initialization of the profiler if the application is run with the OTEL Agent in
18+
* auto-init mode. In that case the agent cannot initialize the profiler yet and falls back to No-Op
19+
* implementations. This Configuration sets the profiler and converter on the options if that was
20+
* the case.
21+
*/
22+
@Configuration(proxyBeanMethods = false)
23+
@Open
24+
public class SentryProfilerConfiguration {
25+
26+
@Bean
27+
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConfiguration")
28+
public IContinuousProfiler sentryOpenTelemetryProfilerConfiguration() {
29+
SentryOptions options = Sentry.getGlobalScope().getOptions();
30+
IContinuousProfiler profiler = NoOpContinuousProfiler.getInstance();
31+
32+
if (Sentry.isEnabled()
33+
&& options.isContinuousProfilingEnabled()
34+
&& options.getContinuousProfiler() instanceof NoOpContinuousProfiler) {
35+
36+
options
37+
.getLogger()
38+
.log(
39+
SentryLevel.DEBUG,
40+
"Continuous profiler is NoOp, attempting to reload with Spring Boot classloader");
41+
42+
String path = options.getProfilingTracesDirPath();
43+
44+
profiler =
45+
ProfilingServiceLoader.loadContinuousProfiler(
46+
options.getLogger(),
47+
path != null ? path : "",
48+
options.getProfilingTracesHz(),
49+
options.getExecutorService());
50+
51+
options.setContinuousProfiler(profiler);
52+
53+
if (!(profiler instanceof NoOpContinuousProfiler)) {
54+
options
55+
.getLogger()
56+
.log(
57+
SentryLevel.INFO,
58+
"Successfully loaded continuous profiler via Spring Boot classloader");
59+
}
60+
}
61+
return profiler;
62+
}
63+
64+
@Bean
65+
@ConditionalOnMissingBean(name = "sentryOpenTelemetryProfilerConverterConfiguration")
66+
public IProfileConverter sentryOpenTelemetryProfilerConverterConfiguration() {
67+
SentryOptions options = Sentry.getGlobalScope().getOptions();
68+
IProfileConverter converter = NoOpProfileConverter.getInstance();
69+
70+
if (Sentry.isEnabled()
71+
&& options.isContinuousProfilingEnabled()
72+
&& options.getProfilerConverter() instanceof NoOpProfileConverter) {
73+
74+
options
75+
.getLogger()
76+
.log(
77+
SentryLevel.DEBUG,
78+
"Profile converter is NoOp, attempting to reload with Spring Boot classloader");
79+
80+
converter = ProfilingServiceLoader.loadProfileConverter();
81+
82+
options.setProfilerConverter(converter);
83+
84+
if (!(converter instanceof NoOpProfileConverter)) {
85+
options
86+
.getLogger()
87+
.log(
88+
SentryLevel.INFO,
89+
"Successfully loaded profile converter via Spring Boot classloader");
90+
}
91+
}
92+
return converter;
93+
}
94+
}

sentry/api/sentry.api

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,6 +1582,11 @@ public final class io/sentry/NoOpLogger : io/sentry/ILogger {
15821582
public fun log (Lio/sentry/SentryLevel;Ljava/lang/Throwable;Ljava/lang/String;[Ljava/lang/Object;)V
15831583
}
15841584

1585+
public final class io/sentry/NoOpProfileConverter : io/sentry/IProfileConverter {
1586+
public fun convertFromFile (Ljava/lang/String;)Lio/sentry/protocol/profiling/SentryProfile;
1587+
public static fun getInstance ()Lio/sentry/NoOpProfileConverter;
1588+
}
1589+
15851590
public final class io/sentry/NoOpReplayBreadcrumbConverter : io/sentry/ReplayBreadcrumbConverter {
15861591
public fun convert (Lio/sentry/Breadcrumb;)Lio/sentry/rrweb/RRWebEvent;
15871592
public static fun getInstance ()Lio/sentry/NoOpReplayBreadcrumbConverter;
@@ -2893,6 +2898,7 @@ public final class io/sentry/SentryEnvelopeItem {
28932898
public static fun fromEvent (Lio/sentry/ISerializer;Lio/sentry/SentryBaseEvent;)Lio/sentry/SentryEnvelopeItem;
28942899
public static fun fromLogs (Lio/sentry/ISerializer;Lio/sentry/SentryLogEvents;)Lio/sentry/SentryEnvelopeItem;
28952900
public static fun fromProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/ISerializer;)Lio/sentry/SentryEnvelopeItem;
2901+
public static fun fromProfileChunk (Lio/sentry/ProfileChunk;Lio/sentry/ISerializer;Lio/sentry/IProfileConverter;)Lio/sentry/SentryEnvelopeItem;
28962902
public static fun fromProfilingTrace (Lio/sentry/ProfilingTraceData;JLio/sentry/ISerializer;)Lio/sentry/SentryEnvelopeItem;
28972903
public static fun fromReplay (Lio/sentry/ISerializer;Lio/sentry/ILogger;Lio/sentry/SentryReplayEvent;Lio/sentry/ReplayRecording;Z)Lio/sentry/SentryEnvelopeItem;
28982904
public static fun fromSession (Lio/sentry/ISerializer;Lio/sentry/Session;)Lio/sentry/SentryEnvelopeItem;
@@ -3385,6 +3391,7 @@ public class io/sentry/SentryOptions {
33853391
public fun getPerformanceCollectors ()Ljava/util/List;
33863392
public fun getProfileLifecycle ()Lio/sentry/ProfileLifecycle;
33873393
public fun getProfileSessionSampleRate ()Ljava/lang/Double;
3394+
public fun getProfilerConverter ()Lio/sentry/IProfileConverter;
33883395
public fun getProfilesSampleRate ()Ljava/lang/Double;
33893396
public fun getProfilesSampler ()Lio/sentry/SentryOptions$ProfilesSamplerCallback;
33903397
public fun getProfilingTracesDirPath ()Ljava/lang/String;
@@ -3530,6 +3537,7 @@ public class io/sentry/SentryOptions {
35303537
public fun setPrintUncaughtStackTrace (Z)V
35313538
public fun setProfileLifecycle (Lio/sentry/ProfileLifecycle;)V
35323539
public fun setProfileSessionSampleRate (Ljava/lang/Double;)V
3540+
public fun setProfilerConverter (Lio/sentry/IProfileConverter;)V
35333541
public fun setProfilesSampleRate (Ljava/lang/Double;)V
35343542
public fun setProfilesSampler (Lio/sentry/SentryOptions$ProfilesSamplerCallback;)V
35353543
public fun setProfilingTracesDirPath (Ljava/lang/String;)V
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.sentry;
2+
3+
import io.sentry.protocol.profiling.SentryProfile;
4+
import java.io.IOException;
5+
import org.jetbrains.annotations.NotNull;
6+
7+
public final class NoOpProfileConverter implements IProfileConverter {
8+
9+
private static final NoOpProfileConverter instance = new NoOpProfileConverter();
10+
11+
private NoOpProfileConverter() {}
12+
13+
public static NoOpProfileConverter getInstance() {
14+
return instance;
15+
}
16+
17+
@Override
18+
public @NotNull SentryProfile convertFromFile(@NotNull String jfrFilePath) throws IOException {
19+
return new SentryProfile();
20+
}
21+
}

sentry/src/main/java/io/sentry/Sentry.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,11 @@ private static void initJvmContinuousProfiling(@NotNull SentryOptions options) {
717717
options.getExecutorService());
718718

719719
options.setContinuousProfiler(continuousProfiler);
720+
721+
final IProfileConverter profileConverter = ProfilingServiceLoader.loadProfileConverter();
722+
if (profileConverter != null) {
723+
options.setProfilerConverter(profileConverter);
724+
}
720725
} catch (Exception e) {
721726
options
722727
.getLogger()

sentry/src/main/java/io/sentry/SentryClient.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ public void captureSession(final @NotNull Session session, final @Nullable Hint
983983
new SentryEnvelope(
984984
new SentryEnvelopeHeader(sentryId, options.getSdkVersion(), null),
985985
Collections.singletonList(
986-
SentryEnvelopeItem.fromProfileChunk(profileChunk, options.getSerializer())));
986+
SentryEnvelopeItem.fromProfileChunk(
987+
profileChunk, options.getSerializer(), options.getProfilerConverter())));
987988
sentryId = sendEnvelope(envelope, null);
988989
} catch (IOException | SentryEnvelopeException e) {
989990
options

0 commit comments

Comments
 (0)