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 MetricsRate || metric instanceof MetricsString) {
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 MetricsRate) {
99          attributes.add( new MBeanAttributeInfo(metric.getName(),
100             "java.lang.Float", metric.getDescription(), true, false, false) );
101         extendedAttributes.put(metric.getName(), metric);
102       } else if (metric instanceof MetricsString) {
103         attributes.add( new MBeanAttributeInfo(metric.getName(),
104             "java.lang.String", metric.getDescription(), true, false, false) );
105         extendedAttributes.put(metric.getName(), metric);
106         LOG.info("MetricsString added: " + metric.getName());
107       }
108       // else, its probably a hadoop metric already registered. Skip it.
109     }
110 
111     LOG.info("new MBeanInfo");
112     this.extendedInfo = new MBeanInfo( this.getClass().getName(),
113         this.description, attributes.toArray( new MBeanAttributeInfo[0] ),
114         parentInfo.getConstructors(), parentInfo.getOperations(),
115         parentInfo.getNotifications() );
116   }
117 
118   private void checkAndUpdateAttributes() {
119     if (this.registryLength != this.registry.getMetricsList().size())
120       this.init();
121   }
122 
123   @Override
124   public Object getAttribute( String name )
125       throws AttributeNotFoundException, MBeanException,
126       ReflectionException {
127 
128     if (name == null) {
129       throw new IllegalArgumentException("Attribute name is NULL");
130     }
131 
132     /*
133      * Ugly.  Since MetricsDynamicMBeanBase implementation is private,
134      * we need to first check the parent class for the attribute.
135      * In case that the MetricsRegistry contents have changed, this will
136      * allow the parent to update it's internal structures (which we rely on
137      * to update our own.
138      */
139     try {
140       return super.getAttribute(name);
141     } catch (AttributeNotFoundException ex) {
142 
143       checkAndUpdateAttributes();
144 
145       MetricsBase metric = this.extendedAttributes.get(name);
146       if (metric != null) {
147         if (metric instanceof MetricsRate) {
148           return ((MetricsRate) metric).getPreviousIntervalValue();
149         } else if (metric instanceof MetricsString) {
150           return ((MetricsString)metric).getValue();
151         } else {
152           LOG.warn( String.format("unknown metrics type %s for attribute %s",
153                         metric.getClass().getName(), name) );
154         }
155       }
156     }
157 
158     throw new AttributeNotFoundException();
159   }
160 
161   @Override
162   public MBeanInfo getMBeanInfo() {
163     return this.extendedInfo;
164   }
165 
166 }