Skip to content

Commit

Permalink
Handle list (#43)
Browse files Browse the repository at this point in the history
* 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 <dan.jaglowski@bluemedora.com>
Co-authored-by: Sam DeHaan <sam.dehaan@bluemedora.com>
Co-authored-by: Ryan Fitzpatrick <rmfitzpatrick@signalfx.com>
  • Loading branch information
4 people committed Oct 20, 2021
1 parent 91e49c5 commit 7184f00
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 7 deletions.
2 changes: 2 additions & 0 deletions jmx-metrics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ mutually exclusive with `otel.jmx.groovy.script`. The currently supported target
but returns an `MBeanHelper` instance representing all matching MBeans for usage by subsequent `InstrumentHelper`
instances (available via `otel.instrument()`) as described below. It is intended to be used in cases
where your given `objectNameStr` can return a multiple element `List<GroovyMBean>`.
- `otel.mbeans(List<String> objectNameStrs)`
- 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()`.

- `otel.instrument(MBeanHelper mBeanHelper, String instrumentName, String description, String unit, Map<String, Closure> labelFuncs, String attribute, Closure instrument)`
- This method provides the ability to easily create and automatically update instrument instances from an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,22 @@ class MBeanHelper {

private final JmxClient jmxClient
private final boolean isSingle
private final String objectName
private final List<String> objectNames

private List<GroovyMBean> mbeans

MBeanHelper(JmxClient jmxClient, String objectName, boolean isSingle) {
this.jmxClient = jmxClient
this.objectName = objectName
this.objectNames = Collections.unmodifiableList([objectName])
this.isSingle = isSingle
}

MBeanHelper(JmxClient jmxClient, List<String> objectNames) {
this.jmxClient = jmxClient
this.objectNames = Collections.unmodifiableList(objectNames)
this.isSingle = false
}

@PackageScope static List<GroovyMBean> queryJmx(JmxClient jmxClient, String objNameStr) {
return queryJmx(jmxClient, new ObjectName(objNameStr))
}
Expand All @@ -54,11 +60,15 @@ class MBeanHelper {
}

void fetch() {
mbeans = queryJmx(jmxClient, objectName)
if (mbeans.size() == 0) {
logger.warning("Failed to fetch MBean ${objectName}.")
} else {
logger.fine("Fetched ${mbeans.size()} MBeans - ${mbeans}")
this.mbeans = []
for(objectName in objectNames){
def tmpMbeans = queryJmx(jmxClient, objectName)
if (tmpMbeans.size() == 0) {
logger.warning("Failed to fetch MBean ${objectName}.")
} else {
this.mbeans.addAll(tmpMbeans)
logger.fine("Fetched ${tmpMbeans.size()} MBeans - ${tmpMbeans}")
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@ class OtelHelper {
return mbeanHelper
}

/**
* Returns a fetched, potentially multi-{@link GroovyMBean} {@link MBeanHelper} for a given object name String.
* @param objNameStr - the {@link String} representation of an object name or pattern, to be
* used as the argument to the basic {@link javax.management.ObjectName} constructor for the JmxClient query.
* @return a {@link MBeanHelper} that operates over all resulting {@link GroovyMBean} instances.
*/
MBeanHelper mbeans(List<String> objNameStrs) {
def mbeanHelper = new MBeanHelper(jmxClient, objNameStrs)
mbeanHelper.fetch()
return mbeanHelper
}

/**
* Returns a fetched, single {@link GroovyMBean} {@link MBeanHelper} for a given object name String.
* @param objNameStr - the {@link String} representation of an object name or pattern, to be
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
import io.opentelemetry.sdk.metrics.data.DoublePointData;
import io.opentelemetry.sdk.metrics.data.LongPointData;
import io.opentelemetry.sdk.metrics.testing.InMemoryMetricReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
Expand Down Expand Up @@ -279,6 +281,38 @@ void doubleSum(String instrumentMethod) throws Exception {
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
}

@ParameterizedTest
@ValueSource(
strings = {
"doubleCounter",
"doubleUpDownCounter",
"doubleCounterCallback",
"doubleUpDownCounterCallback"
})
void doubleSumMultipleMBeans(String instrumentMethod) throws Exception {
ArrayList<String> thingNames = new ArrayList<>();
for (int i = 0; i < 4; i++) {
thingNames.add("multiple:type=" + instrumentMethod + ".Thing,thing=" + i);
}
MBeanHelper mBeanHelper = registerMultipleThings(thingNames);

String instrumentName = "multiple." + instrumentMethod + ".counter";
String description = "multiple double counter description";

updateWithHelper(mBeanHelper, instrumentMethod, instrumentName, description, "Double");

assertThat(metricReader.collectAllMetrics())
.satisfiesExactly(
metric ->
assertThat(metric)
.hasName(instrumentName)
.hasDescription(description)
.hasUnit("1")
.hasDoubleSum()
.points()
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
}

@ParameterizedTest
@ValueSource(
strings = {
Expand Down Expand Up @@ -386,6 +420,32 @@ void doubleValueCallback() throws Exception {
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
}

@Test
void doubleValueCallbackMultipleMBeans() throws Exception {
String instrumentMethod = "doubleValueCallback";
ArrayList<String> thingNames = new ArrayList<>();
for (int i = 0; i < 4; i++) {
thingNames.add("multiple:type=" + instrumentMethod + ".Thing,thing=" + i);
}
MBeanHelper mBeanHelper = registerMultipleThings(thingNames);

String instrumentName = "multiple." + instrumentMethod + ".counter";
String description = "multiple double counter description";

updateWithHelper(mBeanHelper, instrumentMethod, instrumentName, description, "Double");

assertThat(metricReader.collectAllMetrics())
.satisfiesExactly(
metric ->
assertThat(metric)
.hasName(instrumentName)
.hasDescription(description)
.hasUnit("1")
.hasDoubleGauge()
.points()
.satisfiesExactlyInAnyOrder(assertDoublePoints()));
}

@Test
void longValueCallback() throws Exception {
String instrumentMethod = "longValueCallback";
Expand Down Expand Up @@ -528,6 +588,17 @@ MBeanHelper registerThings(String thingName) throws Exception {
return mBeanHelper;
}

MBeanHelper registerMultipleThings(List<String> thingNames) throws Exception {
for (String thingName : thingNames) {
Thing thing = new Thing();
registeredBeans.add(mbeanServer.registerMBean(thing, new ObjectName(thingName)));
}

MBeanHelper mBeanHelper = new MBeanHelper(jmxClient, thingNames);
mBeanHelper.fetch();
return mBeanHelper;
}

void updateWithHelper(
MBeanHelper mBeanHelper,
String instrumentMethod,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Properties;
Expand Down Expand Up @@ -63,6 +64,23 @@ void unregisterBeans() throws Exception {
registeredBeans.clear();
}

@Test
void multiObj() throws Exception {
String thingName = "io.opentelemetry.contrib.jmxmetrics:type=multiObjThing";

registerThings(thingName);
MBeanHelper mBeanHelper =
new MBeanHelper(jmxClient, Arrays.asList(thingName + ",thing=0", thingName + ",thing=1"));
mBeanHelper.fetch();

assertThat(mBeanHelper.getAttribute("SomeAttribute"))
.hasSameElementsAs(
IntStream.range(0, 2).mapToObj(Integer::toString).collect(Collectors.toList()));
assertThat(mBeanHelper.getAttribute("MissingAttribute"))
.hasSameElementsAs(
IntStream.range(0, 2).mapToObj(unused -> null).collect(Collectors.toList()));
}

@Test
void single() throws Exception {
String thingName = "io.opentelemetry.contrib.jmxmetrics:type=singleThing";
Expand Down

0 comments on commit 7184f00

Please sign in to comment.