-
Notifications
You must be signed in to change notification settings - Fork 870
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
jmx state metrics #12369
jmx state metrics #12369
Changes from 15 commits
9272bfe
6f20784
d1a195b
3f2f151
5973b01
4fd10aa
6155206
af37bb4
6551200
376acc5
679c460
e5ff7c5
8e73f10
e9e8e83
550b003
1bb4302
ebf58ff
6c10e6d
652ab32
e24b9ae
2698be3
e4b9fe5
111c26b
96bb6cc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -120,6 +120,13 @@ void enrollExtractor( | |
} | ||
logger.log(INFO, "Created Gauge for {0}", metricName); | ||
} | ||
break; | ||
// CHECKSTYLE:OFF | ||
case STATE: | ||
{ | ||
// CHECKSTYLE:ON | ||
throw new IllegalStateException("state metrics should not be registered"); | ||
} | ||
Comment on lines
+125
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] this is needed to have the switch statement cover all cases. |
||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
import io.opentelemetry.instrumentation.jmx.engine.BeanAttributeExtractor; | ||
import io.opentelemetry.instrumentation.jmx.engine.BeanGroup; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricAttribute; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricAttributeExtractor; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricDef; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricExtractor; | ||
import io.opentelemetry.instrumentation.jmx.engine.MetricInfo; | ||
|
@@ -18,6 +19,7 @@ | |
import java.util.Map; | ||
import java.util.Set; | ||
import javax.annotation.Nullable; | ||
import javax.management.MBeanServerConnection; | ||
import javax.management.MalformedObjectNameException; | ||
import javax.management.ObjectName; | ||
|
||
|
@@ -143,8 +145,7 @@ public MetricDef buildMetricDef() throws Exception { | |
} | ||
|
||
Set<String> attrNames = mapping.keySet(); | ||
MetricExtractor[] metricExtractors = new MetricExtractor[attrNames.size()]; | ||
int n = 0; | ||
List<MetricExtractor> metricExtractors = new ArrayList<>(); | ||
for (String attributeName : attrNames) { | ||
BeanAttributeExtractor attrExtractor = BeanAttributeExtractor.fromName(attributeName); | ||
// This is essentially the same as 'attributeName' but with escape characters removed | ||
|
@@ -162,44 +163,112 @@ public MetricDef buildMetricDef() throws Exception { | |
metricInfo = m.buildMetricInfo(prefix, niceAttributeName, getUnit(), getMetricType()); | ||
} | ||
|
||
List<MetricAttribute> attributeList; | ||
List<MetricAttribute> ownAttributes = getAttributeList(); | ||
if (ownAttributes != null && m != null && m.getAttributeList() != null) { | ||
// MetricAttributes have been specified at two levels, need to combine them | ||
attributeList = combineMetricAttributes(ownAttributes, m.getAttributeList()); | ||
} else if (ownAttributes != null) { | ||
attributeList = ownAttributes; | ||
} else if (m != null && m.getAttributeList() != null) { | ||
// Get the attributes from the metric | ||
attributeList = m.getAttributeList(); | ||
List<MetricAttribute> metricAttributes = m != null ? m.getAttributeList() : null; | ||
List<MetricAttribute> attributeList = | ||
combineMetricAttributes(ownAttributes, metricAttributes); | ||
|
||
// higher priority to metric level mapping, then jmx rule as fallback | ||
StateMapping stateMapping = getEffectiveStateMapping(m, this); | ||
|
||
if (stateMapping.isEmpty()) { | ||
metricExtractors.add( | ||
new MetricExtractor( | ||
attrExtractor, metricInfo, attributeList.toArray(new MetricAttribute[0]))); | ||
} else { | ||
// There are no attributes at all | ||
attributeList = new ArrayList<MetricAttribute>(); | ||
|
||
// generate one metric extractor per state metric key | ||
// each metric extractor will have the state attribute replaced with a constant | ||
metricExtractors.addAll( | ||
createStateMappingExtractors(stateMapping, attributeList, attrExtractor, metricInfo)); | ||
} | ||
} | ||
|
||
return new MetricDef(group, metricExtractors.toArray(new MetricExtractor[0])); | ||
} | ||
|
||
private static List<MetricExtractor> createStateMappingExtractors( | ||
StateMapping stateMapping, | ||
List<MetricAttribute> attributeList, | ||
BeanAttributeExtractor attrExtractor, | ||
MetricInfo metricInfo) { | ||
|
||
List<MetricExtractor> extractors = new ArrayList<>(); | ||
for (String key : stateMapping.getStateKeys()) { | ||
List<MetricAttribute> stateMetricAttributes = new ArrayList<>(); | ||
|
||
for (MetricAttribute ma : attributeList) { | ||
// replace state metric attribute with constant key value | ||
if (!ma.isStateAttribute()) { | ||
stateMetricAttributes.add(ma); | ||
} else { | ||
stateMetricAttributes.add( | ||
new MetricAttribute( | ||
ma.getAttributeName(), MetricAttributeExtractor.fromConstant(key))); | ||
} | ||
} | ||
|
||
MetricExtractor metricExtractor = | ||
BeanAttributeExtractor stateMetricExtractor = | ||
new BeanAttributeExtractor(attrExtractor.getAttributeName()) { | ||
|
||
@Override | ||
protected Object getSampleValue( | ||
MBeanServerConnection connection, ObjectName objectName) { | ||
// metric actual type is sampled in the discovery process, so we have to | ||
// make this extractor as extracting integers. | ||
return 0; | ||
} | ||
|
||
@Override | ||
protected Number extractNumericalAttribute( | ||
MBeanServerConnection connection, ObjectName objectName) { | ||
String rawStateValue = attrExtractor.extractValue(connection, objectName); | ||
String mappedStateValue = stateMapping.getStateValue(rawStateValue); | ||
return key.equals(mappedStateValue) ? 1 : 0; | ||
} | ||
}; | ||
|
||
// state metric are always up/down counters | ||
MetricInfo stateMetricInfo = | ||
new MetricInfo( | ||
metricInfo.getMetricName(), | ||
metricInfo.getDescription(), | ||
metricInfo.getUnit(), | ||
MetricInfo.Type.UPDOWNCOUNTER); | ||
|
||
extractors.add( | ||
new MetricExtractor( | ||
attrExtractor, | ||
metricInfo, | ||
attributeList.toArray(new MetricAttribute[attributeList.size()])); | ||
metricExtractors[n++] = metricExtractor; | ||
stateMetricExtractor, | ||
stateMetricInfo, | ||
stateMetricAttributes.toArray(new MetricAttribute[0]))); | ||
} | ||
|
||
return new MetricDef(group, metricExtractors); | ||
return extractors; | ||
} | ||
|
||
private static List<MetricAttribute> combineMetricAttributes( | ||
List<MetricAttribute> ownAttributes, List<MetricAttribute> metricAttributes) { | ||
|
||
Map<String, MetricAttribute> set = new HashMap<>(); | ||
for (MetricAttribute ownAttribute : ownAttributes) { | ||
set.put(ownAttribute.getAttributeName(), ownAttribute); | ||
if (ownAttributes != null) { | ||
for (MetricAttribute ownAttribute : ownAttributes) { | ||
set.put(ownAttribute.getAttributeName(), ownAttribute); | ||
} | ||
} | ||
|
||
// Let the metric level defined attributes override own attributes | ||
for (MetricAttribute metricAttribute : metricAttributes) { | ||
set.put(metricAttribute.getAttributeName(), metricAttribute); | ||
if (metricAttributes != null) { | ||
// Let the metric level defined attributes override own attributes | ||
for (MetricAttribute metricAttribute : metricAttributes) { | ||
set.put(metricAttribute.getAttributeName(), metricAttribute); | ||
} | ||
} | ||
|
||
return new ArrayList<MetricAttribute>(set.values()); | ||
return new ArrayList<>(set.values()); | ||
} | ||
|
||
private static StateMapping getEffectiveStateMapping(Metric m, JmxRule rule) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [for reviewer] for state mapping, the resulting mapping is not a combination of rule level and metric level definitions. Only one of them is used. |
||
if (m == null || m.getStateMapping().isEmpty()) { | ||
return rule.getStateMapping(); | ||
} else { | ||
return m.getStateMapping(); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[for reviewer] this allows to bypass the sample value check for the "artificial" attribute value that we need for the state metric.