Browse Source

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

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
Peter Findeisen 2 years ago
parent
commit
c4ceaaa8d9

+ 4 - 4
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
 ---

+ 12 - 11
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());
       }
     }
   }

+ 8 - 3
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());