Skip to content

Commit ce523d6

Browse files
committed
TS-43260 Profiler crash fix in case of invalid config options
1 parent daea970 commit ce523d6

4 files changed

Lines changed: 45 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ We use [semantic versioning](http://semver.org/):
55
- PATCH version when you make backwards compatible bug fixes.
66

77
# Next version
8+
- [fix] _agent_: The profiled application no longer crashes when the profiler configuration is invalid (e.g., missing `teamscale-user`). Instead, the application starts normally without coverage collection. The error message now also lists which specific options are missing.
89
- [feature] _teamscale-gradle-plugin_: Annotated tasks with `@DisableCachingByDefault` where caching can't be applied
910

1011
# 36.4.0

agent/src/main/java/com/teamscale/jacoco/agent/PreMain.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ public class PreMain {
5959
private static final String ACCESS_TOKEN_ENVIRONMENT_VARIABLE = "TEAMSCALE_ACCESS_TOKEN";
6060

6161
/**
62-
* Entry point for the agent, called by the JVM.
62+
* Entry point for the agent, called by the JVM. If this method throws an exception, the JVM will abort the
63+
* entire application. Therefore, configuration errors must be handled gracefully by returning normally, which
64+
* allows the application to start without coverage collection.
6365
*/
6466
public static void premain(String options, Instrumentation instrumentation) throws Exception {
6567
if (System.getProperty(LOCKING_SYSTEM_PROPERTY) != null) {
@@ -87,8 +89,6 @@ public static void premain(String options, Instrumentation instrumentation) thro
8789
throw exception;
8890
}
8991
} catch (AgentOptionParseException e) {
90-
getLoggerContext().getLogger(PreMain.class).error(e.getMessage(), e);
91-
9292
// Flush logs to Teamscale, if configured.
9393
closeLoggingResources();
9494

@@ -97,7 +97,9 @@ public static void premain(String options, Instrumentation instrumentation) thro
9797
agentOptions.configurationViaTeamscale.unregisterProfiler();
9898
}
9999

100-
throw e;
100+
// Don't crash the profiled application due to a configuration error
101+
// (see TS-43260). The error has already been logged in getAndApplyAgentOptions.
102+
return;
101103
} catch (AgentOptionReceiveException e) {
102104
// When Teamscale is not available, we don't want to fail hard to still allow for testing even if no
103105
// coverage is collected (see TS-33237)
@@ -158,7 +160,9 @@ private static Pair<AgentOptions, List<Exception>> getAndApplyAgentOptions(Strin
158160
agentOptions = parseResult.getFirst();
159161
} catch (AgentOptionParseException e) {
160162
try (LoggingUtils.LoggingResources ignored = initializeFallbackLogging(options, delayedLogger)) {
161-
delayedLogger.errorAndStdErr("Failed to parse agent options: " + e.getMessage(), e);
163+
delayedLogger.errorAndStdErr(
164+
"Failed to parse agent options: " + e.getMessage() + " The application should start up normally, but NO coverage will be collected!",
165+
e);
162166
attemptLogAndThrow(delayedLogger);
163167
throw e;
164168
}
@@ -206,7 +210,9 @@ private static void initializeLogging(AgentOptions agentOptions, DelayedLogger l
206210

207211
/** Closes the opened logging contexts. */
208212
static void closeLoggingResources() {
209-
loggingResources.close();
213+
if (loggingResources != null) {
214+
loggingResources.close();
215+
}
210216
}
211217

212218
/**

agent/src/main/java/com/teamscale/jacoco/agent/options/AgentOptionsParser.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,18 @@ private void readConfigFromTeamscale(
410410
return;
411411
}
412412
if (!options.teamscaleServer.isConfiguredForServerConnection()) {
413+
List<String> missingOptions = new ArrayList<>();
414+
if (options.teamscaleServer.url == null) {
415+
missingOptions.add("teamscale-server-url");
416+
}
417+
if (options.teamscaleServer.userName == null) {
418+
missingOptions.add("teamscale-user");
419+
}
420+
if (options.teamscaleServer.userAccessToken == null) {
421+
missingOptions.add("teamscale-access-token");
422+
}
413423
throw new AgentOptionParseException(
414-
"Config-id '" + options.teamscaleServer.configId + "' specified without teamscale url/user/accessKey! These options must be provided locally via config-file or command line argument.");
424+
"Config-id '" + options.teamscaleServer.configId + "' specified but the following required option(s) are missing: " + String.join(", ", missingOptions) + ". These options must be provided locally via config-file or command line argument.");
415425
}
416426
// Set ssl validation option in case it needs to be off before trying to reach Teamscale.
417427
HttpUtils.setShouldValidateSsl(options.shouldValidateSsl());

agent/src/test/java/com/teamscale/jacoco/agent/options/AgentOptionsTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,27 @@ private static AgentOptionsParser getAgentOptionsParserWithDummyLoggerAndCredent
489489
return new AgentOptionsParser(new CommandLineLogger(), null, null, credentials, null);
490490
}
491491

492+
/** Tests that config-id without teamscale-user reports the missing option by name. */
493+
@Test
494+
public void configIdWithMissingUserReportsMissingOption() {
495+
assertThatThrownBy(
496+
() -> parseAndMaybeThrow(
497+
"config-id=test,teamscale-server-url=http://localhost:8080,teamscale-access-token=keyfoo"))
498+
.isInstanceOf(AgentOptionParseException.class)
499+
.hasMessageContaining("teamscale-user");
500+
}
501+
502+
/** Tests that config-id with all required options missing reports all of them. */
503+
@Test
504+
public void configIdWithAllMissingOptionsReportsAll() {
505+
assertThatThrownBy(
506+
() -> parseAndMaybeThrow("config-id=test"))
507+
.isInstanceOf(AgentOptionParseException.class)
508+
.hasMessageContaining("teamscale-server-url")
509+
.hasMessageContaining("teamscale-user")
510+
.hasMessageContaining("teamscale-access-token");
511+
}
512+
492513
/**
493514
* Delete created coverage folders
494515
*/

0 commit comments

Comments
 (0)