Skip to content

Commit 7184f00

Browse files
Mrod1598djaglowskiSam DeHaanRyan Fitzpatrick
authored
Handle list (#43)
* WIP - quick attempt to allow multiple object names per otel.mbeans call * Add Support for multiple object names & add test for it * Update Doc * Implement PR feedback * Fix spelling & Remove space * Add new otel.mbeans() signature for multiple ObjectNames (#1) * Add Support for multiple object names & add test for it * Update test * Update Tests * Add new test * Update Script for more predictable metrics * Add Max Workers * Move Test to new Java Tests * Spotless * Remove max workers * Move test to unit test * Spotless * Remove old files * Add multiple object name instrument helper test * Fix new instrumenthelpertests Co-authored-by: Dan Jaglowski <[email protected]> Co-authored-by: Sam DeHaan <[email protected]> Co-authored-by: Ryan Fitzpatrick <[email protected]>
1 parent 91e49c5 commit 7184f00

File tree

5 files changed

+120
-7
lines changed

5 files changed

+120
-7
lines changed

jmx-metrics/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ mutually exclusive with `otel.jmx.groovy.script`. The currently supported target
101101
but returns an `MBeanHelper` instance representing all matching MBeans for usage by subsequent `InstrumentHelper`
102102
instances (available via `otel.instrument()`) as described below. It is intended to be used in cases
103103
where your given `objectNameStr` can return a multiple element `List<GroovyMBean>`.
104+
- `otel.mbeans(List<String> objectNameStrs)`
105+
- This method is equivalent to the above method except, it adds support for multiple ObjectNames. This support is meant for when there are multiple mbeans that relate to the same metric and can be seperated using labels in `otel.instrument()`.
104106

105107
- `otel.instrument(MBeanHelper mBeanHelper, String instrumentName, String description, String unit, Map<String, Closure> labelFuncs, String attribute, Closure instrument)`
106108
- This method provides the ability to easily create and automatically update instrument instances from an

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

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,22 @@ class MBeanHelper {
3333

3434
private final JmxClient jmxClient
3535
private final boolean isSingle
36-
private final String objectName
36+
private final List<String> objectNames
3737

3838
private List<GroovyMBean> mbeans
3939

4040
MBeanHelper(JmxClient jmxClient, String objectName, boolean isSingle) {
4141
this.jmxClient = jmxClient
42-
this.objectName = objectName
42+
this.objectNames = Collections.unmodifiableList([objectName])
4343
this.isSingle = isSingle
4444
}
4545

46+
MBeanHelper(JmxClient jmxClient, List<String> objectNames) {
47+
this.jmxClient = jmxClient
48+
this.objectNames = Collections.unmodifiableList(objectNames)
49+
this.isSingle = false
50+
}
51+
4652
@PackageScope static List<GroovyMBean> queryJmx(JmxClient jmxClient, String objNameStr) {
4753
return queryJmx(jmxClient, new ObjectName(objNameStr))
4854
}
@@ -54,11 +60,15 @@ class MBeanHelper {
5460
}
5561

5662
void fetch() {
57-
mbeans = queryJmx(jmxClient, objectName)
58-
if (mbeans.size() == 0) {
59-
logger.warning("Failed to fetch MBean ${objectName}.")
60-
} else {
61-
logger.fine("Fetched ${mbeans.size()} MBeans - ${mbeans}")
63+
this.mbeans = []
64+
for(objectName in objectNames){
65+
def tmpMbeans = queryJmx(jmxClient, objectName)
66+
if (tmpMbeans.size() == 0) {
67+
logger.warning("Failed to fetch MBean ${objectName}.")
68+
} else {
69+
this.mbeans.addAll(tmpMbeans)
70+
logger.fine("Fetched ${tmpMbeans.size()} MBeans - ${tmpMbeans}")
71+
}
6272
}
6373
}
6474

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ class OtelHelper {
5858
return mbeanHelper
5959
}
6060

61+
/**
62+
* Returns a fetched, potentially multi-{@link GroovyMBean} {@link MBeanHelper} for a given object name String.
63+
* @param objNameStr - the {@link String} representation of an object name or pattern, to be
64+
* used as the argument to the basic {@link javax.management.ObjectName} constructor for the JmxClient query.
65+
* @return a {@link MBeanHelper} that operates over all resulting {@link GroovyMBean} instances.
66+
*/
67+
MBeanHelper mbeans(List<String> objNameStrs) {
68+
def mbeanHelper = new MBeanHelper(jmxClient, objNameStrs)
69+
mbeanHelper.fetch()
70+
return mbeanHelper
71+
}
72+
6173
/**
6274
* Returns a fetched, single {@link GroovyMBean} {@link MBeanHelper} for a given object name String.
6375
* @param objNameStr - the {@link String} representation of an object name or pattern, to be

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

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
import io.opentelemetry.sdk.metrics.data.DoublePointData;
1616
import io.opentelemetry.sdk.metrics.data.LongPointData;
1717
import io.opentelemetry.sdk.metrics.testing.InMemoryMetricReader;
18+
import java.util.ArrayList;
1819
import java.util.Collections;
1920
import java.util.HashMap;
2021
import java.util.HashSet;
22+
import java.util.List;
2123
import java.util.Map;
2224
import java.util.Properties;
2325
import java.util.Set;
@@ -279,6 +281,38 @@ void doubleSum(String instrumentMethod) throws Exception {
279281
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
280282
}
281283

284+
@ParameterizedTest
285+
@ValueSource(
286+
strings = {
287+
"doubleCounter",
288+
"doubleUpDownCounter",
289+
"doubleCounterCallback",
290+
"doubleUpDownCounterCallback"
291+
})
292+
void doubleSumMultipleMBeans(String instrumentMethod) throws Exception {
293+
ArrayList<String> thingNames = new ArrayList<>();
294+
for (int i = 0; i < 4; i++) {
295+
thingNames.add("multiple:type=" + instrumentMethod + ".Thing,thing=" + i);
296+
}
297+
MBeanHelper mBeanHelper = registerMultipleThings(thingNames);
298+
299+
String instrumentName = "multiple." + instrumentMethod + ".counter";
300+
String description = "multiple double counter description";
301+
302+
updateWithHelper(mBeanHelper, instrumentMethod, instrumentName, description, "Double");
303+
304+
assertThat(metricReader.collectAllMetrics())
305+
.satisfiesExactly(
306+
metric ->
307+
assertThat(metric)
308+
.hasName(instrumentName)
309+
.hasDescription(description)
310+
.hasUnit("1")
311+
.hasDoubleSum()
312+
.points()
313+
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
314+
}
315+
282316
@ParameterizedTest
283317
@ValueSource(
284318
strings = {
@@ -386,6 +420,32 @@ void doubleValueCallback() throws Exception {
386420
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
387421
}
388422

423+
@Test
424+
void doubleValueCallbackMultipleMBeans() throws Exception {
425+
String instrumentMethod = "doubleValueCallback";
426+
ArrayList<String> thingNames = new ArrayList<>();
427+
for (int i = 0; i < 4; i++) {
428+
thingNames.add("multiple:type=" + instrumentMethod + ".Thing,thing=" + i);
429+
}
430+
MBeanHelper mBeanHelper = registerMultipleThings(thingNames);
431+
432+
String instrumentName = "multiple." + instrumentMethod + ".counter";
433+
String description = "multiple double counter description";
434+
435+
updateWithHelper(mBeanHelper, instrumentMethod, instrumentName, description, "Double");
436+
437+
assertThat(metricReader.collectAllMetrics())
438+
.satisfiesExactly(
439+
metric ->
440+
assertThat(metric)
441+
.hasName(instrumentName)
442+
.hasDescription(description)
443+
.hasUnit("1")
444+
.hasDoubleGauge()
445+
.points()
446+
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
447+
}
448+
389449
@Test
390450
void longValueCallback() throws Exception {
391451
String instrumentMethod = "longValueCallback";
@@ -528,6 +588,17 @@ MBeanHelper registerThings(String thingName) throws Exception {
528588
return mBeanHelper;
529589
}
530590

591+
MBeanHelper registerMultipleThings(List<String> thingNames) throws Exception {
592+
for (String thingName : thingNames) {
593+
Thing thing = new Thing();
594+
registeredBeans.add(mbeanServer.registerMBean(thing, new ObjectName(thingName)));
595+
}
596+
597+
MBeanHelper mBeanHelper = new MBeanHelper(jmxClient, thingNames);
598+
mBeanHelper.fetch();
599+
return mBeanHelper;
600+
}
601+
531602
void updateWithHelper(
532603
MBeanHelper mBeanHelper,
533604
String instrumentMethod,

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
99
import static org.assertj.core.api.Assertions.assertThat;
1010

11+
import java.util.Arrays;
1112
import java.util.Collections;
1213
import java.util.HashSet;
1314
import java.util.Properties;
@@ -63,6 +64,23 @@ void unregisterBeans() throws Exception {
6364
registeredBeans.clear();
6465
}
6566

67+
@Test
68+
void multiObj() throws Exception {
69+
String thingName = "io.opentelemetry.contrib.jmxmetrics:type=multiObjThing";
70+
71+
registerThings(thingName);
72+
MBeanHelper mBeanHelper =
73+
new MBeanHelper(jmxClient, Arrays.asList(thingName + ",thing=0", thingName + ",thing=1"));
74+
mBeanHelper.fetch();
75+
76+
assertThat(mBeanHelper.getAttribute("SomeAttribute"))
77+
.hasSameElementsAs(
78+
IntStream.range(0, 2).mapToObj(Integer::toString).collect(Collectors.toList()));
79+
assertThat(mBeanHelper.getAttribute("MissingAttribute"))
80+
.hasSameElementsAs(
81+
IntStream.range(0, 2).mapToObj(unused -> null).collect(Collectors.toList()));
82+
}
83+
6684
@Test
6785
void single() throws Exception {
6886
String thingName = "io.opentelemetry.contrib.jmxmetrics:type=singleThing";

0 commit comments

Comments
 (0)