Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions instrumentation/jmx-metrics/javaagent/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private static void addRulesForPlatform(String platform, MetricConfiguration con
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);
}
Expand All @@ -80,14 +80,15 @@ private static void buildFromDefaultRules(

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);
String files = configProperties.getString("otel.jmx.config", "");
String[] configFiles = files.isEmpty() ? new String[0] : files.split(",");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use ConfigProperties#getList() instead

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(new File(configFile).toPath())) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
try (InputStream inputStream = Files.newInputStream(new File(configFile).toPath())) {
try (InputStream inputStream = Files.newInputStream(Paths.get(configFile))) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review, @mateuszrzeszutek!

parserInstance.addMetricDefsTo(conf, inputStream, configFile);
} catch (Exception e) {
JmxMetricInsight.getLogger().warning(e.getMessage());
JmxMetricInsight.getLogger().warning(e.toString());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pretty much only logs the message; shouldn't we log the whole stacktrace here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not in this case. An exception at this location indicates difficulties with reading the file (user error), and the message should be sufficient for troubleshooting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a specific exception that indicates parsing error (e.g. YamlException)? or is the code inside the try block narrow enough that there shouldn't be any other type of exception here?

Copy link
Contributor Author

@PeterF778 PeterF778 Nov 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parsing errors are handled by RuleParser, and an effort has been made to provide as useful contextual info there as possible. But again, without stack traces, as they would not get any value for the users, IMHO.
Only file access related exceptions are expected here.

}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,18 @@ public JmxConfig loadConfig(InputStream is) throws Exception {
*
* @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, id + ": found {0} metric rules", config.getRules().size());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use placeholders?

Suggested change
logger.log(INFO, id + ": 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 " + id + ": " + rootCause(exception));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please use placeholders instead of glueing log messages manually

// 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());
Expand Down