Skip to content

Commit 86aea60

Browse files
jmx: Allow specifying multiple target systems (#28)
1 parent d73c2d7 commit 86aea60

File tree

7 files changed

+476
-22
lines changed

7 files changed

+476
-22
lines changed

contrib/jmx-metrics/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ $ java -D<otel.jmx.property=value> -jar opentelemetry-java-contrib-jmx-metrics-<
1414

1515
```properties
1616
otel.jmx.service.url = service:jmx:rmi:///jndi/rmi://<my-jmx-host>:<my-jmx-port>/jmxrmi
17-
otel.jmx.groovy.script = /opt/script.groovy
17+
otel.jmx.target.system = jvm,kafka
1818
otel.jmx.interval.milliseconds = 5000
1919
otel.exporter = otlp
2020
otel.otlp.endpoint = my-opentelemetry-collector:55680
@@ -34,8 +34,8 @@ otel.instrument(storageLoadMBean, "cassandra.storage.load",
3434

3535
As configured in the example, this metric gatherer will configure an otlp gRPC metric exporter
3636
at the `otel.otlp.endpoint` and establish an MBean server connection using the
37-
provided `otel.jmx.service.url`. After loading the Groovy script whose path is specified
38-
via `otel.jmx.groovy.script`, it will then run the script on the specified
37+
provided `otel.jmx.service.url`. After loading the included metric gathering scripts specified by the
38+
comma-separated list in `otel.jmx.target.system`, it will then run the scripts on the specified
3939
`otel.jmx.interval.milliseconds` and export the resulting metrics.
4040

4141
### JMX Query Helpers
@@ -138,8 +138,8 @@ This metric extension supports Java 7+, though SASL is only supported where
138138
### Target Systems
139139

140140
The JMX Metric Gatherer also provides built in metric producing Groovy scripts for supported target systems
141-
capable of being specified via the `otel.jmx.target.system` property (mutually exclusive with `otel.jmx.groovy.script`).
142-
The currently available target systems are:
141+
capable of being specified via the `otel.jmx.target.system` property as a comma-separated list (mutually exclusive with
142+
`otel.jmx.groovy.script`). The currently available target systems are:
143143

144144
| `otel.jmx.target.system` |
145145
| ------------------------ |
@@ -159,7 +159,7 @@ file contents can also be provided via stdin on startup when using `-config -` a
159159
| ------------- | -------- | ----------- |
160160
| `otel.jmx.service.url` | **yes** | The service URL for the JMX RMI/JMXMP endpoint (generally of the form `service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi` or `service:jmx:jmxmp://<host>:<port>`).|
161161
| `otel.jmx.groovy.script` | if not using `otel.jmx.target.system` | The path for the desired Groovy script. |
162-
| `otel.jmx.target.system` | if not using `otel.jmx.groovy.script` | The supported target application with built in Groovy script. |
162+
| `otel.jmx.target.system` | if not using `otel.jmx.groovy.script` | A comma-separated list of the supported target applications with built in Groovy scripts. |
163163
| `otel.jmx.interval.milliseconds` | no | How often, in milliseconds, the Groovy script should be run and its resulting metrics exported. 10000 by default. |
164164
| `otel.exporter` | no | The type of metric exporter to use: (`otlp`, `prometheus`, `inmemory`, `logging`). `logging` by default. |
165165
| `otel.exporter.otlp.endpoint` | no | The otlp exporter endpoint to use, Required for `otlp`. |

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

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@
3232
import java.nio.file.FileSystems;
3333
import java.nio.file.Files;
3434
import java.nio.file.Path;
35+
import java.util.ArrayList;
3536
import java.util.Collections;
37+
import java.util.List;
3638
import java.util.Map;
3739
import java.util.logging.Level;
3840
import java.util.logging.Logger;
@@ -41,7 +43,7 @@
4143
public class GroovyRunner {
4244
private static final Logger logger = Logger.getLogger(GroovyRunner.class.getName());
4345

44-
private final Script script;
46+
private final List<Script> scripts;
4547
private final GroovyMetricEnvironment groovyMetricEnvironment;
4648

4749
GroovyRunner(
@@ -50,21 +52,26 @@ public class GroovyRunner {
5052
final GroovyMetricEnvironment groovyMetricEnvironment) {
5153
this.groovyMetricEnvironment = groovyMetricEnvironment;
5254

53-
String scriptSource;
55+
List<String> scriptSources = new ArrayList<>();
5456
try {
55-
if (!JmxConfig.isBlank(config.targetSystem)) {
56-
String systemResourcePath = "target-systems/" + config.targetSystem + ".groovy";
57-
scriptSource = getTargetSystemResourceAsString(systemResourcePath);
57+
if (config.targetSystems.size() != 0) {
58+
for (final String target : config.targetSystems) {
59+
String systemResourcePath = "target-systems/" + target + ".groovy";
60+
scriptSources.add(getTargetSystemResourceAsString(systemResourcePath));
61+
}
5862
} else {
59-
scriptSource = getFileAsString(config.groovyScript);
63+
scriptSources.add(getFileAsString(config.groovyScript));
6064
}
6165
} catch (IOException e) {
6266
logger.log(Level.SEVERE, "Failed to read groovy script", e);
6367
throw new ConfigurationException("Failed to read groovy script", e);
6468
}
6569

70+
this.scripts = new ArrayList<>();
6671
try {
67-
this.script = new GroovyShell().parse(scriptSource);
72+
for (final String source : scriptSources) {
73+
this.scripts.add(new GroovyShell().parse(source));
74+
}
6875
} catch (CompilationFailedException e) {
6976
logger.log(Level.SEVERE, "Failed to compile groovy script", e);
7077
throw new ConfigurationException("Failed to compile groovy script", e);
@@ -76,7 +83,9 @@ public class GroovyRunner {
7683
OtelHelper otelHelper = new OtelHelper(jmxClient, this.groovyMetricEnvironment);
7784
binding.setVariable("otel", otelHelper);
7885

79-
script.setBinding(binding);
86+
for (final Script script : scripts) {
87+
script.setBinding(binding);
88+
}
8089
}
8190

8291
private static String getFileAsString(final String fileName) throws IOException {
@@ -134,7 +143,9 @@ private static String getFileFromInputStream(final InputStream is) throws IOExce
134143
}
135144

136145
public void run() {
137-
script.run();
146+
for (final Script script : scripts) {
147+
script.run();
148+
}
138149
flush();
139150
}
140151

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package io.opentelemetry.contrib.jmxmetrics;
1818

1919
import java.util.Arrays;
20+
import java.util.LinkedHashSet;
2021
import java.util.List;
2122
import java.util.Properties;
23+
import java.util.Set;
2224

2325
class JmxConfig {
2426
static final String PREFIX = "otel.";
@@ -45,6 +47,7 @@ class JmxConfig {
4547
final String serviceUrl;
4648
final String groovyScript;
4749
final String targetSystem;
50+
final Set<String> targetSystems;
4851
final int intervalMilliseconds;
4952
final String exporterType;
5053

@@ -69,6 +72,10 @@ class JmxConfig {
6972
groovyScript = properties.getProperty(GROOVY_SCRIPT);
7073
targetSystem = properties.getProperty(TARGET_SYSTEM, "").toLowerCase().trim();
7174

75+
List<String> targets =
76+
Arrays.asList(isBlank(targetSystem) ? new String[0] : targetSystem.split(","));
77+
targetSystems = new LinkedHashSet<>(targets);
78+
7279
int interval = getProperty(INTERVAL_MILLISECONDS, 10000);
7380
intervalMilliseconds = interval == 0 ? 10000 : interval;
7481

@@ -117,9 +124,10 @@ void validate() {
117124
"Only one of " + GROOVY_SCRIPT + " or " + TARGET_SYSTEM + " can be specified.");
118125
}
119126

120-
if (!isBlank(targetSystem) && !AVAILABLE_TARGET_SYSTEMS.contains(targetSystem)) {
127+
if (targetSystems.size() != 0 && !AVAILABLE_TARGET_SYSTEMS.containsAll(targetSystems)) {
121128
throw new ConfigurationException(
122-
String.format("%s must be one of %s", targetSystem, AVAILABLE_TARGET_SYSTEMS));
129+
String.format(
130+
"%s must specify targets from %s", targetSystems, AVAILABLE_TARGET_SYSTEMS));
123131
}
124132

125133
if (isBlank(otlpExporterEndpoint)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class GroovyRunnerTest extends UnitTest {
4444
})
4545

4646
then: 'it is successfully loaded and runnable'
47-
groovyRunner.script != null
47+
groovyRunner.scripts.size() == 1
4848
groovyRunner.run()
4949
exportCalled
5050
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class JmxConfigTest extends UnitTest {
3838
config.serviceUrl == null
3939
config.groovyScript == null
4040
config.targetSystem == ""
41+
config.targetSystems == [] as LinkedHashSet
4142
config.intervalMilliseconds == 10000
4243
config.exporterType == "logging"
4344
config.otlpExporterEndpoint == null
@@ -54,7 +55,7 @@ class JmxConfigTest extends UnitTest {
5455
def properties = [
5556
"jmx.service.url" : "myServiceUrl",
5657
"jmx.groovy.script" : "myGroovyScript",
57-
"jmx.target.system" : "mytargetsystem",
58+
"jmx.target.system" : "mytargetsystem,mytargetsystem,myothertargetsystem,myadditionaltargetsystem",
5859
"jmx.interval.milliseconds": "123",
5960
"exporter": "inmemory",
6061
"exporter.otlp.endpoint": "myOtlpEndpoint",
@@ -71,7 +72,12 @@ class JmxConfigTest extends UnitTest {
7172
then:
7273
config.serviceUrl == "myServiceUrl"
7374
config.groovyScript == "myGroovyScript"
74-
config.targetSystem == "mytargetsystem"
75+
config.targetSystem == "mytargetsystem,mytargetsystem,myothertargetsystem,myadditionaltargetsystem"
76+
config.targetSystems == [
77+
"mytargetsystem",
78+
"myothertargetsystem",
79+
"myadditionaltargetsystem"
80+
] as LinkedHashSet
7581
config.intervalMilliseconds == 123
7682
config.exporterType == "inmemory"
7783
config.otlpExporterEndpoint == "myOtlpEndpoint"
@@ -130,7 +136,7 @@ class JmxConfigTest extends UnitTest {
130136
setup: "config is set with nonexistant target system"
131137
[
132138
"service.url" : "requiredValue",
133-
"target.system": "unavailableTargetSystem"
139+
"target.system": "jvm,unavailableTargetSystem"
134140
].each {
135141
System.setProperty("otel.jmx.${it.key}", it.value)
136142
}
@@ -145,6 +151,6 @@ class JmxConfigTest extends UnitTest {
145151

146152
expect: 'config fails to validate'
147153
raised != null
148-
raised.message == "unavailabletargetsystem must be one of [cassandra, jvm, kafka, kafka-consumer, kafka-producer]"
154+
raised.message == "[jvm, unavailabletargetsystem] must specify targets from [cassandra, jvm, kafka, kafka-consumer, kafka-producer]"
149155
}
150156
}

0 commit comments

Comments
 (0)