[120] | 1 | /** |
---|
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
---|
| 3 | * or more contributor license agreements. See the NOTICE file |
---|
| 4 | * distributed with this work for additional information |
---|
| 5 | * regarding copyright ownership. The ASF licenses this file |
---|
| 6 | * to you under the Apache License, Version 2.0 (the |
---|
| 7 | * "License"); you may not use this file except in compliance |
---|
| 8 | * with the License. You may obtain a copy of the License at |
---|
| 9 | * |
---|
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
---|
| 11 | * |
---|
| 12 | * Unless required by applicable law or agreed to in writing, software |
---|
| 13 | * distributed under the License is distributed on an "AS IS" BASIS, |
---|
| 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
| 15 | * See the License for the specific language governing permissions and |
---|
| 16 | * limitations under the License. |
---|
| 17 | */ |
---|
| 18 | package org.apache.hadoop.metrics.util; |
---|
| 19 | |
---|
| 20 | import java.util.ArrayList; |
---|
| 21 | import java.util.HashMap; |
---|
| 22 | import java.util.List; |
---|
| 23 | import java.util.Map; |
---|
| 24 | |
---|
| 25 | import javax.management.Attribute; |
---|
| 26 | import javax.management.AttributeList; |
---|
| 27 | import javax.management.AttributeNotFoundException; |
---|
| 28 | import javax.management.DynamicMBean; |
---|
| 29 | import javax.management.InvalidAttributeValueException; |
---|
| 30 | import javax.management.MBeanAttributeInfo; |
---|
| 31 | import javax.management.MBeanException; |
---|
| 32 | import javax.management.MBeanInfo; |
---|
| 33 | import javax.management.MBeanOperationInfo; |
---|
| 34 | import javax.management.ReflectionException; |
---|
| 35 | |
---|
| 36 | import org.apache.hadoop.metrics.MetricsUtil; |
---|
| 37 | |
---|
| 38 | |
---|
| 39 | |
---|
| 40 | /** |
---|
| 41 | * This abstract base class facilitates creating dynamic mbeans automatically from |
---|
| 42 | * metrics. |
---|
| 43 | * The metrics constructors registers metrics in a registry. |
---|
| 44 | * Different categories of metrics should be in differnt classes with their own |
---|
| 45 | * registry (as in NameNodeMetrics and DataNodeMetrics). |
---|
| 46 | * Then the MBean can be created passing the registry to the constructor. |
---|
| 47 | * The MBean should be then registered using a mbean name (example): |
---|
| 48 | * MetricsHolder myMetrics = new MetricsHolder(); // has metrics and registry |
---|
| 49 | * MetricsTestMBean theMBean = new MetricsTestMBean(myMetrics.mregistry); |
---|
| 50 | * ObjectName mbeanName = MBeanUtil.registerMBean("ServiceFoo", |
---|
| 51 | * "TestStatistics", theMBean); |
---|
| 52 | * |
---|
| 53 | * |
---|
| 54 | */ |
---|
| 55 | public abstract class MetricsDynamicMBeanBase implements DynamicMBean { |
---|
| 56 | private final static String AVG_TIME = "AvgTime"; |
---|
| 57 | private final static String MIN_TIME = "MinTime"; |
---|
| 58 | private final static String MAX_TIME = "MaxTime"; |
---|
| 59 | private final static String NUM_OPS = "NumOps"; |
---|
| 60 | private final static String RESET_ALL_MIN_MAX_OP = "resetAllMinMax"; |
---|
| 61 | private MetricsRegistry metricsRegistry; |
---|
| 62 | private MBeanInfo mbeanInfo; |
---|
| 63 | private Map<String, MetricsBase> metricsRateAttributeMod; |
---|
| 64 | private int numEntriesInRegistry = 0; |
---|
| 65 | private String mbeanDescription; |
---|
| 66 | |
---|
| 67 | protected MetricsDynamicMBeanBase(final MetricsRegistry mr, final String aMBeanDescription) { |
---|
| 68 | metricsRegistry = mr; |
---|
| 69 | mbeanDescription = aMBeanDescription; |
---|
| 70 | createMBeanInfo(); |
---|
| 71 | } |
---|
| 72 | |
---|
| 73 | private void updateMbeanInfoIfMetricsListChanged() { |
---|
| 74 | if (numEntriesInRegistry != metricsRegistry.size()) |
---|
| 75 | createMBeanInfo(); |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | private void createMBeanInfo() { |
---|
| 79 | metricsRateAttributeMod = new HashMap<String, MetricsBase>(); |
---|
| 80 | boolean needsMinMaxResetOperation = false; |
---|
| 81 | List<MBeanAttributeInfo> attributesInfo = new ArrayList<MBeanAttributeInfo>(); |
---|
| 82 | MBeanOperationInfo[] operationsInfo = null; |
---|
| 83 | numEntriesInRegistry = metricsRegistry.size(); |
---|
| 84 | |
---|
| 85 | for (MetricsBase o : metricsRegistry.getMetricsList()) { |
---|
| 86 | |
---|
| 87 | if (MetricsTimeVaryingRate.class.isInstance(o)) { |
---|
| 88 | // For each of the metrics there are 3 different attributes |
---|
| 89 | attributesInfo.add(new MBeanAttributeInfo(o.getName() + NUM_OPS, "java.lang.Integer", |
---|
| 90 | o.getDescription(), true, false, false)); |
---|
| 91 | attributesInfo.add(new MBeanAttributeInfo(o.getName() + AVG_TIME, "java.lang.Long", |
---|
| 92 | o.getDescription(), true, false, false)); |
---|
| 93 | attributesInfo.add(new MBeanAttributeInfo(o.getName() + MIN_TIME, "java.lang.Long", |
---|
| 94 | o.getDescription(), true, false, false)); |
---|
| 95 | attributesInfo.add(new MBeanAttributeInfo(o.getName() + MAX_TIME, "java.lang.Long", |
---|
| 96 | o.getDescription(), true, false, false)); |
---|
| 97 | needsMinMaxResetOperation = true; // the min and max can be reset. |
---|
| 98 | |
---|
| 99 | // Note the special attributes (AVG_TIME, MIN_TIME, ..) are derived from metrics |
---|
| 100 | // Rather than check for the suffix we store them in a map. |
---|
| 101 | metricsRateAttributeMod.put(o.getName() + NUM_OPS, o); |
---|
| 102 | metricsRateAttributeMod.put(o.getName() + AVG_TIME, o); |
---|
| 103 | metricsRateAttributeMod.put(o.getName() + MIN_TIME, o); |
---|
| 104 | metricsRateAttributeMod.put(o.getName() + MAX_TIME, o); |
---|
| 105 | |
---|
| 106 | } else if ( MetricsIntValue.class.isInstance(o) || MetricsTimeVaryingInt.class.isInstance(o) ) { |
---|
| 107 | attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Integer", |
---|
| 108 | o.getDescription(), true, false, false)); |
---|
| 109 | } else if ( MetricsLongValue.class.isInstance(o) || MetricsTimeVaryingLong.class.isInstance(o) ) { |
---|
| 110 | attributesInfo.add(new MBeanAttributeInfo(o.getName(), "java.lang.Long", |
---|
| 111 | o.getDescription(), true, false, false)); |
---|
| 112 | } else { |
---|
| 113 | MetricsUtil.LOG.error("unknown metrics type: " + o.getClass().getName()); |
---|
| 114 | } |
---|
| 115 | |
---|
| 116 | if (needsMinMaxResetOperation) { |
---|
| 117 | operationsInfo = new MBeanOperationInfo[] { |
---|
| 118 | new MBeanOperationInfo(RESET_ALL_MIN_MAX_OP, "Reset (zero) All Min Max", |
---|
| 119 | null, "void", MBeanOperationInfo.ACTION) }; |
---|
| 120 | } |
---|
| 121 | } |
---|
| 122 | MBeanAttributeInfo[] attrArray = new MBeanAttributeInfo[attributesInfo.size()]; |
---|
| 123 | mbeanInfo = new MBeanInfo(this.getClass().getName(), mbeanDescription, |
---|
| 124 | attributesInfo.toArray(attrArray), null, operationsInfo, null); |
---|
| 125 | } |
---|
| 126 | |
---|
| 127 | @Override |
---|
| 128 | public Object getAttribute(String attributeName) throws AttributeNotFoundException, |
---|
| 129 | MBeanException, ReflectionException { |
---|
| 130 | if (attributeName == null || attributeName.equals("")) |
---|
| 131 | throw new IllegalArgumentException(); |
---|
| 132 | |
---|
| 133 | updateMbeanInfoIfMetricsListChanged(); |
---|
| 134 | |
---|
| 135 | Object o = metricsRateAttributeMod.get(attributeName); |
---|
| 136 | if (o == null) { |
---|
| 137 | o = metricsRegistry.get(attributeName); |
---|
| 138 | } |
---|
| 139 | if (o == null) |
---|
| 140 | throw new AttributeNotFoundException(); |
---|
| 141 | |
---|
| 142 | if (o instanceof MetricsIntValue) |
---|
| 143 | return ((MetricsIntValue) o).get(); |
---|
| 144 | else if (o instanceof MetricsLongValue) |
---|
| 145 | return ((MetricsLongValue) o).get(); |
---|
| 146 | else if (o instanceof MetricsTimeVaryingInt) |
---|
| 147 | return ((MetricsTimeVaryingInt) o).getPreviousIntervalValue(); |
---|
| 148 | else if (o instanceof MetricsTimeVaryingLong) |
---|
| 149 | return ((MetricsTimeVaryingLong) o).getPreviousIntervalValue(); |
---|
| 150 | else if (o instanceof MetricsTimeVaryingRate) { |
---|
| 151 | MetricsTimeVaryingRate or = (MetricsTimeVaryingRate) o; |
---|
| 152 | if (attributeName.endsWith(NUM_OPS)) |
---|
| 153 | return or.getPreviousIntervalNumOps(); |
---|
| 154 | else if (attributeName.endsWith(AVG_TIME)) |
---|
| 155 | return or.getPreviousIntervalAverageTime(); |
---|
| 156 | else if (attributeName.endsWith(MIN_TIME)) |
---|
| 157 | return or.getMinTime(); |
---|
| 158 | else if (attributeName.endsWith(MAX_TIME)) |
---|
| 159 | return or.getMaxTime(); |
---|
| 160 | else { |
---|
| 161 | MetricsUtil.LOG.error("Unexpected attrubute suffix"); |
---|
| 162 | throw new AttributeNotFoundException(); |
---|
| 163 | } |
---|
| 164 | } else { |
---|
| 165 | MetricsUtil.LOG.error("unknown metrics type: " + o.getClass().getName()); |
---|
| 166 | throw new AttributeNotFoundException(); |
---|
| 167 | } |
---|
| 168 | } |
---|
| 169 | |
---|
| 170 | @Override |
---|
| 171 | public AttributeList getAttributes(String[] attributeNames) { |
---|
| 172 | if (attributeNames == null || attributeNames.length == 0) |
---|
| 173 | throw new IllegalArgumentException(); |
---|
| 174 | |
---|
| 175 | updateMbeanInfoIfMetricsListChanged(); |
---|
| 176 | |
---|
| 177 | AttributeList result = new AttributeList(attributeNames.length); |
---|
| 178 | for (String iAttributeName : attributeNames) { |
---|
| 179 | try { |
---|
| 180 | Object value = getAttribute(iAttributeName); |
---|
| 181 | result.add(new Attribute(iAttributeName, value)); |
---|
| 182 | } catch (Exception e) { |
---|
| 183 | continue; |
---|
| 184 | } |
---|
| 185 | } |
---|
| 186 | return result; |
---|
| 187 | } |
---|
| 188 | |
---|
| 189 | @Override |
---|
| 190 | public MBeanInfo getMBeanInfo() { |
---|
| 191 | return mbeanInfo; |
---|
| 192 | } |
---|
| 193 | |
---|
| 194 | @Override |
---|
| 195 | public Object invoke(String actionName, Object[] parms, String[] signature) |
---|
| 196 | throws MBeanException, ReflectionException { |
---|
| 197 | |
---|
| 198 | if (actionName == null || actionName.equals("")) |
---|
| 199 | throw new IllegalArgumentException(); |
---|
| 200 | |
---|
| 201 | |
---|
| 202 | // Right now we support only one fixed operation (if it applies) |
---|
| 203 | if (!(actionName.equals(RESET_ALL_MIN_MAX_OP)) || |
---|
| 204 | mbeanInfo.getOperations().length != 1) { |
---|
| 205 | throw new ReflectionException(new NoSuchMethodException(actionName)); |
---|
| 206 | } |
---|
| 207 | for (MetricsBase m : metricsRegistry.getMetricsList()) { |
---|
| 208 | if ( MetricsTimeVaryingRate.class.isInstance(m) ) { |
---|
| 209 | MetricsTimeVaryingRate.class.cast(m).resetMinMax(); |
---|
| 210 | } |
---|
| 211 | } |
---|
| 212 | return null; |
---|
| 213 | } |
---|
| 214 | |
---|
| 215 | @Override |
---|
| 216 | public void setAttribute(Attribute attribute) |
---|
| 217 | throws AttributeNotFoundException, InvalidAttributeValueException, |
---|
| 218 | MBeanException, ReflectionException { |
---|
| 219 | throw new ReflectionException(new NoSuchMethodException("set" + attribute)); |
---|
| 220 | } |
---|
| 221 | |
---|
| 222 | @Override |
---|
| 223 | public AttributeList setAttributes(AttributeList attributes) { |
---|
| 224 | return null; |
---|
| 225 | } |
---|
| 226 | } |
---|