Skip to content

Commit 5e80d71

Browse files
committed
[jmxattribute] unique getAlias method & test
* Refactor `getAlias` logic from `JMXSimpleAttribute` & `JMXComplexAttribute` to `JMXAttribute` * Add `alias_match` support to `JMXComplexAttribute`(s) * Test coverage `alias_match`
1 parent 737050f commit 5e80d71

File tree

5 files changed

+134
-69
lines changed

5 files changed

+134
-69
lines changed

src/main/java/org/datadog/jmxfetch/JMXAttribute.java

+85-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import java.util.ArrayList;
55
import java.util.Arrays;
66
import java.util.Collection;
7+
import java.util.concurrent.atomic.AtomicInteger;
8+
import java.util.concurrent.atomic.AtomicLong;
79
import java.util.HashMap;
810
import java.util.LinkedHashMap;
911
import java.util.LinkedList;
1012
import java.util.List;
1113
import java.util.Map;
12-
import java.util.concurrent.atomic.AtomicInteger;
13-
import java.util.concurrent.atomic.AtomicLong;
14+
import java.util.regex.Matcher;
1415
import java.util.regex.Pattern;
1516

1617
import javax.management.AttributeNotFoundException;
@@ -24,13 +25,16 @@
2425

2526
public abstract class JMXAttribute {
2627

28+
protected static final String ALIAS = "alias";
29+
protected static final String METRIC_TYPE = "metric_type";
2730
private final static Logger LOGGER = Logger.getLogger(JMXAttribute.class.getName());
2831
private static final List<String> EXCLUDED_BEAN_PARAMS = Arrays.asList("domain", "domain_regex", "bean_name", "bean", "bean_regex", "attribute");
2932
private static final String FIRST_CAP_PATTERN = "(.)([A-Z][a-z]+)";
3033
private static final String ALL_CAP_PATTERN = "([a-z0-9])([A-Z])";
3134
private static final String METRIC_REPLACEMENT = "([^a-zA-Z0-9_.]+)|(^[^a-zA-Z]+)";
3235
private static final String DOT_UNDERSCORE = "_*\\._*";
3336
protected static final String CASSANDRA_DOMAIN = "org.apache.cassandra.metrics";
37+
3438
private MBeanAttributeInfo attribute;
3539
private Connection connection;
3640
private ObjectName beanName;
@@ -355,6 +359,85 @@ public ObjectName getBeanName() {
355359
return beanName;
356360
}
357361

362+
/**
363+
* Get attribute alias.
364+
*
365+
* In order, tries to:
366+
* * Use `alias_match` to generate an alias with a regular expression
367+
* * Use `alias` directly
368+
* * Create an generic alias prefixed with user's `metric_prefix` preference or default to `jmx`
369+
*
370+
* Argument(s):
371+
* * (Optional) `field`
372+
* `Null` for `JMXSimpleAttribute`.
373+
*/
374+
protected String getAlias(String field) {
375+
String alias = null;
376+
377+
Filter include = getMatchingConf().getInclude();
378+
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();
379+
380+
String fullAttributeName =(field!=null)?(getAttribute().getName() + "." + field):(getAttribute().getName());
381+
382+
if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
383+
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
384+
if (attribute.get(fullAttributeName).get("alias_match") != null) {
385+
Pattern p = Pattern.compile(attribute.get(fullAttributeName).get("alias_match"));
386+
Matcher m = p.matcher(getBeanName().getCanonicalName() + "." + fullAttributeName);
387+
if (m.find()) {
388+
alias = m.replaceFirst(attribute.get(fullAttributeName).get(ALIAS));
389+
}
390+
} else {
391+
alias = attribute.get(fullAttributeName).get(ALIAS);
392+
}
393+
} else if (conf.get("metric_prefix") != null) {
394+
alias = conf.get("metric_prefix") + "." + getDomain() + "." + fullAttributeName;
395+
} else if (getDomain().startsWith("org.apache.cassandra")) {
396+
alias = getCassandraAlias();
397+
}
398+
399+
//If still null - generate generic alias,
400+
if (alias == null) {
401+
alias = "jmx." + getDomain() + "." + fullAttributeName;
402+
}
403+
alias = convertMetricName(alias);
404+
return alias;
405+
}
406+
407+
/**
408+
* Metric name aliasing specific to Cassandra.
409+
*
410+
* * (Default) `cassandra_aliasing` == False.
411+
* Legacy aliasing: drop `org.apache` prefix.
412+
* * `cassandra_aliasing` == True
413+
* Comply with CASSANDRA-4009
414+
*
415+
* More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
416+
*/
417+
private String getCassandraAlias() {
418+
if (renameCassandraMetrics()) {
419+
Map<String, String> beanParameters = getBeanParameters();
420+
String metricName = beanParameters.get("name");
421+
String attributeName = getAttributeName();
422+
if (attributeName.equals("Value")) {
423+
return "cassandra." + metricName;
424+
}
425+
return "cassandra." + metricName + "." + attributeName;
426+
}
427+
//Deprecated Cassandra metric. Remove domain prefix.
428+
return getDomain().replace("org.apache.", "") + "." + getAttributeName();
429+
}
430+
431+
/**
432+
* Overload `getAlias` method.
433+
*
434+
* Note: used for `JMXSimpleAttribute` only, as `field` is null.
435+
*/
436+
protected String getAlias(){
437+
return getAlias(null);
438+
}
439+
440+
358441
@SuppressWarnings("unchecked")
359442
protected String[] getTags() {
360443
if(tags != null) {

src/main/java/org/datadog/jmxfetch/JMXComplexAttribute.java

-16
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
@SuppressWarnings("unchecked")
2020
public class JMXComplexAttribute extends JMXAttribute {
2121

22-
public static final String ALIAS = "alias";
23-
public static final String METRIC_TYPE = "metric_type";
2422
private HashMap<String, HashMap<String, Object>> subAttributeList;
2523

2624
public JMXComplexAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
@@ -112,20 +110,6 @@ private Object getMetricType(String subAttribute) {
112110
return metricType;
113111
}
114112

115-
private String getAlias(String subAttribute) {
116-
String subAttributeName = getAttribute().getName() + "." + subAttribute;
117-
118-
Filter include = getMatchingConf().getInclude();
119-
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();
120-
if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
121-
return ((LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute())).get(subAttributeName).get(ALIAS);
122-
} else if (conf.get("metric_prefix") != null) {
123-
return conf.get("metric_prefix") + "." + getDomain() + "." + subAttributeName;
124-
}
125-
return "jmx." + getDomain() + "." + subAttributeName;
126-
}
127-
128-
129113
@Override
130114
public boolean match(Configuration configuration) {
131115
if (!matchDomain(configuration)

src/main/java/org/datadog/jmxfetch/JMXSimpleAttribute.java

+1-50
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
import java.util.LinkedHashMap;
77
import java.util.LinkedList;
88
import java.util.Map;
9-
import java.util.regex.Pattern;
10-
import java.util.regex.Matcher;
119

1210
import javax.management.AttributeNotFoundException;
1311
import javax.management.InstanceNotFoundException;
@@ -18,8 +16,6 @@
1816

1917
@SuppressWarnings("unchecked")
2018
public class JMXSimpleAttribute extends JMXAttribute {
21-
22-
private String alias;
2319
private String metricType;
2420

2521
public JMXSimpleAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
@@ -41,7 +37,6 @@ public LinkedList<HashMap<String, Object>> getMetrics() throws AttributeNotFound
4137
return metrics;
4238
}
4339

44-
4540
public boolean match(Configuration configuration) {
4641
return matchDomain(configuration)
4742
&& matchBean(configuration)
@@ -84,57 +79,13 @@ private boolean matchAttribute(Configuration configuration) {
8479
return false;
8580
}
8681

87-
private String getAlias() {
88-
Filter include = getMatchingConf().getInclude();
89-
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();
90-
if (alias != null) {
91-
return alias;
92-
} else if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
93-
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
94-
if (attribute.get(getAttribute().getName()).get("alias_match") != null) {
95-
Pattern p = Pattern.compile(attribute.get(getAttribute().getName()).get("alias_match"));
96-
Matcher m = p.matcher(getBeanName().getCanonicalName() + "." + getAttribute().getName());
97-
if (m.find()) {
98-
alias = m.replaceFirst(attribute.get(getAttribute().getName()).get("alias"));
99-
}
100-
} else {
101-
alias = attribute.get(getAttribute().getName()).get("alias");
102-
}
103-
} else if (conf.get("metric_prefix") != null) {
104-
alias = conf.get("metric_prefix") + "." + getDomain() + "." + getAttributeName();
105-
} else if (getDomain().startsWith("org.apache.cassandra")) {
106-
alias = getCassandraAlias();
107-
}
108-
109-
//If still null - generate generic alias,
110-
if (alias == null) {
111-
alias = "jmx." + getDomain() + "." + getAttributeName();
112-
}
113-
alias = convertMetricName(alias);
114-
return alias;
115-
}
116-
117-
private String getCassandraAlias() {
118-
if (renameCassandraMetrics()) {
119-
Map<String, String> beanParameters = getBeanParameters();
120-
String metricName = beanParameters.get("name");
121-
String attributeName = getAttributeName();
122-
if (attributeName.equals("Value")) {
123-
return "cassandra." + metricName;
124-
}
125-
return "cassandra." + metricName + "." + attributeName;
126-
}
127-
//Deprecated Cassandra metric. Remove domain prefix.
128-
return getDomain().replace("org.apache.", "") + "." + getAttributeName();
129-
}
130-
13182
private String getMetricType() {
13283
Filter include = getMatchingConf().getInclude();
13384
if (metricType != null) {
13485
return metricType;
13586
} else if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
13687
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
137-
metricType = attribute.get(getAttributeName()).get("metric_type");
88+
metricType = attribute.get(getAttributeName()).get(METRIC_TYPE);
13889
if (metricType == null) {
13990
metricType = attribute.get(getAttributeName()).get("type");
14091
}

src/test/java/org/datadog/jmxfetch/TestApp.java

+31-1
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,40 @@ public void testBeanTags() throws Exception {
4646

4747
assertMetric("this.is.100", tags, 6);
4848
}
49+
/**
50+
* Generate metric aliases from a `alias_match` regular expression.
51+
*/
52+
@Test
53+
public void testRegexpAliasing() throws Exception {
54+
// Expose MBeans
55+
registerMBean(new SimpleTestJavaApp(), "org.datadog.jmxfetch.test:foo=Bar,qux=Baz");
56+
initApplication("jmx_alias_match.yaml");
57+
58+
// Collect metrics
59+
run();
60+
LinkedList<HashMap<String, Object>> metrics = getMetrics();
61+
62+
// Assertions
63+
64+
// 15 metrics = 13 from `java.lang` + 2 from the user configuration file
65+
assertEquals(15, metrics.size());
66+
67+
// Metric aliases are generated from `alias_match`
68+
List<String> tags = Arrays.asList(
69+
"jmx_domain:org.datadog.jmxfetch.test",
70+
"instance:jmx_test_instance",
71+
"foo:Bar",
72+
"qux:Baz"
73+
);
74+
75+
assertMetric("this.is.100.bar", tags, 4);
76+
assertMetric("baz.this.is.0", tags, 4);
77+
78+
}
4979

5080
/**
5181
* Check JMXFetch Cassandra metric aliasing logic, i.e. compliant with CASSANDRA-4009
52-
* when `cassandra4009` flag is enabled, or default.
82+
* when `cassandra_aliasing` flag is enabled, or default.
5383
*
5484
* More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
5585
*/
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
init_config:
2+
3+
instances:
4+
- process_name_regex: .*surefire.*
5+
name: jmx_test_instance
6+
conf:
7+
- include:
8+
domain: org.datadog.jmxfetch.test
9+
attribute:
10+
ShouldBe100:
11+
metric_type: gauge
12+
alias_match: '[a-z.]*:foo=([a-zA-Z]*).*'
13+
alias: this.is.100.$1
14+
Hashmap.thisis0:
15+
metric_type: gauge
16+
alias_match: '.*qux=([a-zA-Z]*).*'
17+
alias: $1.this.is.0

0 commit comments

Comments
 (0)