package org.datadog.jmxfetch; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; 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.ReflectionException; import javax.management.openmbean.CompositeData; @SuppressWarnings("unchecked") public class JMXComplexAttribute extends JMXAttribute { private HashMap<String, HashMap<String, Object>> subAttributeList; public JMXComplexAttribute(MBeanAttributeInfo attribute, ObjectName beanName, String instanceName, Connection connection, HashMap<String, String> instanceTags) { super(attribute, beanName, instanceName, connection, instanceTags, false); this.subAttributeList = new HashMap<String, HashMap<String, Object>>(); } private void populateSubAttributeList(Object attributeValue) { String attributeType = getAttribute().getType(); if ("javax.management.openmbean.CompositeData".equals(attributeType)) { CompositeData data = (CompositeData) attributeValue; for (String key : data.getCompositeType().keySet()) { this.subAttributeList.put(key, new HashMap<String, Object>()); } } else if (("java.util.HashMap".equals(attributeType)) || ("java.util.Map".equals(attributeType))){ Map<String, Double> data = (Map<String, Double>) attributeValue; for (String key : data.keySet()) { this.subAttributeList.put(key, new HashMap<String, Object>()); } } } @Override public LinkedList<HashMap<String, Object>> getMetrics() throws AttributeNotFoundException, InstanceNotFoundException, MBeanException, ReflectionException, IOException { LinkedList<HashMap<String, Object>> metrics = new LinkedList<HashMap<String, Object>>(); for (Map.Entry<String, HashMap<String, Object>> pair : subAttributeList.entrySet()) { String subAttribute = pair.getKey(); HashMap<String, Object> metric = pair.getValue(); if (metric.get(ALIAS) == null) { metric.put(ALIAS, convertMetricName(getAlias(subAttribute))); } if (metric.get(METRIC_TYPE) == null) { metric.put(METRIC_TYPE, getMetricType(subAttribute)); } if (metric.get("tags") == null) { metric.put("tags", getTags()); } metric.put("value", castToDouble(getValue(subAttribute))); metrics.add(metric); } return metrics; } 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 data.get(subAttribute); } else if (("java.util.HashMap".equals(attributeType)) || ("java.util.Map".equals(attributeType))) { Map<String, Object> data = (Map<String, Object>) value; return data.get(subAttribute); } 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) && !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> it = subAttributeList.keySet().iterator(); while (it.hasNext()) { String subAttribute = it.next(); if (!matchSubAttribute(configuration.getInclude(), getAttributeName() + "." + subAttribute, true)) { it.remove(); } } return subAttributeList.size() > 0; } private boolean excludeMatchAttribute(Configuration configuration) { Filter exclude = configuration.getExclude(); if (exclude.getAttribute() != null && matchSubAttribute(exclude, getAttributeName(), false)) { return true; } Iterator<String> it = subAttributeList.keySet().iterator(); while (it.hasNext()) { String subAttribute = it.next(); if (matchSubAttribute(exclude, getAttributeName() + "." + subAttribute, false)) { it.remove(); } } return subAttributeList.size() <= 0; } }