blob: d65cce0597e6db42302c117cc76ce517b7ff7980 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.metrics.util;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 org.apache.hadoop.metrics.MetricsUtil;
/**
* This abstract base class facilitates creating dynamic mbeans automatically from
* metrics.
* The metrics constructors registers metrics in a registry.
* Different categories of metrics should be in differnt classes with their own
* registry (as in NameNodeMetrics and DataNodeMetrics).
* Then the MBean can be created passing the registry to the constructor.
* The MBean should be then registered using a mbean name (example):
* MetricsHolder myMetrics = new MetricsHolder(); // has metrics and registry
* MetricsTestMBean theMBean = new MetricsTestMBean(myMetrics.mregistry);
* ObjectName mbeanName = MBeanUtil.registerMBean("ServiceFoo",
* "TestStatistics", theMBean);
*
*
*/
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 {
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 {
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;
}
}