Skip to content

Commit 3cef693

Browse files
committed
Replace pattern matching with string comparison
1 parent 3071423 commit 3cef693

File tree

3 files changed

+76
-51
lines changed

3 files changed

+76
-51
lines changed

collector/src/main/java/io/prometheus/jmx/JmxCollector.java

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,16 @@ static class Rule {
7171
String type = "UNKNOWN";
7272
ArrayList<String> labelNames;
7373
ArrayList<String> labelValues;
74-
ArrayList<String> attributesAsLabels;
74+
}
75+
76+
public static class MetricCustomizer {
77+
MBeanFilter mbeanFilter;
78+
List<String> attributesAsLabels;
79+
}
80+
81+
public static class MBeanFilter {
82+
String domain;
83+
Map<String, String> properties;
7584
}
7685

7786
private static class Config {
@@ -87,7 +96,7 @@ private static class Config {
8796
ObjectNameAttributeFilter objectNameAttributeFilter;
8897
List<Rule> rules = new ArrayList<>();
8998
long lastUpdate = 0L;
90-
99+
List<MetricCustomizer> metricCustomizers = new ArrayList<>();
91100
MatchedRulesCache rulesCache;
92101
}
93102

@@ -297,6 +306,29 @@ private Config loadConfig(Map<String, Object> yamlConfig) throws MalformedObject
297306
}
298307
}
299308

309+
if (yamlConfig.containsKey("metricCustomizers")) {
310+
List<Map<String, Object>> metricCustomizersYaml =
311+
(List<Map<String, Object>>) yamlConfig.get("metricCustomizers");
312+
for (Map<String, Object> metricCustomizerYaml : metricCustomizersYaml) {
313+
Map<String, Object> mbeanFilterYaml =
314+
(Map<String, Object>) metricCustomizerYaml.get("mbeanFilter");
315+
MBeanFilter mbeanFilter = new MBeanFilter();
316+
mbeanFilter.domain = (String) mbeanFilterYaml.get("domain");
317+
mbeanFilter.properties = (Map<String, String>) mbeanFilterYaml.get("properties");
318+
319+
List<String> attributesAsLabels =
320+
(List<String>) metricCustomizerYaml.get("attributesAsLabels");
321+
if (attributesAsLabels == null) {
322+
attributesAsLabels = new ArrayList<>();
323+
}
324+
325+
MetricCustomizer metricCustomizer = new MetricCustomizer();
326+
metricCustomizer.mbeanFilter = mbeanFilter;
327+
metricCustomizer.attributesAsLabels = attributesAsLabels;
328+
cfg.metricCustomizers.add(metricCustomizer);
329+
}
330+
}
331+
300332
if (yamlConfig.containsKey("rules")) {
301333
List<Map<String, Object>> configRules =
302334
(List<Map<String, Object>>) yamlConfig.get("rules");
@@ -349,13 +381,6 @@ private Config loadConfig(Map<String, Object> yamlConfig) throws MalformedObject
349381
}
350382
}
351383

352-
if (yamlRule.containsKey("attributesAsLabels")) {
353-
List<String> attributes = (List<String>) yamlRule.get("attributesAsLabels");
354-
rule.attributesAsLabels = new ArrayList<>();
355-
if (attributes != null) {
356-
rule.attributesAsLabels.addAll(attributes);
357-
}
358-
}
359384
// Validation.
360385
if ((rule.labelNames != null || rule.help != null) && rule.name == null) {
361386
throw new IllegalArgumentException(
@@ -750,7 +775,7 @@ public MetricSnapshots collect() {
750775
config.includeObjectNames,
751776
config.excludeObjectNames,
752777
config.objectNameAttributeFilter,
753-
config.rules,
778+
config.metricCustomizers,
754779
receiver,
755780
jmxMBeanPropertyCache);
756781

collector/src/main/java/io/prometheus/jmx/JmxScraper.java

Lines changed: 29 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.Optional;
3232
import java.util.Set;
3333
import java.util.TreeSet;
34-
import java.util.regex.Matcher;
3534
import java.util.stream.Collectors;
3635
import javax.management.Attribute;
3736
import javax.management.AttributeList;
@@ -74,7 +73,7 @@ void recordBean(
7473
private final String password;
7574
private final boolean ssl;
7675
private final List<ObjectName> includeObjectNames, excludeObjectNames;
77-
private final List<JmxCollector.Rule> rules;
76+
private final List<JmxCollector.MetricCustomizer> metricCustomizers;
7877
private final ObjectNameAttributeFilter objectNameAttributeFilter;
7978
private final JmxMBeanPropertyCache jmxMBeanPropertyCache;
8079

@@ -86,7 +85,7 @@ public JmxScraper(
8685
List<ObjectName> includeObjectNames,
8786
List<ObjectName> excludeObjectNames,
8887
ObjectNameAttributeFilter objectNameAttributeFilter,
89-
List<JmxCollector.Rule> rules,
88+
List<JmxCollector.MetricCustomizer> metricCustomizers,
9089
MBeanReceiver receiver,
9190
JmxMBeanPropertyCache jmxMBeanPropertyCache) {
9291
this.jmxUrl = jmxUrl;
@@ -96,7 +95,7 @@ public JmxScraper(
9695
this.ssl = ssl;
9796
this.includeObjectNames = includeObjectNames;
9897
this.excludeObjectNames = excludeObjectNames;
99-
this.rules = rules;
98+
this.metricCustomizers = metricCustomizers;
10099
this.objectNameAttributeFilter = objectNameAttributeFilter;
101100
this.jmxMBeanPropertyCache = jmxMBeanPropertyCache;
102101
}
@@ -225,7 +224,12 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {
225224

226225
final String mBeanNameString = mBeanName.toString();
227226
final String mBeanDomain = mBeanName.getDomain();
228-
Map<String, Object> attributeMap = attributes.asList().stream().collect(Collectors.toMap(Attribute::getName, Attribute::getValue));
227+
JmxCollector.MetricCustomizer metricCustomizer = getMetricCustomizer(mBeanName);
228+
Map<String, String> attributesAsLabelsWithValues = new HashMap<>();
229+
if (metricCustomizer != null) {
230+
attributesAsLabelsWithValues =
231+
getAttributesAsLabelsWithValues(metricCustomizer, attributes);
232+
}
229233

230234
for (Object object : attributes) {
231235
// The contents of an AttributeList should all be Attribute instances, but we'll verify
@@ -246,8 +250,6 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {
246250
continue;
247251
}
248252

249-
Map<String, String> attributesAsLabelsWithValues = getAttributesAsLabelsWithValues(mBeanName, attribute, attributeMap);
250-
251253
MBeanAttributeInfo mBeanAttributeInfo =
252254
name2MBeanAttributeInfo.get(attribute.getName());
253255
LOGGER.log(FINE, "%s_%s process", mBeanName, mBeanAttributeInfo.getName());
@@ -276,43 +278,33 @@ private void scrapeBean(MBeanServerConnection beanConn, ObjectName mBeanName) {
276278
}
277279
}
278280

279-
private Map<String, String> getAttributesAsLabelsWithValues(ObjectName mBeanName, Attribute attribute, Map<String, Object> attributeMap) {
280-
JmxCollector.Rule matchedRule = null;
281-
for (JmxCollector.Rule rule : rules) {
282-
if (rule.pattern != null) {
283-
Object matchBeanValue = rule.cache ? "<cache>" : attribute.getValue();
284-
List<String> attrKeys = new LinkedList<>();
285-
if (attribute.getValue() instanceof TabularData || attribute.getValue() instanceof CompositeData) {
286-
attrKeys.add(attribute.getName());
287-
}
288-
String beanName = mBeanName.getDomain()
289-
+ angleBrackets(jmxMBeanPropertyCache.getKeyPropertyList(mBeanName).toString())
290-
+ angleBrackets(attrKeys.toString());
291-
String matchName = beanName + attribute.getName() + ": " + matchBeanValue;
292-
Matcher matcher = rule.pattern.matcher(matchName);
293-
if (matcher.matches() && rule.attributesAsLabels != null) {
294-
matchedRule = rule;
295-
}
296-
} else if (rule.name == null) {
297-
matchedRule = rule;
281+
private Map<String, String> getAttributesAsLabelsWithValues(JmxCollector.MetricCustomizer metricCustomizer, AttributeList attributes) {
282+
Map<String, Object> attributeMap = attributes.asList().stream()
283+
.collect(Collectors.toMap(Attribute::getName, Attribute::getValue));
284+
Map<String, String> attributesAsLabelsWithValues = new HashMap<>();
285+
for (String attributeAsLabel : metricCustomizer.attributesAsLabels) {
286+
Object attrValue = attributeMap.get(attributeAsLabel);
287+
if (attrValue != null) {
288+
attributesAsLabelsWithValues.put(attributeAsLabel, attrValue.toString());
298289
}
299290
}
300-
Map<String, String> attributesAsLabelsWithValues = new HashMap<>();
301-
if (matchedRule != null) {
302-
for (String attributeAsLabel : matchedRule.attributesAsLabels) {
303-
Object attrValue = attributeMap.get(attributeAsLabel);
304-
if (attrValue != null) {
305-
attributesAsLabelsWithValues.put(
306-
attributeAsLabel,
307-
attrValue.toString());
291+
return attributesAsLabelsWithValues;
292+
}
293+
294+
private JmxCollector.MetricCustomizer getMetricCustomizer(ObjectName mBeanName) {
295+
if (!metricCustomizers.isEmpty()) {
296+
for (JmxCollector.MetricCustomizer metricCustomizer : metricCustomizers) {
297+
if (filterMbeanByDomainAndProperties(mBeanName, metricCustomizer)) {
298+
return metricCustomizer;
308299
}
309300
}
310301
}
311-
return attributesAsLabelsWithValues;
302+
return null;
312303
}
313304

314-
private String angleBrackets(String s) {
315-
return "<" + s.substring(1, s.length() - 1) + ">";
305+
private boolean filterMbeanByDomainAndProperties(ObjectName mBeanName, JmxCollector.MetricCustomizer metricCustomizer) {
306+
return metricCustomizer.mbeanFilter.domain.equals(mBeanName.getDomain()) &&
307+
mBeanName.getKeyPropertyList().entrySet().containsAll(metricCustomizer.mbeanFilter.properties.entrySet());
316308
}
317309

318310
private void processAttributesOneByOne(

docs/README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ excludeObjectNameAttributes:
109109
"java.lang:type=Runtime":
110110
- "ClassPath"
111111
- "SystemProperties"
112+
metricCustomizers:
113+
- mbeanFilter:
114+
domain: org.apache.cassandra.metrics
115+
properties:
116+
type: <type>
117+
attributesAsLabels:
118+
- string1
119+
- string2
112120
rules:
113121
- pattern: 'org.apache.cassandra.metrics<type=(\w+), name=(\w+)><>Value: (\d+)'
114122
name: cassandra_$1_$2
@@ -119,9 +127,6 @@ rules:
119127
cache: false
120128
type: GAUGE
121129
attrNameSnakeCase: false
122-
attributesAsLabels:
123-
- string1
124-
- string2
125130
126131
```
127132
Name | Description
@@ -148,7 +153,10 @@ labels | A map of label name to label value pairs. Capture groups fro
148153
help | Help text for the metric. Capture groups from `pattern` can be used. `name` must be set to use this. Defaults to the mBean attribute description, domain, and name of the attribute.
149154
cache | Whether to cache bean name expressions to rule computation (match and mismatch). Not recommended for rules matching on bean value, as only the value from the first scrape will be cached and re-used. This can increase performance when collecting a lot of mbeans. Defaults to `false`.
150155
type | The type of the metric, can be `GAUGE`, `COUNTER` or `UNTYPED`. `name` must be set to use this. Defaults to `UNTYPED`.
151-
attributesAsLabels | A list of attributes from an mBean which will be added as labels for all the metrics of that mBean. Defaults to none.
156+
metricCustomizers | A list of objects that contain `mbeanFilter` and `attributesAsLabels`. For those mbeans that match the filter, the items in the `attributesAsLabels` list will be added as attributes to the existing metrics.
157+
domain | Domain of an mbean.
158+
properties | Properties of an mbean.
159+
attributesAsLabels | List of elements to be added as attributes to existing metrics.
152160

153161
Metric names and label names are sanitized. All characters other than `[a-zA-Z0-9:_]` are replaced with underscores,
154162
and adjacent underscores are collapsed. There's no limitations on label values or the help text.

0 commit comments

Comments
 (0)