Issue 7212 - Allow multiple YAML configuration files for JMX rules
MODIFY
instrumentation/jmx-metrics/javaagent/README.md
instrumentation/jmx-metrics/javaagent/README.md
@@ -30,20 +30,20 @@ No targets are enabled by default. The supported target environments are listed
- [wildfly](wildfly.md)
- [hadoop](hadoop.md)
-## Configuration File
+## Configuration Files
-To provide your own metric definitions, create a YAML configuration file, and specify its location using the `otel.jmx.config` property. For example
+To provide your own metric definitions, create one or more YAML configuration files, and specify their location using the `otel.jmx.config` property. Absolute or relative pathnames can be specified. For example
```bash
$ java -javaagent:path/to/opentelemetry-javaagent.jar \
- -Dotel.jmx.config=path/to/config_file.yaml \
+ -Dotel.jmx.config=path/to/config_file.yaml,more_rules.yaml \
... \
-jar myapp.jar
```
### Basic Syntax
-The configuration file can contain multiple entries (which we call _rules_), defining a number of metrics. Each rule must identify a set of MBeans and the name of the MBean attribute to query, along with additional information on how to report the values. Let's look at a simple example.
+Each configuration file can contain multiple entries (which we call _rules_), defining a number of metrics. Each rule must identify a set of MBeans and the name of the MBean attribute to query, along with additional information on how to report the values. Let's look at a simple example.
```yaml
---

MODIFY
instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java
instrumentation/jmx-metrics/javaagent/src/main/java/io/opentelemetry/instrumentation/javaagent/jmx/JmxMetricInsightInstaller.java
@@ -16,9 +16,10 @@ import io.opentelemetry.instrumentation.jmx.yaml.RuleParser;
import io.opentelemetry.javaagent.extension.AgentListener;
import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk;
import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
-import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.List;
/** An {@link AgentListener} that enables JMX metrics during agent startup. */
@AutoService(AgentListener.class)
@@ -59,7 +60,7 @@ public class JmxMetricInsightInstaller implements AgentListener {
if (inputStream != null) {
JmxMetricInsight.getLogger().log(FINE, "Opened input stream {0}", yamlResource);
RuleParser parserInstance = RuleParser.get();
- parserInstance.addMetricDefsTo(conf, inputStream);
+ parserInstance.addMetricDefsTo(conf, inputStream, platform);
} else {
JmxMetricInsight.getLogger().log(INFO, "No support found for {0}", platform);
}
@@ -70,9 +71,7 @@ public class JmxMetricInsightInstaller implements AgentListener {
private static void buildFromDefaultRules(
MetricConfiguration conf, ConfigProperties configProperties) {
- String targetSystem = configProperties.getString("otel.jmx.target.system", "");
- String[] platforms = targetSystem.isEmpty() ? new String[0] : targetSystem.split(",");
-
+ List<String> platforms = configProperties.getList("otel.jmx.target.system");
for (String platform : platforms) {
addRulesForPlatform(platform, conf);
}
@@ -80,14 +79,16 @@ public class JmxMetricInsightInstaller implements AgentListener {
private static void buildFromUserRules(
MetricConfiguration conf, ConfigProperties configProperties) {
- String jmxDir = configProperties.getString("otel.jmx.config");
- if (jmxDir != null) {
- JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", jmxDir);
+ List<String> configFiles = configProperties.getList("otel.jmx.config");
+ for (String configFile : configFiles) {
+ JmxMetricInsight.getLogger().log(FINE, "JMX config file name: {0}", configFile);
RuleParser parserInstance = RuleParser.get();
- try (InputStream inputStream = Files.newInputStream(new File(jmxDir.trim()).toPath())) {
- parserInstance.addMetricDefsTo(conf, inputStream);
+ try (InputStream inputStream = Files.newInputStream(Paths.get(configFile))) {
+ parserInstance.addMetricDefsTo(conf, inputStream, configFile);
} catch (Exception e) {
- JmxMetricInsight.getLogger().warning(e.getMessage());
+ // yaml parsing errors are caught and logged inside of addMetricDefsTo
+ // only file access related exceptions are expected here
+ JmxMetricInsight.getLogger().warning(e.toString());
}
}
}

MODIFY
instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java
instrumentation/jmx-metrics/library/src/main/java/io/opentelemetry/instrumentation/jmx/yaml/RuleParser.java
@@ -51,17 +51,22 @@ public class RuleParser {
*
* @param conf the metric configuration
* @param is the InputStream with the YAML rules
+ * @param id identifier of the YAML ruleset, such as a filename
*/
- public void addMetricDefsTo(MetricConfiguration conf, InputStream is) {
+ public void addMetricDefsTo(MetricConfiguration conf, InputStream is, String id) {
try {
JmxConfig config = loadConfig(is);
if (config != null) {
- logger.log(INFO, "Found {0} metric rules", config.getRules().size());
+ logger.log(
+ INFO, "{0}: found {1} metric rules", new Object[] {id, config.getRules().size()});
config.addMetricDefsTo(conf);
}
} catch (Exception exception) {
- logger.log(WARNING, "Failed to parse YAML rules: " + rootCause(exception));
+ logger.log(
+ WARNING,
+ "Failed to parse YAML rules from {0}: {1}",
+ new Object[] {id, rootCause(exception)});
// It is essential that the parser exception is made visible to the user.
// It contains contextual information about any syntax issues found by the parser.
logger.log(WARNING, exception.toString());

Issue 7212 - Allow multiple YAML configuration files for JMX rules (#7284)

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>