View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.metrics;
20  
21  import java.util.ArrayList;
22  import java.util.List;
23  import java.util.Map;
24  import java.util.concurrent.ConcurrentHashMap;
25  
26  import javax.management.AttributeNotFoundException;
27  import javax.management.MBeanAttributeInfo;
28  import javax.management.MBeanException;
29  import javax.management.MBeanInfo;
30  import javax.management.ReflectionException;
31  
32  import com.yammer.metrics.stats.Snapshot;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  import org.apache.hadoop.classification.InterfaceAudience;
36  import org.apache.hadoop.hbase.metrics.histogram.MetricsHistogram;
37  import org.apache.hadoop.metrics.util.MetricsBase;
38  import org.apache.hadoop.metrics.util.MetricsDynamicMBeanBase;
39  import org.apache.hadoop.metrics.util.MetricsRegistry;
40  
41  /**
42   * Extends the Hadoop MetricsDynamicMBeanBase class to provide JMX support for
43   * custom HBase MetricsBase implementations.  MetricsDynamicMBeanBase ignores
44   * registered MetricsBase instance that are not instances of one of the
45   * org.apache.hadoop.metrics.util implementations.
46   *
47   */
48  @Deprecated
49  @InterfaceAudience.Private
50  public class MetricsMBeanBase extends MetricsDynamicMBeanBase {
51  
52    private static final Log LOG = LogFactory.getLog("org.apache.hadoop.hbase.metrics");
53  
54    protected final MetricsRegistry registry;
55    protected final String description;
56    protected int registryLength;
57    /** HBase MetricsBase implementations that MetricsDynamicMBeanBase does
58     * not understand
59     */
60    protected Map<String, MetricsBase> extendedAttributes =
61        new ConcurrentHashMap<String, MetricsBase>();
62    protected MBeanInfo extendedInfo;
63  
64    protected MetricsMBeanBase( MetricsRegistry mr, String description ) {
65      super(copyMinusHBaseMetrics(mr), description);
66      this.registry = mr;
67      this.description = description;
68      this.init();
69    }
70  
71    /*
72     * @param mr MetricsRegistry.
73     * @return A copy of the passed MetricsRegistry minus the hbase metrics
74     */
75    private static MetricsRegistry copyMinusHBaseMetrics(final MetricsRegistry mr) {
76      MetricsRegistry copy = new MetricsRegistry();
77      for (MetricsBase metric : mr.getMetricsList()) {
78        if (metric instanceof MetricsRate || metric instanceof MetricsString ||
79            metric instanceof MetricsHistogram || metric instanceof ExactCounterMetric) {
80          continue;
81        }
82        copy.add(metric.getName(), metric);
83      }
84      return copy;
85    }
86  
87    protected void init() {
88      List<MBeanAttributeInfo> attributes = new ArrayList<MBeanAttributeInfo>();
89      MBeanInfo parentInfo = super.getMBeanInfo();
90      List<String> parentAttributes = new ArrayList<String>();
91      for (MBeanAttributeInfo attr : parentInfo.getAttributes()) {
92        attributes.add(attr);
93        parentAttributes.add(attr.getName());
94      }
95  
96      this.registryLength = this.registry.getMetricsList().size();
97  
98      for (MetricsBase metric : this.registry.getMetricsList()) {
99        if (metric.getName() == null || parentAttributes.contains(metric.getName()))
100         continue;
101 
102       // add on custom HBase metric types
103       if (metric instanceof MetricsRate) {
104         attributes.add( new MBeanAttributeInfo(metric.getName(),
105             "java.lang.Float", metric.getDescription(), true, false, false) );
106         extendedAttributes.put(metric.getName(), metric);
107       } else if (metric instanceof MetricsString) {
108         attributes.add( new MBeanAttributeInfo(metric.getName(),
109             "java.lang.String", metric.getDescription(), true, false, false) );
110         extendedAttributes.put(metric.getName(), metric);
111         LOG.info("MetricsString added: " + metric.getName());
112       } else if (metric instanceof MetricsHistogram) {
113 
114         String metricName = metric.getName() + MetricsHistogram.NUM_OPS_METRIC_NAME;
115         attributes.add(new MBeanAttributeInfo(metricName,
116             "java.lang.Long", metric.getDescription(), true, false, false));
117         extendedAttributes.put(metricName, metric);
118 
119         metricName = metric.getName() + MetricsHistogram.MIN_METRIC_NAME;
120         attributes.add(new MBeanAttributeInfo(metricName,
121             "java.lang.Long", metric.getDescription(), true, false, false));
122         extendedAttributes.put(metricName, metric);
123 
124         metricName = metric.getName() + MetricsHistogram.MAX_METRIC_NAME;
125         attributes.add(new MBeanAttributeInfo(metricName,
126             "java.lang.Long", metric.getDescription(), true, false, false));
127         extendedAttributes.put(metricName, metric);
128 
129         metricName = metric.getName() + MetricsHistogram.MEAN_METRIC_NAME;
130         attributes.add(new MBeanAttributeInfo(metricName,
131             "java.lang.Float", metric.getDescription(), true, false, false));
132         extendedAttributes.put(metricName, metric);
133 
134         metricName = metric.getName() + MetricsHistogram.STD_DEV_METRIC_NAME;
135         attributes.add(new MBeanAttributeInfo(metricName,
136             "java.lang.Float", metric.getDescription(), true, false, false));
137         extendedAttributes.put(metricName, metric);
138 
139         metricName = metric.getName() + MetricsHistogram.MEDIAN_METRIC_NAME;
140         attributes.add(new MBeanAttributeInfo(metricName,
141             "java.lang.Float", metric.getDescription(), true, false, false));
142         extendedAttributes.put(metricName, metric);
143 
144         metricName = metric.getName() + MetricsHistogram.SEVENTY_FIFTH_PERCENTILE_METRIC_NAME;
145         attributes.add(new MBeanAttributeInfo(metricName,
146             "java.lang.Float", metric.getDescription(), true, false, false));
147         extendedAttributes.put(metricName, metric);
148 
149         metricName = metric.getName() + MetricsHistogram.NINETY_FIFTH_PERCENTILE_METRIC_NAME;
150         attributes.add(new MBeanAttributeInfo(metricName,
151             "java.lang.Float", metric.getDescription(), true, false, false));
152         extendedAttributes.put(metricName, metric);
153 
154         metricName = metric.getName() + MetricsHistogram.NINETY_NINETH_PERCENTILE_METRIC_NAME;
155         attributes.add(new MBeanAttributeInfo(metricName,
156             "java.lang.Float", metric.getDescription(), true, false, false));
157         extendedAttributes.put(metricName, metric);
158       }
159       // else, its probably a hadoop metric already registered. Skip it.
160     }
161 
162     LOG.info("new MBeanInfo");
163     this.extendedInfo = new MBeanInfo( this.getClass().getName(),
164         this.description, attributes.toArray( new MBeanAttributeInfo[0] ),
165         parentInfo.getConstructors(), parentInfo.getOperations(),
166         parentInfo.getNotifications() );
167   }
168 
169   private void checkAndUpdateAttributes() {
170     if (this.registryLength != this.registry.getMetricsList().size())
171       this.init();
172   }
173 
174   @Override
175   public Object getAttribute( String name )
176       throws AttributeNotFoundException, MBeanException,
177       ReflectionException {
178 
179     if (name == null) {
180       throw new IllegalArgumentException("Attribute name is NULL");
181     }
182 
183     /*
184      * Ugly.  Since MetricsDynamicMBeanBase implementation is private,
185      * we need to first check the parent class for the attribute.
186      * In case that the MetricsRegistry contents have changed, this will
187      * allow the parent to update it's internal structures (which we rely on
188      * to update our own.
189      */
190     try {
191       return super.getAttribute(name);
192     } catch (AttributeNotFoundException ex) {
193 
194       checkAndUpdateAttributes();
195 
196       MetricsBase metric = this.extendedAttributes.get(name);
197       if (metric != null) {
198         if (metric instanceof MetricsRate) {
199           return ((MetricsRate) metric).getPreviousIntervalValue();
200         } else if (metric instanceof MetricsString) {
201           return ((MetricsString)metric).getValue();
202         } else if (metric instanceof MetricsHistogram)  {
203           MetricsHistogram hist = (MetricsHistogram) metric;
204           if (name.endsWith(MetricsHistogram.NUM_OPS_METRIC_NAME)) {
205             return hist.getCount();
206           } else if (name.endsWith(MetricsHistogram.MIN_METRIC_NAME)) {
207             return hist.getMin();
208           } else if (name.endsWith(MetricsHistogram.MAX_METRIC_NAME)) {
209             return hist.getMax();
210           } else if (name.endsWith(MetricsHistogram.MEAN_METRIC_NAME)) {
211             return (float) hist.getMean();
212           } else if (name.endsWith(MetricsHistogram.STD_DEV_METRIC_NAME)) {
213             return (float) hist.getStdDev();
214           } else if (name.endsWith(MetricsHistogram.MEDIAN_METRIC_NAME)) {
215             Snapshot s = hist.getSnapshot();
216             return (float) s.getMedian();
217           } else if (name.endsWith(MetricsHistogram.SEVENTY_FIFTH_PERCENTILE_METRIC_NAME)) {
218             Snapshot s = hist.getSnapshot();
219             return (float) s.get75thPercentile();
220           } else if (name.endsWith(MetricsHistogram.NINETY_FIFTH_PERCENTILE_METRIC_NAME)) {
221             Snapshot s = hist.getSnapshot();
222             return (float) s.get95thPercentile();
223           } else if (name.endsWith(MetricsHistogram.NINETY_NINETH_PERCENTILE_METRIC_NAME)) {
224             Snapshot s = hist.getSnapshot();
225             return (float) s.get99thPercentile();
226           }
227 
228         } else {
229           LOG.warn( String.format("unknown metrics type %s for attribute %s",
230                         metric.getClass().getName(), name) );
231         }
232       }
233     }
234 
235     throw new AttributeNotFoundException();
236   }
237 
238   @Override
239   public MBeanInfo getMBeanInfo() {
240     return this.extendedInfo;
241   }
242 
243 }