@@ -55,6 +55,11 @@ public class Arguments {
5555 */
5656 private static final String DEFAULT_HOST = "0.0.0.0" ;
5757
58+ /**
59+ * Prefix that enables graceful error handling for startup errors.
60+ */
61+ private static final String GRACEFUL_PREFIX = "graceful:" ;
62+
5863 /**
5964 * Regular expression pattern for parsing agent arguments.
6065 *
@@ -102,6 +107,15 @@ public class Arguments {
102107 */
103108 private final String filename ;
104109
110+ /**
111+ * Flag indicating whether graceful error handling is enabled.
112+ *
113+ * <p>When {@code true}, startup errors are logged and resources are cleaned up without calling
114+ * {@code System.exit(1)}. When {@code false}, the agent fails fast and exits the JVM on startup
115+ * errors.
116+ */
117+ private final boolean gracefulErrorHandling ;
118+
105119 /**
106120 * Constructs an Arguments instance with the specified configuration.
107121 *
@@ -110,13 +124,15 @@ public class Arguments {
110124 * disabled
111125 * @param port the port number for HTTP server, may be {@code null} when HTTP is disabled
112126 * @param filename the path to the configuration file, must not be {@code null}
127+ * @param gracefulErrorHandling whether graceful error handling is enabled
113128 * @throws NullPointerException if {@code filename} is {@code null}
114129 */
115- private Arguments (boolean httpEnabled , String host , Integer port , String filename ) {
130+ private Arguments (boolean httpEnabled , String host , Integer port , String filename , boolean gracefulErrorHandling ) {
116131 this .httpEnabled = httpEnabled ;
117132 this .host = host ;
118133 this .port = port ;
119134 this .filename = Objects .requireNonNull (filename , "filename cannot be null" );
135+ this .gracefulErrorHandling = gracefulErrorHandling ;
120136 }
121137
122138 /**
@@ -169,6 +185,18 @@ public String getFilename() {
169185 return filename ;
170186 }
171187
188+ /**
189+ * Returns whether graceful error handling is enabled.
190+ *
191+ * <p>When {@code true}, startup errors are logged and resources are cleaned up without calling
192+ * {@code System.exit(1)}.
193+ *
194+ * @return {@code true} if graceful error handling is enabled, {@code false} otherwise
195+ */
196+ public boolean isGracefulErrorHandling () {
197+ return gracefulErrorHandling ;
198+ }
199+
172200 /**
173201 * Parses the Java agent argument string into an Arguments instance.
174202 *
@@ -178,6 +206,9 @@ public String getFilename() {
178206 * <li>{@code port:configFile} - Enables HTTP on default host (0.0.0.0) and specified port
179207 * <li>{@code host:port:configFile} - Enables HTTP on specified host and port
180208 * <li>{@code configFile} - Disables HTTP (only OpenTelemetry export possible via config)
209+ * <li>{@code graceful:port:configFile} - Enables HTTP and graceful error handling
210+ * <li>{@code graceful:host:port:configFile} - Enables HTTP on specified host/port and graceful error handling
211+ * <li>{@code graceful:configFile} - Disables HTTP and enables graceful error handling
181212 * </ul>
182213 *
183214 * <p>Host can be a hostname, IPv4 address, or IPv6 address enclosed in square brackets.
@@ -191,14 +222,64 @@ public static Arguments parse(String agentArgument) {
191222 throw new ConfigurationException (format ("Malformed arguments [%s]" , agentArgument ));
192223 }
193224
194- Pattern pattern = Pattern .compile (CONFIGURATION_REGEX );
195- Matcher matcher = pattern .matcher (agentArgument );
225+ boolean gracefulErrorHandling = parseGracefulPrefix (agentArgument );
226+ String remainingArgument = stripGracefulPrefix (agentArgument );
227+
228+ ParsedHttpArguments parsedHttpArguments = parseHttpArguments (remainingArgument );
196229
230+ return new Arguments (
231+ parsedHttpArguments .httpEnabled ,
232+ parsedHttpArguments .host ,
233+ parsedHttpArguments .port ,
234+ parsedHttpArguments .filename ,
235+ gracefulErrorHandling );
236+ }
237+
238+ /**
239+ * Determines whether the agent argument starts with the graceful error handling prefix.
240+ *
241+ * @param agentArgument the agent argument string to check, must not be {@code null}
242+ * @return {@code true} if the argument starts with {@code graceful:}, {@code false} otherwise
243+ */
244+ private static boolean parseGracefulPrefix (String agentArgument ) {
245+ return agentArgument .startsWith (GRACEFUL_PREFIX );
246+ }
247+
248+ /**
249+ * Strips the optional graceful error handling prefix from the agent argument.
250+ *
251+ * @param agentArgument the agent argument string, must not be {@code null}
252+ * @return the argument string with the graceful prefix removed, if present
253+ * @throws ConfigurationException if only the graceful prefix was provided
254+ */
255+ private static String stripGracefulPrefix (String agentArgument ) {
256+ if (agentArgument .startsWith (GRACEFUL_PREFIX )) {
257+ String remaining = agentArgument .substring (GRACEFUL_PREFIX .length ());
258+ if (remaining .isEmpty ()) {
259+ throw new ConfigurationException (format ("Malformed arguments [%s]" , remaining ));
260+ }
261+ return remaining ;
262+ }
263+ return agentArgument ;
264+ }
265+
266+ /**
267+ * Parses the host, port, and filename from the agent argument after any graceful prefix has been
268+ * removed.
269+ *
270+ * @param agentArgument the agent argument string with graceful prefix already stripped
271+ * @return a {@link ParsedHttpArguments} containing the parsed values
272+ * @throws ConfigurationException if the argument is malformed
273+ */
274+ private static ParsedHttpArguments parseHttpArguments (String agentArgument ) {
197275 boolean httpEnabled = false ;
198276 String host = null ;
199277 Integer port = null ;
200278 String filename ;
201279
280+ Pattern pattern = Pattern .compile (CONFIGURATION_REGEX );
281+ Matcher matcher = pattern .matcher (agentArgument );
282+
202283 if (matcher .matches ()) {
203284 httpEnabled = true ;
204285
@@ -225,6 +306,24 @@ public static Arguments parse(String agentArgument) {
225306 filename = agentArgument ;
226307 }
227308
228- return new Arguments (httpEnabled , host , port , filename );
309+ return new ParsedHttpArguments (httpEnabled , host , port , filename );
310+ }
311+
312+ /**
313+ * Simple holder for HTTP-related parsed arguments.
314+ */
315+ private static class ParsedHttpArguments {
316+
317+ final boolean httpEnabled ;
318+ final String host ;
319+ final Integer port ;
320+ final String filename ;
321+
322+ ParsedHttpArguments (boolean httpEnabled , String host , Integer port , String filename ) {
323+ this .httpEnabled = httpEnabled ;
324+ this .host = host ;
325+ this .port = port ;
326+ this .filename = filename ;
327+ }
229328 }
230329}
0 commit comments