Skip to content

Commit 6f3cfa3

Browse files
authored
Update JMX metrics to support both a script and target systems (#1339)
1 parent 8a9d9c6 commit 6f3cfa3

File tree

5 files changed

+71
-21
lines changed

5 files changed

+71
-21
lines changed

jmx-metrics/README.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# JMX Metric Gatherer
22

33
This utility provides an easy framework for gathering and reporting metrics based on queried
4-
MBeans from a JMX server. It loads an included or custom Groovy script and establishes a helpful,
4+
MBeans from a JMX server. It loads included and/or custom Groovy scripts and establishes a helpful,
55
bound `otel` object with methods for obtaining MBeans and constructing OpenTelemetry instruments:
66

77
## Usage
88

99
The JMX Metric Gatherer is intended to be run as an uber jar and configured with properties from the command line,
1010
properties file, and stdin (`-`). Its metric-gathering scripts are specified by supported `otel.jmx.target.system`
11-
values or a `otel.jmx.groovy.script` path to run your own.
11+
values and/or a `otel.jmx.groovy.script` path to run your own.
1212

1313
```bash
1414
java -D<otel.jmx.property=value> -jar opentelemetry-jmx-metrics-<version>.jar [-config {session.properties, '-'}]
@@ -29,9 +29,11 @@ otel.exporter.otlp.endpoint = http://my-opentelemetry-collector:4317
2929

3030
As configured in this example, the metric gatherer will establish an MBean server connection using the
3131
specified `otel.jmx.service.url` (required) and credentials and configure an OTLP gRPC metrics exporter reporting to
32-
`otel.exporter.otlp.endpoint`. If SSL is enabled on the RMI registry for your server, the `otel.jmx.remote.registry.ssl` property must be set to `true`. After loading the included JVM and Kafka metric-gathering scripts determined by
33-
the comma-separated list in `otel.jmx.target.system`, it will then run the scripts on the desired interval
34-
length of `otel.jmx.interval.milliseconds` and export the resulting metrics.
32+
`otel.exporter.otlp.endpoint`. If SSL is enabled on the RMI registry for your server, the
33+
`otel.jmx.remote.registry.ssl` property must be set to `true`. After loading the included JVM and
34+
Kafka metric-gathering scripts determined by the comma-separated list in `otel.jmx.target.system`,
35+
it will then run the scripts on the desired interval length of `otel.jmx.interval.milliseconds` and
36+
export the resulting metrics.
3537

3638
For custom metrics and unsupported targets, you can provide your own MBean querying scripts to produce
3739
OpenTelemetry instruments:
@@ -63,8 +65,8 @@ attribute as queried in each interval.
6365
## Target Systems
6466

6567
The JMX Metric Gatherer provides built in metric producing Groovy scripts for supported target systems
66-
capable of being specified via the `otel.jmx.target.system` property as a comma-separated list. This property is
67-
mutually exclusive with `otel.jmx.groovy.script`. The currently supported target systems are:
68+
capable of being specified via the `otel.jmx.target.system` property as a comma-separated list. The
69+
currently supported target systems are:
6870

6971
| `otel.jmx.target.system` |
7072
|--------------------------|

jmx-metrics/src/main/groovy/io/opentelemetry/contrib/jmxmetrics/GroovyRunner.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ public class GroovyRunner {
4848
String systemResourcePath = "target-systems/" + target + ".groovy";
4949
scriptSources.add(getTargetSystemResourceAsString(systemResourcePath));
5050
}
51-
} else {
51+
}
52+
if (config.groovyScript != null && !config.groovyScript.isEmpty()) {
5253
scriptSources.add(getFileAsString(config.groovyScript));
5354
}
5455
} catch (IOException e) {

jmx-metrics/src/main/groovy/io/opentelemetry/contrib/jmxmetrics/JmxConfig.java

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class JmxConfig {
3333
static final String JMX_REALM = PREFIX + "jmx.realm";
3434

3535
// These properties need to be copied into System Properties if provided via the property
36-
// file so they are available to the JMX Connection builder
36+
// file so that they are available to the JMX Connection builder
3737
static final List<String> JAVA_SYSTEM_PROPERTIES =
3838
Arrays.asList(
3939
"javax.net.ssl.keyStore",
@@ -175,11 +175,6 @@ void validate() {
175175
GROOVY_SCRIPT + " or " + TARGET_SYSTEM + " must be specified.");
176176
}
177177

178-
if (!isBlank(groovyScript) && !isBlank(targetSystem)) {
179-
throw new ConfigurationException(
180-
"Only one of " + GROOVY_SCRIPT + " or " + TARGET_SYSTEM + " can be specified.");
181-
}
182-
183178
if (targetSystems.size() != 0 && !AVAILABLE_TARGET_SYSTEMS.containsAll(targetSystems)) {
184179
throw new ConfigurationException(
185180
String.format(

jmx-metrics/src/test/java/io/opentelemetry/contrib/jmxmetrics/GroovyRunnerTest.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,63 @@ public List<ObjectName> query(ObjectName objectName) {
4444
@Test
4545
@SetSystemProperty(key = "otel.jmx.service.url", value = "requiredValue")
4646
@SetSystemProperty(key = "otel.jmx.target.system", value = "notAProvidededTargetSystem")
47-
void loadUnavailableTargetScript() throws Exception {
47+
void loadUnavailableTargetScript() {
4848
JmxConfig config = new JmxConfig();
4949

5050
assertThatThrownBy(() -> new GroovyRunner(config, null, null))
5151
.isInstanceOf(ConfigurationException.class)
5252
.hasMessage("Failed to load target-systems/notaprovidededtargetsystem.groovy");
5353
}
54+
55+
@Test
56+
@SetSystemProperty(
57+
key = "otel.jmx.service.url",
58+
value = "service:jmx:rmi:///jndi/rmi://localhost:12345/jmxrmi")
59+
@SetSystemProperty(key = "otel.jmx.target.system", value = "jvm,hadoop")
60+
@SetSystemProperty(
61+
key = "otel.jmx.groovy.script",
62+
value = "src/integrationTest/resources/script.groovy")
63+
void loadScriptAndTargetSystems() throws Exception {
64+
JmxConfig config = new JmxConfig();
65+
66+
assertThatCode(config::validate).doesNotThrowAnyException();
67+
68+
JmxClient stub =
69+
new JmxClient(config) {
70+
@Override
71+
public List<ObjectName> query(ObjectName objectName) {
72+
return Collections.emptyList();
73+
}
74+
};
75+
76+
GroovyRunner runner = new GroovyRunner(config, stub, new GroovyMetricEnvironment(config));
77+
78+
assertThat(runner.getScripts()).hasSize(3);
79+
runner.run();
80+
}
81+
82+
@Test
83+
@SetSystemProperty(
84+
key = "otel.jmx.service.url",
85+
value = "service:jmx:rmi:///jndi/rmi://localhost:12345/jmxrmi")
86+
@SetSystemProperty(key = "otel.jmx.target.system", value = "jvm")
87+
@SetSystemProperty(key = "otel.jmx.groovy.script", value = "")
88+
void loadScriptAndTargetSystemWithBlankInputForScript() throws Exception {
89+
JmxConfig config = new JmxConfig();
90+
91+
assertThatCode(config::validate).doesNotThrowAnyException();
92+
93+
JmxClient stub =
94+
new JmxClient(config) {
95+
@Override
96+
public List<ObjectName> query(ObjectName objectName) {
97+
return Collections.emptyList();
98+
}
99+
};
100+
101+
GroovyRunner runner = new GroovyRunner(config, stub, new GroovyMetricEnvironment(config));
102+
103+
assertThat(runner.getScripts()).hasSize(1);
104+
runner.run();
105+
}
54106
}

jmx-metrics/src/test/java/io/opentelemetry/contrib/jmxmetrics/JmxConfigTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,16 @@ void invalidPrometheusPort() {
171171
}
172172

173173
@Test
174-
@SetSystemProperty(key = "otel.jmx.service.url", value = "requiredValue")
174+
@SetSystemProperty(key = "otel.jmx.service.url", value = "myServiceUrl")
175175
@SetSystemProperty(key = "otel.jmx.groovy.script", value = "myGroovyScript")
176176
@SetSystemProperty(key = "otel.jmx.target.system", value = "myTargetSystem")
177-
void conflictingScriptAndTargetSystem() {
177+
void canSupportScriptAndTargetSystem() {
178178
JmxConfig config = new JmxConfig();
179179

180-
assertThatThrownBy(config::validate)
181-
.isInstanceOf(ConfigurationException.class)
182-
.hasMessage(
183-
"Only one of otel.jmx.groovy.script or otel.jmx.target.system can be specified.");
180+
assertThat(config.serviceUrl).isEqualTo("myServiceUrl");
181+
assertThat(config.groovyScript).isEqualTo("myGroovyScript");
182+
assertThat(config.targetSystem).isEqualTo("mytargetsystem");
183+
assertThat(config.targetSystems).containsOnly("mytargetsystem");
184184
}
185185

186186
@Test

0 commit comments

Comments
 (0)