Skip to content

Commit b9a1d90

Browse files
committed
throw exception in case of parsing error
1 parent f30888c commit b9a1d90

File tree

5 files changed

+71
-42
lines changed

5 files changed

+71
-42
lines changed

instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
1414
import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil;
1515
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
16+
import java.nio.file.Paths;
1617
import java.time.Duration;
18+
import java.util.logging.Level;
19+
import java.util.logging.Logger;
1720

1821
/** An {@link AgentListener} that enables JMX metrics during agent startup. */
1922
@AutoService(AgentListener.class)
2023
public class JmxMetricInsightInstaller implements AgentListener {
2124

25+
private static final Logger logger = Logger.getLogger(JmxMetricInsightInstaller.class.getName());
26+
2227
@Override
2328
public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
2429
ConfigProperties config = AutoConfigureUtil.getConfig(autoConfiguredSdk);
@@ -28,10 +33,13 @@ public void afterAgent(AutoConfiguredOpenTelemetrySdk autoConfiguredSdk) {
2833
JmxTelemetry.builder(GlobalOpenTelemetry.get())
2934
.beanDiscoveryDelay(beanDiscoveryDelay(config).toMillis());
3035

31-
config.getList("otel.jmx.config").forEach(jmx::addCustomRules);
32-
config
33-
.getList("otel.jmx.target.system")
34-
.forEach(system -> jmx.addClasspathRules(JmxMetricInsightInstaller.class, system));
36+
try {
37+
config.getList("otel.jmx.config").stream().map(Paths::get).forEach(jmx::addCustomRules);
38+
config.getList("otel.jmx.target.system").forEach(jmx::addClasspathRules);
39+
} catch (IllegalArgumentException e) {
40+
// for now only log JMX errors as they do not prevent agent startup
41+
logger.log(Level.SEVERE, "Error while loading JMX configuration", e);
42+
}
3543

3644
jmx.build().startLocal();
3745
}

instrumentation/jmx-metrics/javaagent/src/test/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstallerTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import java.io.File;
1414
import java.io.FileInputStream;
1515
import java.io.InputStream;
16-
import java.nio.file.Files;
1716
import java.nio.file.Path;
1817
import java.nio.file.Paths;
1918
import java.util.Arrays;
@@ -39,7 +38,7 @@ void testToVerifyExistingRulesAreValid() throws Exception {
3938
assertThat(parser).isNotNull();
4039

4140
Path path = Paths.get(PATH_TO_ALL_EXISTING_RULES);
42-
assertThat(Files.exists(path)).isTrue();
41+
assertThat(path).isNotEmptyDirectory();
4342

4443
File existingRulesDir = path.toFile();
4544
File[] existingRules = existingRulesDir.listFiles();

instrumentation/jmx-metrics/library/README.md

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,21 @@ implementation("io.opentelemetry.instrumentation:opentelemetry-jmx-metrics:OPENT
3232

3333
```java
3434
import io.opentelemetry.api.OpenTelemetry;
35-
import io.opentelemetry.instrumentation.jmx.engine.JmxMetricInsight;
36-
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
35+
import io.opentelemetry.instrumentation.jmx.JmxTelemetry;
36+
import io.opentelemetry.instrumentation.jmx.JmxTelemetryBuilder;
3737

3838
// Get an OpenTelemetry instance
39-
OpenTelemetry openTelemetry = ...;
40-
41-
JmxMetricInsight jmxMetricInsight = JmxMetricInsight.createService(openTelemetry, 5000);
42-
43-
// Configure your JMX metrics
44-
MetricConfiguration config = new MetricConfiguration();
45-
46-
jmxMetricInsight.startLocal(config);
39+
OpenTelemetry openTelemetry = ...
40+
41+
JmxTelemetry jmxTelemetry = JmxTelemetry.builder(openTelemetry)
42+
// Configure included metrics (optional)
43+
.addClasspathRules("tomcat")
44+
.addClasspathRules("jetty")
45+
// Configure custom metrics (optional)
46+
.addCustomRules("/path/to/custom-jmx.yaml")
47+
// delay bean discovery by 5 seconds
48+
.beanDiscoveryDelay(5000)
49+
.build();
50+
51+
jmxTelemetry.startLocal();
4752
```

instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/JmxTelemetryBuilder.java

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66
package io.opentelemetry.instrumentation.jmx;
77

88
import static java.util.logging.Level.FINE;
9-
import static java.util.logging.Level.INFO;
109

1110
import com.google.errorprone.annotations.CanIgnoreReturnValue;
1211
import io.opentelemetry.api.OpenTelemetry;
1312
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
1413
import io.opentelemetry.instrumentation.jmx.yaml.RuleParser;
14+
import java.io.IOException;
1515
import java.io.InputStream;
1616
import java.nio.file.Files;
17-
import java.nio.file.Paths;
17+
import java.nio.file.Path;
1818
import java.util.logging.Logger;
1919

2020
public class JmxTelemetryBuilder {
@@ -31,40 +31,57 @@ public class JmxTelemetryBuilder {
3131
this.metricConfiguration = new MetricConfiguration();
3232
}
3333

34+
/**
35+
* Sets initial delay for MBean discovery
36+
*
37+
* @param delayMs delay in milliseconds
38+
* @return builder instance
39+
*/
3440
@CanIgnoreReturnValue
3541
public JmxTelemetryBuilder beanDiscoveryDelay(long delayMs) {
3642
this.discoveryDelayMs = delayMs;
3743
return this;
3844
}
3945

40-
// TODO: can we use classloader as argument instead of baseClass?
46+
/**
47+
* Adds built-in JMX rules from classpath resource
48+
*
49+
* @param target name of target in /jmx/rules/{target}.yaml classpath resource
50+
* @return builder instance
51+
* @throws IllegalArgumentException when classpath resource does not exist or can't be parsed
52+
*/
4153
@CanIgnoreReturnValue
42-
public JmxTelemetryBuilder addClasspathRules(Class<?> baseClass, String targetId) {
43-
String yamlResource = String.format("/jmx/rules/%s.yaml", targetId);
44-
try (InputStream inputStream = baseClass.getResourceAsStream(yamlResource)) {
45-
if (inputStream != null) {
46-
logger.log(FINE, "Adding JMX config from classpath for {0}", yamlResource);
47-
RuleParser parserInstance = RuleParser.get();
48-
parserInstance.addMetricDefsTo(metricConfiguration, inputStream, targetId);
49-
} else {
50-
logger.log(INFO, "No support found for {0}", targetId);
54+
public JmxTelemetryBuilder addClasspathRules(String target) {
55+
String yamlResource = String.format("/jmx/rules/%s.yaml", target);
56+
ClassLoader classLoader = JmxTelemetryBuilder.class.getClassLoader();
57+
try (InputStream inputStream = classLoader.getResourceAsStream(yamlResource)) {
58+
if (inputStream == null) {
59+
throw new IllegalArgumentException("JMX rules not found in classpath: " + yamlResource);
5160
}
61+
logger.log(FINE, "Adding JMX config from classpath for {0}", yamlResource);
62+
RuleParser parserInstance = RuleParser.get();
63+
parserInstance.addMetricDefsTo(metricConfiguration, inputStream, target);
5264
} catch (Exception e) {
53-
logger.warning(e.getMessage());
65+
throw new IllegalArgumentException("Unable to load JMX rules from classpath: " + yamlResource, e);
5466
}
5567
return this;
5668
}
5769

70+
/**
71+
* Adds custom JMX rules from file system path
72+
*
73+
* @param path path to yaml file
74+
* @return builder instance
75+
* @throws IllegalArgumentException when classpath resource does not exist or can't be parsed
76+
*/
5877
@CanIgnoreReturnValue
59-
public JmxTelemetryBuilder addCustomRules(String path) {
78+
public JmxTelemetryBuilder addCustomRules(Path path) {
6079
logger.log(FINE, "Adding JMX config from file: {0}", path);
6180
RuleParser parserInstance = RuleParser.get();
62-
try (InputStream inputStream = Files.newInputStream(Paths.get(path))) {
63-
parserInstance.addMetricDefsTo(metricConfiguration, inputStream, path);
64-
} catch (Exception e) {
65-
// yaml parsing errors are caught and logged inside of addMetricDefsTo
66-
// only file access related exceptions are expected here
67-
logger.warning(e.toString());
81+
try (InputStream inputStream = Files.newInputStream(path)) {
82+
parserInstance.addMetricDefsTo(metricConfiguration, inputStream, path.toString());
83+
} catch (IOException e) {
84+
throw new IllegalArgumentException("Unable to load JMX rules in path: " + path, e);
6885
}
6986
return this;
7087
}

instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import static java.util.Collections.emptyList;
99
import static java.util.logging.Level.INFO;
10-
import static java.util.logging.Level.WARNING;
1110

1211
import io.opentelemetry.instrumentation.jmx.engine.MetricConfiguration;
1312
import java.io.InputStream;
@@ -164,20 +163,21 @@ private static void failOnExtraKeys(Map<String, Object> yaml) {
164163
* @param conf the metric configuration
165164
* @param is the InputStream with the YAML rules
166165
* @param id identifier of the YAML ruleset, such as a filename
166+
* @throws IllegalArgumentException when unable to parse YAML
167167
*/
168168
public void addMetricDefsTo(MetricConfiguration conf, InputStream is, String id) {
169169
try {
170170
JmxConfig config = loadConfig(is);
171171
logger.log(INFO, "{0}: found {1} metric rules", new Object[] {id, config.getRules().size()});
172172
config.addMetricDefsTo(conf);
173173
} catch (Exception exception) {
174-
logger.log(
175-
WARNING,
176-
"Failed to parse YAML rules from {0}: {1}",
177-
new Object[] {id, rootCause(exception)});
178174
// It is essential that the parser exception is made visible to the user.
179175
// It contains contextual information about any syntax issues found by the parser.
180-
logger.log(WARNING, exception.toString());
176+
String msg =
177+
String.format(
178+
"Failed to parse YAML rules from %s: %s %s",
179+
id, rootCause(exception), exception.getMessage());
180+
throw new IllegalArgumentException(msg, exception);
181181
}
182182
}
183183

0 commit comments

Comments
 (0)