View Javadoc

1   /**
2    * Copyright 2010 The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS,
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17   * See the License for the specific language governing permissions and
18   * limitations under the License.
19   */
20  package org.apache.hadoop.hbase.metrics;
21  
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import javax.management.AttributeNotFoundException;
28  import javax.management.MBeanAttributeInfo;
29  import javax.management.MBeanException;
30  import javax.management.MBeanInfo;
31  import javax.management.ReflectionException;
32  
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.hadoop.metrics.util.MetricsBase;
36  import org.apache.hadoop.metrics.util.MetricsDynamicMBeanBase;
37  import org.apache.hadoop.metrics.util.MetricsRegistry;
38  
39  /**
40   * Extends the Hadoop MetricsDynamicMBeanBase class to provide JMX support for
41   * custom HBase MetricsBase implementations.  MetricsDynamicMBeanBase ignores
42   * registered MetricsBase instance that are not instances of one of the
43   * org.apache.hadoop.metrics.util implementations.
44   *
45   */
46  public class MetricsMBeanBase extends MetricsDynamicMBeanBase {
47  
48    private static final Log LOG = LogFactory.getLog("org.apache.hadoop.hbase.metrics");
49  
50    protected final MetricsRegistry registry;
51    protected final String description;
52    protected int registryLength;
53    /** HBase MetricsBase implementations that MetricsDynamicMBeanBase does
54     * not understand
55     */
56    protected Map<String,MetricsBase> extendedAttributes =
57        new HashMap<String,MetricsBase>();
58    protected MBeanInfo extendedInfo;
59  
60    protected MetricsMBeanBase( MetricsRegistry mr, String description ) {
61      super(copyMinusHBaseMetrics(mr), description);
62      this.registry = mr;
63      this.description = description;
64      this.init();
65    }
66  
67    /*
68     * @param mr MetricsRegistry.
69     * @return A copy of the passed MetricsRegistry minus the hbase metrics
70     */
71    private static MetricsRegistry copyMinusHBaseMetrics(final MetricsRegistry mr) {
72      MetricsRegistry copy = new MetricsRegistry();
73      for (MetricsBase metric : mr.getMetricsList()) {
74        if (metric instanceof org.apache.hadoop.hbase.metrics.MetricsRate) {
75          continue;
76        }
77        copy.add(metric.getName(), metric);
78      }
79      return copy;
80    }
81  
82    protected void init() {
83      List<MBeanAttributeInfo> attributes = new ArrayList<MBeanAttributeInfo>();
84      MBeanInfo parentInfo = super.getMBeanInfo();
85      List<String> parentAttributes = new ArrayList<String>();
86      for (MBeanAttributeInfo attr : parentInfo.getAttributes()) {
87        attributes.add(attr);
88        parentAttributes.add(attr.getName());
89      }
90  
91      this.registryLength = this.registry.getMetricsList().size();
92  
93      for (MetricsBase metric : this.registry.getMetricsList()) {
94        if (metric.getName() == null || parentAttributes.contains(metric.getName()))
95          continue;
96  
97        // add on custom HBase metric types
98        if (metric instanceof org.apache.hadoop.hbase.metrics.MetricsRate) {
99          attributes.add( new MBeanAttributeInfo(metric.getName(),
100             "java.lang.Float", metric.getDescription(), true, false, false) );
101         extendedAttributes.put(metric.getName(), metric);
102       }
103       // else, its probably a hadoop metric already registered. Skip it.
104     }
105 
106     this.extendedInfo = new MBeanInfo( this.getClass().getName(),
107         this.description, attributes.toArray( new MBeanAttributeInfo[0] ),
108         parentInfo.getConstructors(), parentInfo.getOperations(),
109         parentInfo.getNotifications() );
110   }
111 
112   private void checkAndUpdateAttributes() {
113     if (this.registryLength != this.registry.getMetricsList().size())
114       this.init();
115   }
116 
117   @Override
118   public Object getAttribute( String name )
119       throws AttributeNotFoundException, MBeanException,
120       ReflectionException {
121 
122     if (name == null) {
123       throw new IllegalArgumentException("Attribute name is NULL");
124     }
125 
126     /*
127      * Ugly.  Since MetricsDynamicMBeanBase implementation is private,
128      * we need to first check the parent class for the attribute.
129      * In case that the MetricsRegistry contents have changed, this will
130      * allow the parent to update it's internal structures (which we rely on
131      * to update our own.
132      */
133     try {
134       return super.getAttribute(name);
135     } catch (AttributeNotFoundException ex) {
136 
137       checkAndUpdateAttributes();
138 
139       MetricsBase metric = this.extendedAttributes.get(name);
140       if (metric != null) {
141         if (metric instanceof MetricsRate) {
142           return ((MetricsRate) metric).getPreviousIntervalValue();
143         } else {
144           LOG.warn( String.format("unknown metrics type %s for attribute %s",
145                         metric.getClass().getName(), name) );
146         }
147       }
148     }
149 
150     throw new AttributeNotFoundException();
151   }
152 
153   @Override
154   public MBeanInfo getMBeanInfo() {
155     return this.extendedInfo;
156   }
157 
158 }