Skip to content

Commit

Permalink
Merge pull request #79 from DataDog/yann/cassandra-metric-mapping-update
Browse files Browse the repository at this point in the history
Map Cassandra new metric name structure
  • Loading branch information
yannmh committed Nov 3, 2015
2 parents fc8ce63 + 941f6ec commit 0bc1a29
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 40 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ target/*
.classpath
.project
/target
.idea
*.iml

*.ucls

Expand Down
3 changes: 1 addition & 2 deletions src/main/java/org/datadog/jmxfetch/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ private static HashMap<String, LinkedList<Filter>> getIncludeFiltersByDomain(Lin
String[] splitBeanName = beanName.split(":");
String domain = splitBeanName[0];
String rawBeanParameters = splitBeanName[1];
LinkedList<String> beanParameters = new LinkedList<String>(Arrays.asList(new String(rawBeanParameters).replace("=", ":").split(",")));
HashMap<String, String> beanParametersHash = JMXAttribute.getBeanParametersHash(beanParameters);
HashMap<String, String> beanParametersHash = JMXAttribute.getBeanParametersHash(rawBeanParameters);
beanParametersHash.put("domain", domain);
filters.add(new Filter(beanParametersHash));
}
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/org/datadog/jmxfetch/Instance.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class Instance {
private boolean limitReached;
private Connection connection;
private AppConfig appConfig;
private Boolean cassandraAliasing;


public Instance(Instance instance, AppConfig appConfig) {
Expand Down Expand Up @@ -95,6 +96,13 @@ public Instance(LinkedHashMap<String, Object> yamlInstance, LinkedHashMap<String
}
}

// Alternative aliasing for CASSANDRA-4009 metrics
// More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
this.cassandraAliasing = (Boolean) yaml.get("cassandra_aliasing");
if (this.cassandraAliasing == null){
this.cassandraAliasing = false;
}

// In case the configuration to match beans is not specified in the "instance" parameter but in the initConfig one
Object yamlConf = this.yaml.get("conf");
if (yamlConf == null && this.initConfig != null) {
Expand Down Expand Up @@ -221,7 +229,7 @@ private void getMatchingAttributes() {
String attributeType = attributeInfo.getType();
if (SIMPLE_TYPES.contains(attributeType)) {
LOGGER.debug("Attribute: " + beanName + " : " + attributeInfo + " has attributeInfo simple type");
jmxAttribute = new JMXSimpleAttribute(attributeInfo, beanName, instanceName, connection, tags);
jmxAttribute = new JMXSimpleAttribute(attributeInfo, beanName, instanceName, connection, tags, cassandraAliasing);
} else if (COMPOSED_TYPES.contains(attributeType)) {
LOGGER.debug("Attribute: " + beanName + " : " + attributeInfo + " has attributeInfo complex type");
jmxAttribute = new JMXComplexAttribute(attributeInfo, beanName, instanceName, connection, tags);
Expand Down
67 changes: 54 additions & 13 deletions src/main/java/org/datadog/jmxfetch/JMXAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
Expand All @@ -29,6 +30,7 @@ public abstract class JMXAttribute {
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 All @@ -40,49 +42,60 @@ public abstract class JMXAttribute {
protected String[] tags;
private Configuration matchingConf;
private LinkedList<String> defaultTagsList;
private Boolean cassandraAliasing;

JMXAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
Connection connection, HashMap<String, String> instanceTags) {
Connection connection, HashMap<String, String> instanceTags, Boolean cassandraAliasing) {
this.attribute = attribute;
this.beanName = beanName;
this.matchingConf = null;
this.connection = connection;
this.attributeName = attribute.getName();
this.beanStringName = beanName.toString();
this.cassandraAliasing = cassandraAliasing;

// A bean name is formatted like that: org.apache.cassandra.db:type=Caches,keyspace=system,cache=HintsColumnFamilyKeyCache
// i.e. : domain:bean_parameter1,bean_parameter2
String[] splitBeanName = beanStringName.split(":");
String domain = splitBeanName[0];
String beanParameters = splitBeanName[1];
LinkedList<String> beanParametersList = getBeanParametersList(instanceName, domain, beanParameters, instanceTags);
HashMap<String, String> beanParametersHash = getBeanParametersHash(beanParametersList);

this.domain = domain;

HashMap<String, String> beanParametersHash = getBeanParametersHash(beanParameters);
LinkedList<String> beanParametersList = getBeanParametersList(instanceName, beanParametersHash, instanceTags);

this.beanParameters = beanParametersHash;
this.defaultTagsList = renameConflictingParameters(beanParametersList);
}

public static HashMap<String, String> getBeanParametersHash(LinkedList<String> beanParameters) {
HashMap<String, String> beanParams = new HashMap<String, String>();
public static HashMap<String, String> getBeanParametersHash(String beanParametersString) {
String[] beanParameters = beanParametersString.split(",");
HashMap<String, String> beanParamsMap = new HashMap<String, String>(beanParameters.length);
for (String param : beanParameters) {
String[] paramSplit = param.split(":");
String[] paramSplit = param.split("=");
if (paramSplit.length > 1) {
beanParams.put(new String(paramSplit[0]), new String(paramSplit[1]));
beanParamsMap.put(new String(paramSplit[0]), new String(paramSplit[1]));
} else {
beanParams.put(new String(paramSplit[0]), "");
beanParamsMap.put(new String(paramSplit[0]), "");
}
}

return beanParams;
return beanParamsMap;
}


private static LinkedList<String> getBeanParametersList(String instanceName, String domain, String beanParameters, HashMap<String, String> instanceTags) {
LinkedList<String> beanTags = new LinkedList<String>(Arrays.asList(new String(beanParameters).replace("=", ":").split(",")));
private LinkedList<String> getBeanParametersList(String instanceName, Map<String, String> beanParameters, HashMap<String, String> instanceTags) {
LinkedList<String> beanTags = new LinkedList<String>();
beanTags.add("instance:" + instanceName);
beanTags.add("jmx_domain:" + domain);

if (renameCassandraMetrics()) {
beanTags.addAll(getCassandraBeanTags(beanParameters));
} else {
for (Map.Entry<String, String> param : beanParameters.entrySet()) {
beanTags.add(param.getKey() + ":" + param.getValue());
}
}

if (instanceTags != null) {
for (Map.Entry<String, String> tag : instanceTags.entrySet()) {
beanTags.add(tag.getKey() + ":" + tag.getValue());
Expand All @@ -109,6 +122,26 @@ private static LinkedList<String> renameConflictingParameters(LinkedList<String>
return defaultTagsList;
}

protected Boolean renameCassandraMetrics(){
return cassandraAliasing && domain.equals(CASSANDRA_DOMAIN);
}

private static Collection<String> getCassandraBeanTags(Map<String, String> beanParameters) {
Collection<String> tags = new LinkedList<String>();
for (Map.Entry<String, String> param : beanParameters.entrySet()) {
if (param.getKey().equals("name")) {
//This is already in the alias
continue;
} else if (param.getKey().equals("scope")) {
String type = beanParameters.get("type");
tags.add(type + ":" + param.getValue());
} else {
tags.add(param.getKey() + ":" + param.getValue());
}
}
return tags;
}

static String convertMetricName(String metricName) {
metricName = metricName.replaceAll(FIRST_CAP_PATTERN, "$1_$2");
metricName = metricName.replaceAll(ALL_CAP_PATTERN, "$1_$2").toLowerCase();
Expand Down Expand Up @@ -344,4 +377,12 @@ String getAttributeName() {
public static List<String> getExcludedBeanParams(){
return EXCLUDED_BEAN_PARAMS;
}

protected String getDomain() {
return domain;
}

protected HashMap<String, String> getBeanParameters() {
return beanParameters;
}
}
6 changes: 3 additions & 3 deletions src/main/java/org/datadog/jmxfetch/JMXComplexAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class JMXComplexAttribute extends JMXAttribute {

public JMXComplexAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
Connection connection, HashMap<String, String> instanceTags) {
super(attribute, beanName, instanceName, connection, instanceTags);
super(attribute, beanName, instanceName, connection, instanceTags, false);
this.subAttributeList = new HashMap<String, HashMap<String, Object>>();
}

Expand Down Expand Up @@ -118,9 +118,9 @@ private String getAlias(String subAttribute) {
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") + "." + getBeanStringName().split(":")[0] + "." + subAttributeName;
return conf.get("metric_prefix") + "." + getDomain() + "." + subAttributeName;
}
return "jmx." + getBeanStringName().split(":")[0] + "." + subAttributeName;
return "jmx." + getDomain() + "." + subAttributeName;
}


Expand Down
25 changes: 21 additions & 4 deletions src/main/java/org/datadog/jmxfetch/JMXSimpleAttribute.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;

import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
Expand All @@ -20,8 +21,8 @@ public class JMXSimpleAttribute extends JMXAttribute {
private String metricType;

public JMXSimpleAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName,
Connection connection, HashMap<String, String> instanceTags) {
super(attribute, beanName, instanceName, connection, instanceTags);
Connection connection, HashMap<String, String> instanceTags, Boolean cassandraAliasing) {
super(attribute, beanName, instanceName, connection, instanceTags, cassandraAliasing);
}

@Override
Expand Down Expand Up @@ -90,17 +91,33 @@ private String getAlias() {
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") + "." + getBeanStringName().split(":")[0] + "." + getAttributeName();
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." + getBeanStringName().split(":")[0] + "." + getAttributeName();
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) {
Expand Down
15 changes: 1 addition & 14 deletions src/main/java/org/datadog/jmxfetch/reporter/Reporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ public void sendMetrics(LinkedList<HashMap<String, Object>> metrics, String inst
// We need to edit metrics for legacy reasons (rename metrics, etc)
HashMap<String, Object> metric = new HashMap<String, Object>(m);

postProcess(metric);

Double currentValue = (Double) metric.get("value");
if (currentValue.isNaN() || currentValue.isInfinite()) {
continue;
Expand Down Expand Up @@ -102,24 +100,13 @@ public void sendMetrics(LinkedList<HashMap<String, Object>> metrics, String inst
ratesAggregator.put(instanceName, instanceRatesAggregator);
}


void postProcess(HashMap<String, Object> metric) {
if (metric.get("check_name").equals("cassandra")) {
postProcessCassandra(metric);
}
}

public void sendServiceCheck(String checkName, String status, String message, String[] tags){
this.incrementServiceCheckCount(checkName);
String dataName = Reporter.formatServiceCheckPrefix(checkName);

this.doSendServiceCheck(dataName, status, message, tags);
}

private void postProcessCassandra(HashMap<String, Object> metric) {
metric.put("alias", ((String) metric.get("alias")).replace("jmx.org.apache.", ""));
}

public void incrementServiceCheckCount(String checkName){
int scCount = this.getServiceCheckCount(checkName);
this.getServiceCheckCountMap().put(checkName, new Integer(scCount+1));
Expand All @@ -129,7 +116,7 @@ public int getServiceCheckCount(String checkName){
Integer scCount = this.serviceCheckCount.get(checkName);
return (scCount == null) ? 0 : scCount.intValue();
}

public void resetServiceCheckCount(String checkName){
this.serviceCheckCount.put(checkName, new Integer(0));
}
Expand Down
68 changes: 68 additions & 0 deletions src/test/java/org/datadog/jmxfetch/TestApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,74 @@ public void testBeanTags() throws Exception {
}
}

/**
* Check JMXFetch Cassandra metric aliasing logic, i.e. compliant with CASSANDRA-4009
* when `cassandra4009` flag is enabled, or default.
*
* More information: https://issues.apache.org/jira/browse/CASSANDRA-4009
*/
@Test
public void testCassandraBean() throws Exception {
// We expose a few metrics through JMX
registerMBean(new SimpleTestJavaApp(), "org.apache.cassandra.metrics:keyspace=MyKeySpace,type=ColumnFamily,scope=MyColumnFamily,name=PendingTasks");
initApplication("jmx_cassandra.yaml");


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

// 14 = 2*13 metrics from java.lang + 2*1 metric explicitly defined in the yaml config file
assertEquals(28, metrics.size());

// Assert compliancy with CASSANDRA-4009
ArrayList<String> tags = new ArrayList<String>() {{
add("type:ColumnFamily");
add("keyspace:MyKeySpace");
add("ColumnFamily:MyColumnFamily");
add("jmx_domain:org.apache.cassandra.metrics");
add("instance:jmx_first_instance");
}};

assertMetric("cassandra.pending_tasks.should_be100", tags, 5);

// Default behavior
tags = new ArrayList<String>() {{
add("type:ColumnFamily");
add("scope:MyColumnFamily");
add("keyspace:MyKeySpace");
add("jmx_domain:org.apache.cassandra.metrics");
add("instance:jmx_second_instance");
add("name:PendingTasks");
}};

assertMetric("cassandra.metrics.should_be1000", tags, 6);
}

@Test
public void testCassandraDeprecatedBean() throws Exception {
// We expose a few metrics through JMX
registerMBean(new SimpleTestJavaApp(), "org.apache.cassandra.db:type=ColumnFamilies,keyspace=MyKeySpace,columnfamily=MyColumnFamily");
initApplication("jmx_cassandra_deprecated.yaml");

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

// 14 = 13 metrics from java.lang + 1 metric explicitly defined in the yaml config file
assertEquals(14, metrics.size());

ArrayList<String> tags = new ArrayList<String>() {{
add("type:ColumnFamilies");
add("keyspace:MyKeySpace");
add("columnfamily:MyColumnFamily");
add("jmx_domain:org.apache.cassandra.db");
add("instance:jmx_test_instance");
}};

assertMetric("cassandra.db.should_be100", tags, 5);
}

@Test
public void testDomainInclude() throws Exception {
// We expose a few metrics through JMX
Expand Down
Loading

0 comments on commit 0bc1a29

Please sign in to comment.