// Do not apply Lily license package org.lilyproject.util.hbase.metrics; import javax.management.Attribute; import javax.management.AttributeList; import javax.management.AttributeNotFoundException; import javax.management.DynamicMBean; import javax.management.InvalidAttributeValueException; import javax.management.MBeanAttributeInfo; import javax.management.MBeanException; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.ReflectionException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.hadoop.hbase.metrics.MetricsRate; import org.apache.hadoop.metrics.MetricsUtil; import org.apache.hadoop.metrics.util.MetricsBase; import org.apache.hadoop.metrics.util.MetricsIntValue; import org.apache.hadoop.metrics.util.MetricsLongValue; import org.apache.hadoop.metrics.util.MetricsRegistry; import org.apache.hadoop.metrics.util.MetricsTimeVaryingInt; import org.apache.hadoop.metrics.util.MetricsTimeVaryingLong; import org.apache.hadoop.metrics.util.MetricsTimeVaryingRate; /** * This class was copied from Hadoop and extended to support some new types of metrics. */ public abstract class MetricsDynamicMBeanBase implements DynamicMBean { private final static String AVG_TIME = "AvgTime"; private final static String MIN_TIME = "MinTime"; private final static String MAX_TIME = "MaxTime"; private final static String NUM_OPS = "NumOps"; private final static String RESET_ALL_MIN_MAX_OP = "resetAllMinMax"; private MetricsRegistry metricsRegistry; private MBeanInfo mbeanInfo; private Map<String, MetricsBase> metricsRateAttributeMod; private int numEntriesInRegistry = 0; private String mbeanDescription; protected MetricsDynamicMBeanBase(final MetricsRegistry mr, final String aMBeanDescription) { metricsRegistry = mr; mbeanDescription = aMBeanDescription; createMBeanInfo(); } private void updateMbeanInfoIfMetricsListChanged() { if (numEntriesInRegistry != metricsRegistry.size()) { createMBeanInfo(); } } private void createMBeanInfo() { metricsRateAttributeMod = new HashMap<String, MetricsBase>(); boolean needsMinMaxResetOperation = false; List<MBeanAttributeInfo> attributesInfo = new ArrayList<MBeanAttributeInfo>(); MBeanOperationInfo[] operationsInfo = null; numEntriesInRegistry = metricsRegistry.size(); for (MetricsBase o : metricsRegistry.getMetricsList()) { if (MetricsTimeVaryingRate.class.isInstance(o)) { // For each of the metrics there are 3 different attributes attributesInfo.add(new MBeanAttributeInfo(o.getName() + NUM_OPS, "java.lang.Integer", o.getDescription(), true, false, false)); attributesInfo.add(new MBeanAttributeInfo(o.getName() + AVG_TIME, "java.lang.Long", o.getDescription(), true, false, false)); attributesInfo.add(new MBeanAttributeInfo(o.getName() + MIN_TIME, "java.lang.Long", o.getDescription(), true, false, false)); attributesInfo.add(new MBeanAttributeInfo(o.getName() + MAX_TIME, "java.lang.Long", o.getDescription(), true, false, false)); needsMinMaxResetOperation = true; // the min and max can be reset. // Note the special attributes (AVG_TIME, MIN_TIME, ..) are derived from metrics // Rather than check for the suffix we store them in a map. metricsRateAttributeMod.put(o.getName() + NUM_OPS, o); metricsRateAttributeMod.put(o.getName() + AVG_TIME, o); metricsRateAttributeMod.put(o.getName() + MIN_TIME, o); metricsRateAttributeMod.put(o.getName() + MAX_TIME, o); } else if ( MetricsIntValue.class.isInstance(o) || MetricsTimeVaryingInt.class.isInstance(o) ) { attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Integer", o.getDescription(), true, false, false)); } else if ( MetricsLongValue.class.isInstance(o) || MetricsTimeVaryingLong.class.isInstance(o) ) { attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Long", o.getDescription(), true, false, false)); } else if ( MetricsNonTimeRate.class.isInstance(o)) { attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Float", o.getDescription(), true, false, false)); } else if ( MetricsRate.class.isInstance(o)) { attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Float", o.getDescription(), true, false, false)); } else { MetricsUtil.LOG.error("unknown metrics type: " + o.getClass().getName()); } if (needsMinMaxResetOperation) { operationsInfo = new MBeanOperationInfo[] { new MBeanOperationInfo(RESET_ALL_MIN_MAX_OP, "Reset (zero) All Min Max", null, "void", MBeanOperationInfo.ACTION) }; } } MBeanAttributeInfo[] attrArray = new MBeanAttributeInfo[attributesInfo.size()]; mbeanInfo = new MBeanInfo(this.getClass().getName(), mbeanDescription, attributesInfo.toArray(attrArray), null, operationsInfo, null); } @Override public Object getAttribute(String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException { if (attributeName == null || attributeName.equals("")) { throw new IllegalArgumentException(); } updateMbeanInfoIfMetricsListChanged(); Object o = metricsRateAttributeMod.get(attributeName); if (o == null) { o = metricsRegistry.get(attributeName); } if (o == null) { throw new AttributeNotFoundException(); } if (o instanceof MetricsIntValue) { return ((MetricsIntValue)o).get(); } else if (o instanceof MetricsLongValue) { return ((MetricsLongValue)o).get(); } else if (o instanceof MetricsTimeVaryingInt) { return ((MetricsTimeVaryingInt)o).getPreviousIntervalValue(); } else if (o instanceof MetricsTimeVaryingLong) { return ((MetricsTimeVaryingLong)o).getPreviousIntervalValue(); } else if (o instanceof MetricsTimeVaryingRate) { MetricsTimeVaryingRate or = (MetricsTimeVaryingRate) o; if (attributeName.endsWith(NUM_OPS)) { return or.getPreviousIntervalNumOps(); } else if (attributeName.endsWith(AVG_TIME)) { return or.getPreviousIntervalAverageTime(); } else if (attributeName.endsWith(MIN_TIME)) { return or.getMinTime(); } else if (attributeName.endsWith(MAX_TIME)) { return or.getMaxTime(); } else { MetricsUtil.LOG.error("Unexpected attrubute suffix"); throw new AttributeNotFoundException(); } } else if (o instanceof MetricsNonTimeRate) { MetricsNonTimeRate metric = (MetricsNonTimeRate)o; return metric.getPreviousIntervalValue(); } else if (o instanceof MetricsRate) { MetricsRate metric = (MetricsRate)o; return metric.getPreviousIntervalValue(); } else { MetricsUtil.LOG.error("unknown metrics type: " + o.getClass().getName()); throw new AttributeNotFoundException(); } } @Override public AttributeList getAttributes(String[] attributeNames) { if (attributeNames == null || attributeNames.length == 0) { throw new IllegalArgumentException(); } updateMbeanInfoIfMetricsListChanged(); AttributeList result = new AttributeList(attributeNames.length); for (String iAttributeName : attributeNames) { try { Object value = getAttribute(iAttributeName); result.add(new Attribute(iAttributeName, value)); } catch (Exception e) { continue; } } return result; } @Override public MBeanInfo getMBeanInfo() { return mbeanInfo; } @Override public Object invoke(String actionName, Object[] parms, String[] signature) throws MBeanException, ReflectionException { if (actionName == null || actionName.equals("")) { throw new IllegalArgumentException(); } // Right now we support only one fixed operation (if it applies) if (!(actionName.equals(RESET_ALL_MIN_MAX_OP)) || mbeanInfo.getOperations().length != 1) { throw new ReflectionException(new NoSuchMethodException(actionName)); } for (MetricsBase m : metricsRegistry.getMetricsList()) { if ( MetricsTimeVaryingRate.class.isInstance(m) ) { MetricsTimeVaryingRate.class.cast(m).resetMinMax(); } } return null; } @Override public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { throw new ReflectionException(new NoSuchMethodException("set" + attribute)); } @Override public AttributeList setAttributes(AttributeList attributes) { return null; } }