Skip to content

Commit

Permalink
[jmxattribute] generate alias from regexp match
Browse files Browse the repository at this point in the history
[jmxattribute] generate alias from regexp match
  • Loading branch information
yannmh committed Apr 29, 2016
2 parents 8689358 + a4a7f91 commit 8719979
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 59 deletions.
110 changes: 108 additions & 2 deletions src/main/java/org/datadog/jmxfetch/JMXAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.management.AttributeNotFoundException;
Expand All @@ -24,13 +25,16 @@

public abstract class JMXAttribute {

protected static final String ALIAS = "alias";
protected static final String METRIC_TYPE = "metric_type";
private final static Logger LOGGER = Logger.getLogger(JMXAttribute.class.getName());
private static final List<String> EXCLUDED_BEAN_PARAMS = Arrays.asList("domain", "domain_regex", "bean_name", "bean", "bean_regex", "attribute");
private static final String FIRST_CAP_PATTERN = "(.)([A-Z][a-z]+)";
private static final String ALL_CAP_PATTERN = "([a-z0-9])([A-Z])";
private static final String METRIC_REPLACEMENT = "([^a-zA-Z0-9_.]+)|(^[^a-zA-Z]+)";
private static final String DOT_UNDERSCORE = "_*\\._*";
protected static final String CASSANDRA_DOMAIN = "org.apache.cassandra.metrics";

private MBeanAttributeInfo attribute;
private Connection connection;
private ObjectName beanName;
Expand Down Expand Up @@ -351,6 +355,108 @@ MBeanAttributeInfo getAttribute() {
return attribute;
}

public ObjectName getBeanName() {
return beanName;
}

/**
* Get attribute alias.
*
* In order, tries to:
* * Use `alias_match` to generate an alias with a regular expression
* * Use `alias` directly
* * Create an generic alias prefixed with user's `metric_prefix` preference or default to `jmx`
*
* Argument(s):
* * (Optional) `field`
* `Null` for `JMXSimpleAttribute`.
*/
protected String getAlias(String field) {
String alias = null;

Filter include = getMatchingConf().getInclude();
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();

String fullAttributeName =(field!=null)?(getAttribute().getName() + "." + field):(getAttribute().getName());

if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
alias = getUserAlias(attribute, fullAttributeName);
} else if (conf.get("metric_prefix") != null) {
alias = conf.get("metric_prefix") + "." + getDomain() + "." + fullAttributeName;
} else if (getDomain().startsWith("org.apache.cassandra")) {
alias = getCassandraAlias();
}

//If still null - generate generic alias,
if (alias == null) {
alias = "jmx." + getDomain() + "." + fullAttributeName;
}
alias = convertMetricName(alias);
return alias;
}

/**
* Metric name aliasing specific to Cassandra.
*
* * (Default) `cassandra_aliasing` == False.
* Legacy aliasing: drop `org.apache` prefix.
* * `cassandra_aliasing` == True
* Comply with CASSANDRA-4009
*
* More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
*/
private String getCassandraAlias() {
if (renameCassandraMetrics()) {
Map<String, String> beanParameters = getBeanParameters();
String metricName = beanParameters.get("name");
String attributeName = getAttributeName();
if (attributeName.equals("Value")) {
return "cassandra." + metricName;
}
return "cassandra." + metricName + "." + attributeName;
}
//Deprecated Cassandra metric. Remove domain prefix.
return getDomain().replace("org.apache.", "") + "." + getAttributeName();
}

/**
* Retrieve user defined alias. Substitute regular expression named groups.
*
* Example:
* ```
* bean: org.datadog.jmxfetch.test:foo=Bar,qux=Baz
* attribute:
* toto:
* alias: my.metric.$foo.$attribute
* ```
* returns a metric name `my.metric.bar.toto`
*/
private String getUserAlias(LinkedHashMap<String, LinkedHashMap<String, String>> attribute, String fullAttributeName){
String alias = attribute.get(fullAttributeName).get(ALIAS);

// Bean parameters
for (Map.Entry<String, String> param : beanParameters.entrySet()) {
alias = alias.replace("$" + param.getKey(), param.getValue());
}

// Attribute & domain
alias = alias.replace("$attribute", fullAttributeName);
alias = alias.replace("$domain", domain);

return alias;
}

/**
* Overload `getAlias` method.
*
* Note: used for `JMXSimpleAttribute` only, as `field` is null.
*/
protected String getAlias(){
return getAlias(null);
}


@SuppressWarnings("unchecked")
protected String[] getTags() {
if(tags != null) {
Expand Down
16 changes: 0 additions & 16 deletions src/main/java/org/datadog/jmxfetch/JMXComplexAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
@SuppressWarnings("unchecked")
public class JMXComplexAttribute extends JMXAttribute {

public static final String ALIAS = "alias";
public static final String METRIC_TYPE = "metric_type";
private HashMap<String, HashMap<String, Object>> subAttributeList;

public JMXComplexAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
Expand Down Expand Up @@ -112,20 +110,6 @@ private Object getMetricType(String subAttribute) {
return metricType;
}

private String getAlias(String subAttribute) {
String subAttributeName = getAttribute().getName() + "." + subAttribute;

Filter include = getMatchingConf().getInclude();
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();
if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
return ((LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute())).get(subAttributeName).get(ALIAS);
} else if (conf.get("metric_prefix") != null) {
return conf.get("metric_prefix") + "." + getDomain() + "." + subAttributeName;
}
return "jmx." + getDomain() + "." + subAttributeName;
}


@Override
public boolean match(Configuration configuration) {
if (!matchDomain(configuration)
Expand Down
41 changes: 1 addition & 40 deletions src/main/java/org/datadog/jmxfetch/JMXSimpleAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

@SuppressWarnings("unchecked")
public class JMXSimpleAttribute extends JMXAttribute {

private String alias;
private String metricType;

public JMXSimpleAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
Expand All @@ -39,7 +37,6 @@ public LinkedList<HashMap<String, Object>> getMetrics() throws AttributeNotFound
return metrics;
}


public boolean match(Configuration configuration) {
return matchDomain(configuration)
&& matchBean(configuration)
Expand Down Expand Up @@ -82,49 +79,13 @@ private boolean matchAttribute(Configuration configuration) {
return false;
}

private String getAlias() {
Filter include = getMatchingConf().getInclude();
LinkedHashMap<String, Object> conf = getMatchingConf().getConf();
if (alias != null) {
return alias;
} else if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
alias = attribute.get(getAttribute().getName()).get("alias");
} else if (conf.get("metric_prefix") != null) {
alias = conf.get("metric_prefix") + "." + getDomain() + "." + getAttributeName();
} else if (getDomain().startsWith("org.apache.cassandra")) {
alias = getCassandraAlias();
}

//If still null - generate generic alias,
if (alias == null) {
alias = "jmx." + getDomain() + "." + getAttributeName();
}
alias = convertMetricName(alias);
return alias;
}

private String getCassandraAlias() {
if (renameCassandraMetrics()) {
Map<String, String> beanParameters = getBeanParameters();
String metricName = beanParameters.get("name");
String attributeName = getAttributeName();
if (attributeName.equals("Value")) {
return "cassandra." + metricName;
}
return "cassandra." + metricName + "." + attributeName;
}
//Deprecated Cassandra metric. Remove domain prefix.
return getDomain().replace("org.apache.", "") + "." + getAttributeName();
}

private String getMetricType() {
Filter include = getMatchingConf().getInclude();
if (metricType != null) {
return metricType;
} else if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String, LinkedHashMap<String, String>>) (include.getAttribute());
metricType = attribute.get(getAttributeName()).get("metric_type");
metricType = attribute.get(getAttributeName()).get(METRIC_TYPE);
if (metricType == null) {
metricType = attribute.get(getAttributeName()).get("type");
}
Expand Down
31 changes: 30 additions & 1 deletion src/test/java/org/datadog/jmxfetch/TestApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,39 @@ public void testBeanTags() throws Exception {

assertMetric("this.is.100", tags, 6);
}
/**
* Generate metric aliases from a `alias_match` regular expression.
*/
@Test
public void testRegexpAliasing() throws Exception {
// Expose MBeans
registerMBean(new SimpleTestJavaApp(), "org.datadog.jmxfetch.test:foo=Bar,qux=Baz");
initApplication("jmx_alias_match.yaml");

// Collect metrics
run();
LinkedList<HashMap<String, Object>> metrics = getMetrics();

// Assertions

// 15 metrics = 13 from `java.lang` + 2 from the user configuration file
assertEquals(15, metrics.size());

// Metric aliases are generated from `alias_match`
List<String> tags = Arrays.asList(
"jmx_domain:org.datadog.jmxfetch.test",
"instance:jmx_test_instance",
"foo:Bar",
"qux:Baz"
);

assertMetric("this.is.100.bar.baz", tags, 4);
assertMetric("org.datadog.jmxfetch.test.baz.hashmap.thisis0", tags, 4);
}

/**
* Check JMXFetch Cassandra metric aliasing logic, i.e. compliant with CASSANDRA-4009
* when `cassandra4009` flag is enabled, or default.
* when `cassandra_aliasing` flag is enabled, or default.
*
* More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
*/
Expand Down
15 changes: 15 additions & 0 deletions src/test/resources/jmx_alias_match.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
init_config:

instances:
- process_name_regex: .*surefire.*
name: jmx_test_instance
conf:
- include:
domain: org.datadog.jmxfetch.test
attribute:
ShouldBe100:
metric_type: gauge
alias: this.is.100.$foo.$qux
Hashmap.thisis0:
metric_type: gauge
alias: $domain.$qux.$attribute

0 comments on commit 8719979

Please sign in to comment.