Skip to content
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

Support for exposing attributes as labels #996

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 54 additions & 3 deletions collector/src/main/java/io/prometheus/jmx/JmxCollector.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,16 @@ static class Rule {
ArrayList<String> labelValues;
}

public static class MetricCustomizer {
MBeanFilter mbeanFilter;
List<String> attributesAsLabels;
}

public static class MBeanFilter {
String domain;
Map<String, String> properties;
}

private static class Config {
Integer startDelaySeconds = 0;
String jmxUrl = "";
Expand All @@ -90,7 +100,7 @@ private static class Config {
ObjectNameAttributeFilter objectNameAttributeFilter;
final List<Rule> rules = new ArrayList<>();
long lastUpdate = 0L;

List<MetricCustomizer> metricCustomizers = new ArrayList<>();
MatchedRulesCache rulesCache;
}

Expand Down Expand Up @@ -325,6 +335,29 @@ private Config loadConfig(Map<String, Object> yamlConfig) throws MalformedObject
}
}

if (yamlConfig.containsKey("metricCustomizers")) {
List<Map<String, Object>> metricCustomizersYaml =
(List<Map<String, Object>>) yamlConfig.get("metricCustomizers");
for (Map<String, Object> metricCustomizerYaml : metricCustomizersYaml) {
Map<String, Object> mbeanFilterYaml =
(Map<String, Object>) metricCustomizerYaml.get("mbeanFilter");
MBeanFilter mbeanFilter = new MBeanFilter();
mbeanFilter.domain = (String) mbeanFilterYaml.get("domain");
mbeanFilter.properties = (Map<String, String>) mbeanFilterYaml.get("properties");

List<String> attributesAsLabels =
(List<String>) metricCustomizerYaml.get("attributesAsLabels");
if (attributesAsLabels == null) {
attributesAsLabels = new ArrayList<>();
}

MetricCustomizer metricCustomizer = new MetricCustomizer();
metricCustomizer.mbeanFilter = mbeanFilter;
metricCustomizer.attributesAsLabels = attributesAsLabels;
cfg.metricCustomizers.add(metricCustomizer);
}
}

if (yamlConfig.containsKey("rules")) {
List<Map<String, Object>> configRules =
(List<Map<String, Object>>) yamlConfig.get("rules");
Expand Down Expand Up @@ -497,7 +530,8 @@ private MatchedRule defaultExport(
String help,
Double value,
double valueFactor,
String type) {
String type,
Map<String, String> attributesAsLabelsWithValues) {
StringBuilder name = new StringBuilder();
name.append(domain);
if (!beanProperties.isEmpty()) {
Expand Down Expand Up @@ -532,6 +566,7 @@ private MatchedRule defaultExport(
labelValues.add(entry.getValue());
}
}
addAttributesAsLabelsWithValuesToLabels(config, attributesAsLabelsWithValues, labelNames, labelValues);

return new MatchedRule(
fullname, matchName, type, help, labelNames, labelValues, value, valueFactor);
Expand All @@ -540,6 +575,7 @@ private MatchedRule defaultExport(
public void recordBean(
String domain,
LinkedHashMap<String, String> beanProperties,
Map<String, String> attributesAsLabelsWithValues,
LinkedList<String> attrKeys,
String attrName,
String attrType,
Expand Down Expand Up @@ -637,7 +673,8 @@ public void recordBean(
help,
value,
rule.valueFactor,
rule.type);
rule.type,
attributesAsLabelsWithValues);
addToCache(rule, matchName, matchedRule);
break;
}
Expand All @@ -659,6 +696,7 @@ public void recordBean(
// Set the labels.
ArrayList<String> labelNames = new ArrayList<>();
ArrayList<String> labelValues = new ArrayList<>();
addAttributesAsLabelsWithValuesToLabels(config, attributesAsLabelsWithValues, labelNames, labelValues);
if (rule.labelNames != null) {
for (int i = 0; i < rule.labelNames.size(); i++) {
final String unsafeLabelName = rule.labelNames.get(i);
Expand Down Expand Up @@ -733,6 +771,18 @@ public void recordBean(
}
}

private static void addAttributesAsLabelsWithValuesToLabels(Config config, Map<String, String> attributesAsLabelsWithValues, List<String> labelNames, List<String> labelValues) {
attributesAsLabelsWithValues.forEach(
(attributeAsLabelName, attributeValue) -> {
String labelName = safeName(attributeAsLabelName);
if (config.lowercaseOutputLabelNames) {
labelName = labelName.toLowerCase();
}
labelNames.add(labelName);
labelValues.add(attributeValue);
});
}

@Override
public MetricSnapshots collect() {
// Take a reference to the current config and collect with this one
Expand All @@ -753,6 +803,7 @@ public MetricSnapshots collect() {
config.includeObjectNames,
config.excludeObjectNames,
config.objectNameAttributeFilter,
config.metricCustomizers,
receiver,
jmxMBeanPropertyCache);

Expand Down
53 changes: 52 additions & 1 deletion collector/src/main/java/io/prometheus/jmx/JmxScraper.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.JMException;
Expand Down Expand Up @@ -72,6 +73,7 @@ public interface MBeanReceiver {
void recordBean(
String domain,
LinkedHashMap<String, String> beanProperties,
Map<String, String> attributesAsLabelsWithValues,
LinkedList<String> attrKeys,
String attrName,
String attrType,
Expand All @@ -85,6 +87,7 @@ void recordBean(
private final String password;
private final boolean ssl;
private final List<ObjectName> includeObjectNames, excludeObjectNames;
private final List<JmxCollector.MetricCustomizer> metricCustomizers;
private final ObjectNameAttributeFilter objectNameAttributeFilter;
private final JmxMBeanPropertyCache jmxMBeanPropertyCache;

Expand All @@ -109,6 +112,7 @@ public JmxScraper(
List<ObjectName> includeObjectNames,
List<ObjectName> excludeObjectNames,
ObjectNameAttributeFilter objectNameAttributeFilter,
List<JmxCollector.MetricCustomizer> metricCustomizers,
MBeanReceiver receiver,
JmxMBeanPropertyCache jmxMBeanPropertyCache) {
this.jmxUrl = jmxUrl;
Expand All @@ -118,6 +122,7 @@ public JmxScraper(
this.ssl = ssl;
this.includeObjectNames = includeObjectNames;
this.excludeObjectNames = excludeObjectNames;
this.metricCustomizers = metricCustomizers;
this.objectNameAttributeFilter = objectNameAttributeFilter;
this.jmxMBeanPropertyCache = jmxMBeanPropertyCache;
}
Expand Down Expand Up @@ -253,6 +258,12 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {

final String mBeanNameString = mBeanName.toString();
final String mBeanDomain = mBeanName.getDomain();
JmxCollector.MetricCustomizer metricCustomizer = getMetricCustomizer(mBeanName);
Map<String, String> attributesAsLabelsWithValues = new HashMap<>();
if (metricCustomizer != null) {
attributesAsLabelsWithValues =
getAttributesAsLabelsWithValues(metricCustomizer, attributes);
}

for (Object object : attributes) {
// The contents of an AttributeList should all be Attribute instances, but we'll verify
Expand Down Expand Up @@ -280,6 +291,7 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {
mBeanName,
mBeanDomain,
jmxMBeanPropertyCache.getKeyPropertyList(mBeanName),
attributesAsLabelsWithValues,
new LinkedList<>(),
mBeanAttributeInfo.getName(),
mBeanAttributeInfo.getType(),
Expand All @@ -300,6 +312,35 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {
}
}

private Map<String, String> getAttributesAsLabelsWithValues(JmxCollector.MetricCustomizer metricCustomizer, AttributeList attributes) {
Map<String, Object> attributeMap = attributes.asList().stream()
.collect(Collectors.toMap(Attribute::getName, Attribute::getValue));
Map<String, String> attributesAsLabelsWithValues = new HashMap<>();
for (String attributeAsLabel : metricCustomizer.attributesAsLabels) {
Object attrValue = attributeMap.get(attributeAsLabel);
if (attrValue != null) {
attributesAsLabelsWithValues.put(attributeAsLabel, attrValue.toString());
}
}
return attributesAsLabelsWithValues;
}

private JmxCollector.MetricCustomizer getMetricCustomizer(ObjectName mBeanName) {
if (!metricCustomizers.isEmpty()) {
for (JmxCollector.MetricCustomizer metricCustomizer : metricCustomizers) {
if (filterMbeanByDomainAndProperties(mBeanName, metricCustomizer)) {
return metricCustomizer;
}
}
}
return null;
}

private boolean filterMbeanByDomainAndProperties(ObjectName mBeanName, JmxCollector.MetricCustomizer metricCustomizer) {
return metricCustomizer.mbeanFilter.domain.equals(mBeanName.getDomain()) &&
mBeanName.getKeyPropertyList().entrySet().containsAll(metricCustomizer.mbeanFilter.properties.entrySet());
}

private void processAttributesOneByOne(
MBeanServerConnection beanConn,
ObjectName mbeanName,
Expand All @@ -318,6 +359,7 @@ private void processAttributesOneByOne(
mbeanName,
mbeanName.getDomain(),
jmxMBeanPropertyCache.getKeyPropertyList(mbeanName),
new HashMap<>(),
new LinkedList<>(),
attr.getName(),
attr.getType(),
Expand All @@ -335,6 +377,7 @@ private void processBeanValue(
ObjectName objectName,
String domain,
LinkedHashMap<String, String> beanProperties,
Map<String, String> attributesAsLabelsWithValues,
LinkedList<String> attrKeys,
String attrName,
String attrType,
Expand All @@ -352,7 +395,7 @@ private void processBeanValue(
}
LOGGER.log(FINE, "%s%s%s scrape: %s", domain, beanProperties, attrName, value);
this.receiver.recordBean(
domain, beanProperties, attrKeys, attrName, attrType, attrDescription, value);
domain, beanProperties, attributesAsLabelsWithValues, attrKeys, attrName, attrType, attrDescription, value);
} else if (value instanceof CompositeData) {
LOGGER.log(FINE, "%s%s%s scrape: compositedata", domain, beanProperties, attrName);
CompositeData composite = (CompositeData) value;
Expand All @@ -366,6 +409,7 @@ private void processBeanValue(
objectName,
domain,
beanProperties,
attributesAsLabelsWithValues,
attrKeys,
key,
typ,
Expand Down Expand Up @@ -432,6 +476,7 @@ private void processBeanValue(
objectName,
domain,
l2s,
attributesAsLabelsWithValues,
attrNames,
name,
typ,
Expand All @@ -452,6 +497,7 @@ private void processBeanValue(
objectName,
domain,
beanProperties,
attributesAsLabelsWithValues,
attrKeys,
attrName,
attrType,
Expand All @@ -464,6 +510,7 @@ private void processBeanValue(
objectName,
domain,
beanProperties,
attributesAsLabelsWithValues,
attrKeys,
attrName,
attrType,
Expand All @@ -479,6 +526,7 @@ private static class StdoutWriter implements MBeanReceiver {
public void recordBean(
String domain,
LinkedHashMap<String, String> beanProperties,
Map<String, String> attributesAsLabelsWithValues,
LinkedList<String> attrKeys,
String attrName,
String attrType,
Expand All @@ -503,6 +551,7 @@ public static void main(String[] args) throws Exception {
objectNames,
new LinkedList<>(),
objectNameAttributeFilter,
new LinkedList<>(),
new StdoutWriter(),
new JmxMBeanPropertyCache())
.doScrape();
Expand All @@ -515,6 +564,7 @@ public static void main(String[] args) throws Exception {
objectNames,
new LinkedList<>(),
objectNameAttributeFilter,
new LinkedList<>(),
new StdoutWriter(),
new JmxMBeanPropertyCache())
.doScrape();
Expand All @@ -527,6 +577,7 @@ public static void main(String[] args) throws Exception {
objectNames,
new LinkedList<>(),
objectNameAttributeFilter,
new LinkedList<>(),
new StdoutWriter(),
new JmxMBeanPropertyCache())
.doScrape();
Expand Down