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

[attribute] add TabularData support #128

Merged
merged 7 commits into from
Mar 3, 2017
Merged
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
6 changes: 5 additions & 1 deletion src/main/java/org/datadog/jmxfetch/Instance.java
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ public class Instance {
"java.util.concurrent.atomic.AtomicInteger", "java.util.concurrent.atomic.AtomicLong",
"java.lang.Object", "java.lang.Boolean", "boolean", "java.lang.Number");
private final static List<String> COMPOSED_TYPES = Arrays.asList("javax.management.openmbean.CompositeData", "java.util.HashMap", "java.util.Map");
private final static List<String> MULTI_TYPES = Arrays.asList("javax.management.openmbean.TabularData");
private final static int MAX_RETURNED_METRICS = 350;
private final static int DEFAULT_REFRESH_BEANS_PERIOD = 600;
public static final String PROCESS_NAME_REGEX = "process_name_regex";
@@ -248,8 +249,11 @@ private void getMatchingAttributes() {
LOGGER.debug(ATTRIBUTE + beanName + " : " + attributeInfo + " has attributeInfo simple type");
jmxAttribute = new JMXSimpleAttribute(attributeInfo, beanName, instanceName, connection, tags, cassandraAliasing);
} else if (COMPOSED_TYPES.contains(attributeType)) {
LOGGER.debug(ATTRIBUTE + beanName + " : " + attributeInfo + " has attributeInfo complex type");
LOGGER.debug(ATTRIBUTE + beanName + " : " + attributeInfo + " has attributeInfo composite type");
jmxAttribute = new JMXComplexAttribute(attributeInfo, beanName, instanceName, connection, tags);
} else if (MULTI_TYPES.contains(attributeType)) {
LOGGER.debug(ATTRIBUTE + beanName + " : " + attributeInfo + " has attributeInfo tabular type");
jmxAttribute = new JMXTabularAttribute(attributeInfo, beanName, instanceName, connection, tags);
} else {
try {
LOGGER.debug(ATTRIBUTE + beanName + " : " + attributeInfo + " has an unsupported type: " + attributeType);
5 changes: 2 additions & 3 deletions src/main/java/org/datadog/jmxfetch/JMXAttribute.java
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ 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());
protected 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", "exclude_tags", "tags");
private static final String FIRST_CAP_PATTERN = "(.)([A-Z][a-z]+)";
@@ -98,7 +98,6 @@ private void applyTagsBlackList() {
private void addAdditionalTags() {
Filter include = this.matchingConf.getInclude();
if (include != null) {

for (Map.Entry<String, String> tag : include.getAdditionalTags().entrySet()) {
this.defaultTagsList.add(tag.getKey() + ":" + this.replaceByAlias(tag.getValue()));
}
@@ -254,7 +253,7 @@ Object convertMetricValue(Object metricValue) {
return converted;
}

double getValueAsDouble(Object metricValue) {
double castToDouble(Object metricValue) {
Object value = convertMetricValue(metricValue);

if (value instanceof String) {
9 changes: 4 additions & 5 deletions src/main/java/org/datadog/jmxfetch/JMXComplexAttribute.java
Original file line number Diff line number Diff line change
@@ -65,27 +65,26 @@ public LinkedList<HashMap<String, Object>> getMetrics()
metric.put("tags", getTags());
}

metric.put("value", getValue(subAttribute));
metric.put("value", castToDouble(getValue(subAttribute)));
metrics.add(metric);

}
return metrics;

}

private double getValue(String subAttribute) throws AttributeNotFoundException, InstanceNotFoundException,
private Object getValue(String subAttribute) throws AttributeNotFoundException, InstanceNotFoundException,
MBeanException, ReflectionException, IOException {

Object value = this.getJmxValue();
String attributeType = getAttribute().getType();

if ("javax.management.openmbean.CompositeData".equals(attributeType)) {
CompositeData data = (CompositeData) value;
return getValueAsDouble(data.get(subAttribute));

return data.get(subAttribute);
} else if (("java.util.HashMap".equals(attributeType)) || ("java.util.Map".equals(attributeType))) {
Map<String, Object> data = (Map<String, Object>) value;
return getValueAsDouble(data.get(subAttribute));
return data.get(subAttribute);
}
throw new NumberFormatException();
}
6 changes: 3 additions & 3 deletions src/main/java/org/datadog/jmxfetch/JMXSimpleAttribute.java
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ public LinkedList<HashMap<String, Object>> getMetrics() throws AttributeNotFound
HashMap<String, Object> metric = new HashMap<String, Object>();

metric.put("alias", getAlias());
metric.put("value", getValue());
metric.put("value", castToDouble(getValue()));
metric.put("tags", getTags());
metric.put("metric_type", getMetricType());
LinkedList<HashMap<String, Object>> metrics = new LinkedList<HashMap<String, Object>>();
@@ -98,8 +98,8 @@ private String getMetricType() {
return metricType;
}

private double getValue() throws AttributeNotFoundException, InstanceNotFoundException, MBeanException,
private Object getValue() throws AttributeNotFoundException, InstanceNotFoundException, MBeanException,
ReflectionException, IOException, NumberFormatException {
return getValueAsDouble(this.getJmxValue());
return this.getJmxValue();
}
}
296 changes: 296 additions & 0 deletions src/main/java/org/datadog/jmxfetch/JMXTabularAttribute.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
package org.datadog.jmxfetch;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.InvalidKeyException;
import javax.management.openmbean.TabularData;
import javax.management.ReflectionException;

public class JMXTabularAttribute extends JMXAttribute {
private String instanceName;
private HashMap<String, HashMap<String, HashMap<String, Object>>> subAttributeList;

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

private String getMultiKey(Collection keys) {
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Object key : keys) {
if (!first) { sb.append(","); }
// I hope these have sane toString() methods
sb.append(key.toString());
first = false;
}
return sb.toString();
}

private void populateSubAttributeList(Object value) {
TabularData data = (TabularData) value;
for (Object rowKey : data.keySet()) {
Collection keys = (Collection) rowKey;
CompositeData compositeData = data.get(keys.toArray());
String pathKey = getMultiKey(keys);
HashMap<String, HashMap<String, Object>> subAttributes = new HashMap<String, HashMap<String, Object>>();
for (String key : compositeData.getCompositeType().keySet()) {
if (compositeData.get(key) instanceof CompositeData) {
for (String subKey : ((CompositeData) compositeData.get(key)).getCompositeType().keySet()) {
subAttributes.put(key + "." + subKey, new HashMap<String, Object>());
}
} else {
subAttributes.put(key, new HashMap<String, Object>());
}
}
subAttributeList.put(pathKey, subAttributes);
}
}

protected String[] getTags(String key, String subAttribute) throws AttributeNotFoundException,
InstanceNotFoundException, MBeanException, ReflectionException, IOException {
List<String> tagsList = new ArrayList<String>();
String fullMetricKey = getAttributeName() + "." + subAttribute;
Map<String, ?> attributeParams = getAttributesFor(fullMetricKey);
if (attributeParams != null) {
Map<String, String> yamlTags = (Map) attributeParams.get("tags");
for (String tagName : yamlTags.keySet()) {
String tag = tagName;
String value = yamlTags.get(tagName);
Object resolvedValue;

if (value.startsWith("$")){
resolvedValue = getValue(key, value.substring(1));
if (resolvedValue != null){
value = (String) resolvedValue;
}
}

tagsList.add(tag + ":" + value);
}
}
String[] defaultTags = super.getTags();
tagsList.addAll(Arrays.asList(defaultTags));

String[] tags = new String[tagsList.size()];
tags = tagsList.toArray(tags);
return tags;
}

private Map<String, ?> getAttributesFor(String key) {
Filter include = getMatchingConf().getInclude();
if (include != null) {
Object includeAttribute = include.getAttribute();
if (includeAttribute instanceof LinkedHashMap<?, ?>) {
return (Map<String, ?>) ((Map)includeAttribute).get(key);
}
}
return null;
}

@Override
public LinkedList<HashMap<String, Object>> getMetrics() throws AttributeNotFoundException,
InstanceNotFoundException, MBeanException, ReflectionException, IOException {
LinkedList<HashMap<String, Object>> metrics = new LinkedList<HashMap<String, Object>>();
HashMap<String, LinkedList<HashMap<String, Object>>> subMetrics = new HashMap<String,
LinkedList<HashMap<String, Object>>>();

for (String dataKey : subAttributeList.keySet()) {
HashMap<String, HashMap<String, Object>> subSub = subAttributeList.get(dataKey);
for (String metricKey : subSub.keySet()) {
String fullMetricKey = getAttributeName() + "." + metricKey;

HashMap<String, Object> metric = subSub.get(metricKey);

if (metric.get(ALIAS) == null) {
metric.put(ALIAS, convertMetricName(getAlias(metricKey)));
}

if (metric.get(METRIC_TYPE) == null) {
metric.put(METRIC_TYPE, getMetricType(metricKey));
}

if (metric.get("tags") == null) {
metric.put("tags", getTags(dataKey, metricKey));
}

metric.put("value", castToDouble(getValue(dataKey, metricKey)));

if(!subMetrics.containsKey(fullMetricKey)) {
subMetrics.put(fullMetricKey, new LinkedList<HashMap<String, Object>>());
}
subMetrics.get(fullMetricKey).add(metric);
}
}

for (String key : subMetrics.keySet()) {
// only add explicitly included metrics
if (getAttributesFor(key) != null) {
metrics.addAll(sortAndFilter(key, subMetrics.get(key)));
}
}

return metrics;
}

private List<HashMap<String, Object>> sortAndFilter(String metricKey, LinkedList<HashMap<String, Object>>
metrics) {
Map<String, ?> attributes = getAttributesFor(metricKey);
if (!attributes.containsKey("limit")) {
return metrics;
}
Integer limit = (Integer) attributes.get("limit");
if (metrics.size() <= limit) {
return metrics;
}
MetricComparator comp = new MetricComparator();
Collections.sort(metrics, comp);
String sort = (String) attributes.get("sort");
if (sort == null || sort.equals("desc")) {
metrics.subList(0, limit).clear();
} else {
metrics.subList(metrics.size() - limit, metrics.size()).clear();
}
return metrics;
}

private class MetricComparator implements Comparator<HashMap<String, Object>> {
public int compare(HashMap<String, Object> o1, HashMap<String, Object> o2) {
Double v1 = (Double) o1.get("value");
Double v2 = (Double) o2.get("value");
return v1.compareTo(v2);
}
}

private Object getValue(String key, String subAttribute) throws AttributeNotFoundException,
InstanceNotFoundException,
MBeanException, ReflectionException, IOException {

try{
Object value = this.getJmxValue();
String attributeType = getAttribute().getType();

TabularData data = (TabularData) value;
for (Object rowKey : data.keySet()) {
Collection keys = (Collection) rowKey;
String pathKey = getMultiKey(keys);
if (key.equals(pathKey)) {
CompositeData compositeData = data.get(keys.toArray());
if (subAttribute.contains(".")) {
// walk down the path
Object o;
for (String subPathKey : subAttribute.split("\\.")) {
o = compositeData.get(subPathKey);
if (o instanceof CompositeData) {
compositeData = (CompositeData) o;
} else {
return compositeData.get(subPathKey);
}
}
} else {
return compositeData.get(subAttribute);
}
}
}
}
catch (InvalidKeyException e){
LOGGER.warn("`"+getAttribute().getName()+"` attribute does not have a `"+subAttribute+"` key.");
return null;
}

throw new NumberFormatException();
}

private Object getMetricType(String subAttribute) {
String subAttributeName = getAttribute().getName() + "." + subAttribute;
String metricType = null;

Filter include = getMatchingConf().getInclude();
if (include.getAttribute() instanceof LinkedHashMap<?, ?>) {
LinkedHashMap<String, LinkedHashMap<String, String>> attribute = (LinkedHashMap<String,
LinkedHashMap<String, String>>) (include.getAttribute());
metricType = attribute.get(subAttributeName).get(METRIC_TYPE);
if (metricType == null) {
metricType = attribute.get(subAttributeName).get("type");
}
}

if (metricType == null) {
metricType = "gauge";
}

return metricType;
}

@Override
public boolean match(Configuration configuration) {
if (!matchDomain(configuration)
|| !matchBean(configuration)
|| excludeMatchDomain(configuration)
|| excludeMatchBean(configuration)) {
return false;
}

try {
populateSubAttributeList(getJmxValue());
} catch (Exception e) {
return false;
}

return matchAttribute(configuration);//TODO && !excludeMatchAttribute(configuration);
}

private boolean matchSubAttribute(Filter params, String subAttributeName, boolean matchOnEmpty) {
if ((params.getAttribute() instanceof LinkedHashMap<?, ?>)
&& ((LinkedHashMap<String, Object>) (params.getAttribute())).containsKey(subAttributeName)) {
return true;
} else if ((params.getAttribute() instanceof ArrayList<?>
&& ((ArrayList<String>) (params.getAttribute())).contains(subAttributeName))) {
return true;
} else if (params.getAttribute() == null) {
return matchOnEmpty;
}
return false;
}

private boolean matchAttribute(Configuration configuration) {
if (matchSubAttribute(configuration.getInclude(), getAttributeName(), true)) {
return true;
}

Iterator<String> it1 = subAttributeList.keySet().iterator();
while (it1.hasNext()) {
String key = it1.next();
HashMap<String, HashMap<String, Object>> subSub = subAttributeList.get(key);
Iterator<String> it2 = subSub.keySet().iterator();
while (it2.hasNext()) {
String subKey = it2.next();
if (!matchSubAttribute(configuration.getInclude(), getAttributeName() + "." + subKey, true)) {
it2.remove();
}
}
if (subSub.size() <= 0) {
it1.remove();
}
}

return subAttributeList.size() > 0;
}
}
Loading