Skip to content

Commit 7b6d02f

Browse files
runningcodeclaude
andcommitted
fix(profiling): Accept dots in the JVM profiling traces dir path
JavaContinuousProfiler refused any traces directory whose path held one of 26 characters, including ".", so a cache dir like /home/app/.sentry or /opt/my.app logged "Disabling profiling". async-profiler only treats "," (its argument separator) and "%" (file name patterns) specially, so those are the only characters it still rejects. The check also only stopped the first start: init() marked itself done before validating and returned true from then on, so later starts went ahead with the rejected options. It now remembers the result, as the Android profiler does. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent 04bb98f commit 7b6d02f

2 files changed

Lines changed: 30 additions & 5 deletions

File tree

‎sentry-async-profiler/src/main/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfiler.java‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,15 @@
4242
public final class JavaContinuousProfiler
4343
implements IContinuousProfiler, RateLimiter.IRateLimitObserver {
4444
private static final long MAX_CHUNK_DURATION_MILLIS = 10000;
45-
private final List<String> invalidFilenameChars =
46-
Arrays.asList(
47-
".", ",", ":", ";", "|", "\\", "=", "%", "&", "[", "]", "(", ")", "<", ">", "{", "}", "!",
48-
"*", "?", "~", "\"", "'", "$", "`", "^");
45+
// async-profiler splits its arguments on "," and expands "%" patterns in the file name.
46+
private final List<String> invalidFilenameChars = Arrays.asList(",", "%");
4947

5048
private final @NotNull ILogger logger;
5149
private final @Nullable String profilingTracesDirPath;
5250
private final int profilingTracesHz;
5351
private final @NotNull ISentryExecutorService executorService;
5452
private boolean isInitialized = false;
53+
private boolean hasValidOptions = false;
5554
private boolean isRunning = false;
5655
private @Nullable IScopes scopes;
5756
private @Nullable Future<?> stopFuture;
@@ -92,7 +91,7 @@ private void initializeProfiler() throws Exception {
9291

9392
private boolean init() {
9493
if (isInitialized) {
95-
return true;
94+
return hasValidOptions;
9695
}
9796
isInitialized = true;
9897

@@ -107,6 +106,7 @@ private boolean init() {
107106
profilingTracesHz);
108107
return false;
109108
}
109+
hasValidOptions = true;
110110
return true;
111111
}
112112

‎sentry-async-profiler/src/test/java/io/sentry/asyncprofiler/profiling/JavaContinuousProfilerTest.kt‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,31 @@ class JavaContinuousProfilerTest {
421421
)
422422
}
423423

424+
@Test
425+
fun `profiler starts when the traces dir path contains a dot`() {
426+
val profiler = fixture.getSut {
427+
it.profilingTracesDirPath = File("tmp", "sentry.traces").absolutePath
428+
}
429+
File(fixture.options.profilingTracesDirPath!!).mkdirs()
430+
431+
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
432+
assertTrue(profiler.isRunning)
433+
profiler.close(true)
434+
}
435+
436+
@Test
437+
fun `profiler stays disabled when the traces dir is created after its first start`() {
438+
val tracesDir = File(fixture.options.profilingTracesDirPath!!)
439+
tracesDir.deleteRecursively()
440+
val profiler = fixture.getSut()
441+
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
442+
assertFalse(profiler.isRunning)
443+
444+
tracesDir.mkdirs()
445+
profiler.startProfiler(ProfileLifecycle.MANUAL, fixture.mockTracesSampler)
446+
assertFalse(profiler.isRunning)
447+
}
448+
424449
fun withMockScopes(closure: () -> Unit) =
425450
Mockito.mockStatic(Sentry::class.java).use {
426451
it.`when`<Any> { Sentry.getCurrentScopes() }.thenReturn(fixture.scopes)

0 commit comments

Comments
 (0)