| /** |
| * Copyright 2010 The Apache Software Foundation |
| * |
| * 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.hbase.metrics; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.management.AttributeNotFoundException; |
| import javax.management.MBeanAttributeInfo; |
| import javax.management.MBeanException; |
| import javax.management.MBeanInfo; |
| import javax.management.ReflectionException; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| import org.apache.hadoop.metrics.util.MetricsBase; |
| import org.apache.hadoop.metrics.util.MetricsDynamicMBeanBase; |
| import org.apache.hadoop.metrics.util.MetricsRegistry; |
| |
| /** |
| * Extends the Hadoop MetricsDynamicMBeanBase class to provide JMX support for |
| * custom HBase MetricsBase implementations. MetricsDynamicMBeanBase ignores |
| * registered MetricsBase instance that are not instances of one of the |
| * org.apache.hadoop.metrics.util implementations. |
| * |
| */ |
| public class MetricsMBeanBase extends MetricsDynamicMBeanBase { |
| |
| private static final Log LOG = LogFactory.getLog("org.apache.hadoop.hbase.metrics"); |
| |
| protected final MetricsRegistry registry; |
| protected final String description; |
| protected int registryLength; |
| /** HBase MetricsBase implementations that MetricsDynamicMBeanBase does |
| * not understand |
| */ |
| protected Map<String,MetricsBase> extendedAttributes = |
| new HashMap<String,MetricsBase>(); |
| protected MBeanInfo extendedInfo; |
| |
| protected MetricsMBeanBase( MetricsRegistry mr, String description ) { |
| super(copyMinusHBaseMetrics(mr), description); |
| this.registry = mr; |
| this.description = description; |
| this.init(); |
| } |
| |
| /* |
| * @param mr MetricsRegistry. |
| * @return A copy of the passed MetricsRegistry minus the hbase metrics |
| */ |
| private static MetricsRegistry copyMinusHBaseMetrics(final MetricsRegistry mr) { |
| MetricsRegistry copy = new MetricsRegistry(); |
| for (MetricsBase metric : mr.getMetricsList()) { |
| if (metric instanceof MetricsRate || metric instanceof MetricsString) { |
| continue; |
| } |
| copy.add(metric.getName(), metric); |
| } |
| return copy; |
| } |
| |
| protected void init() { |
| List<MBeanAttributeInfo> attributes = new ArrayList<MBeanAttributeInfo>(); |
| MBeanInfo parentInfo = super.getMBeanInfo(); |
| List<String> parentAttributes = new ArrayList<String>(); |
| for (MBeanAttributeInfo attr : parentInfo.getAttributes()) { |
| attributes.add(attr); |
| parentAttributes.add(attr.getName()); |
| } |
| |
| this.registryLength = this.registry.getMetricsList().size(); |
| |
| for (MetricsBase metric : this.registry.getMetricsList()) { |
| if (metric.getName() == null || parentAttributes.contains(metric.getName())) |
| continue; |
| |
| // add on custom HBase metric types |
| if (metric instanceof MetricsRate) { |
| attributes.add( new MBeanAttributeInfo(metric.getName(), |
| "java.lang.Float", metric.getDescription(), true, false, false) ); |
| extendedAttributes.put(metric.getName(), metric); |
| } else if (metric instanceof MetricsString) { |
| attributes.add( new MBeanAttributeInfo(metric.getName(), |
| "java.lang.String", metric.getDescription(), true, false, false) ); |
| extendedAttributes.put(metric.getName(), metric); |
| LOG.info("MetricsString added: " + metric.getName()); |
| } |
| // else, its probably a hadoop metric already registered. Skip it. |
| } |
| |
| LOG.info("new MBeanInfo"); |
| this.extendedInfo = new MBeanInfo( this.getClass().getName(), |
| this.description, attributes.toArray( new MBeanAttributeInfo[0] ), |
| parentInfo.getConstructors(), parentInfo.getOperations(), |
| parentInfo.getNotifications() ); |
| } |
| |
| private void checkAndUpdateAttributes() { |
| if (this.registryLength != this.registry.getMetricsList().size()) |
| this.init(); |
| } |
| |
| @Override |
| public Object getAttribute( String name ) |
| throws AttributeNotFoundException, MBeanException, |
| ReflectionException { |
| |
| if (name == null) { |
| throw new IllegalArgumentException("Attribute name is NULL"); |
| } |
| |
| /* |
| * Ugly. Since MetricsDynamicMBeanBase implementation is private, |
| * we need to first check the parent class for the attribute. |
| * In case that the MetricsRegistry contents have changed, this will |
| * allow the parent to update it's internal structures (which we rely on |
| * to update our own. |
| */ |
| try { |
| return super.getAttribute(name); |
| } catch (AttributeNotFoundException ex) { |
| |
| checkAndUpdateAttributes(); |
| |
| MetricsBase metric = this.extendedAttributes.get(name); |
| if (metric != null) { |
| if (metric instanceof MetricsRate) { |
| return ((MetricsRate) metric).getPreviousIntervalValue(); |
| } else if (metric instanceof MetricsString) { |
| return ((MetricsString)metric).getValue(); |
| } else { |
| LOG.warn( String.format("unknown metrics type %s for attribute %s", |
| metric.getClass().getName(), name) ); |
| } |
| } |
| } |
| |
| throw new AttributeNotFoundException(); |
| } |
| |
| @Override |
| public MBeanInfo getMBeanInfo() { |
| return this.extendedInfo; |
| } |
| |
| } |