001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.hbase.metrics;
020
021import org.apache.hadoop.hbase.metrics.impl.GlobalMetricRegistriesAdapter;
022import org.apache.hadoop.hbase.metrics.impl.HBaseMetrics2HadoopMetricsAdapter;
023import org.apache.hadoop.hbase.regionserver.MetricsRegionServerSourceImpl;
024import org.apache.hadoop.metrics2.MetricsCollector;
025import org.apache.hadoop.metrics2.MetricsSource;
026import org.apache.hadoop.metrics2.impl.JmxCacheBuster;
027import org.apache.hadoop.metrics2.lib.DefaultMetricsSystem;
028import org.apache.hadoop.metrics2.lib.DynamicMetricsRegistry;
029import org.apache.hadoop.metrics2.lib.MutableFastCounter;
030import org.apache.hadoop.metrics2.lib.MutableGaugeLong;
031import org.apache.hadoop.metrics2.lib.MutableHistogram;
032import org.apache.hadoop.metrics2.source.JvmMetrics;
033import org.apache.yetus.audience.InterfaceAudience;
034
035/**
036 * Hadoop 2 implementation of BaseSource (using metrics2 framework).  It handles registration to
037 * DefaultMetricsSystem and creation of the metrics registry.
038 *
039 * All MetricsSource's in hbase-hadoop2-compat should derive from this class.
040 */
041@InterfaceAudience.Private
042public class BaseSourceImpl implements BaseSource, MetricsSource {
043
044  private static enum DefaultMetricsSystemInitializer {
045    INSTANCE;
046    private boolean inited = false;
047
048    synchronized void init(String name) {
049      if (inited) {
050        return;
051      }
052
053      inited = true;
054      DefaultMetricsSystem.initialize(HBASE_METRICS_SYSTEM_NAME);
055      JvmMetrics.initSingleton(name, "");
056      // initialize hbase-metrics module based metric system as well. GlobalMetricRegistriesSource
057      // initialization depends on the metric system being already initialized, that is why we are
058      // doing it here. Once BaseSourceSourceImpl is removed, we should do the initialization of
059      // these elsewhere.
060      GlobalMetricRegistriesAdapter.init();
061    }
062  }
063
064  /**
065   * @deprecated Use hbase-metrics/hbase-metrics-api module interfaces for new metrics.
066   *             Defining BaseSources for new metric groups (WAL, RPC, etc) is not needed anymore,
067   *             however, for existing {@link BaseSource} implementations, please use the field
068   *             named "registry" which is a {@link MetricRegistry} instance together with the
069   *             {@link HBaseMetrics2HadoopMetricsAdapter}.
070   */
071  @Deprecated
072  protected final DynamicMetricsRegistry metricsRegistry;
073  protected final String metricsName;
074  protected final String metricsDescription;
075  protected final String metricsContext;
076  protected final String metricsJmxContext;
077
078  /**
079   * Note that there are at least 4 MetricRegistry definitions in the source code. The first one is
080   * Hadoop Metrics2 MetricRegistry, second one is DynamicMetricsRegistry which is HBase's fork
081   * of the Hadoop metrics2 class. The third one is the dropwizard metrics implementation of
082   * MetricRegistry, and finally a new API abstraction in HBase that is the
083   * o.a.h.h.metrics.MetricRegistry class. This last one is the new way to use metrics within the
084   * HBase code. However, the others are in play because of existing metrics2 based code still
085   * needs to coexists until we get rid of all of our BaseSource and convert them to the new
086   * framework. Until that happens, new metrics can use the new API, but will be collected
087   * through the HBaseMetrics2HadoopMetricsAdapter class.
088   *
089   * BaseSourceImpl has two MetricRegistries. metricRegistry is for hadoop Metrics2 based
090   * metrics, while the registry is for hbase-metrics based metrics.
091   */
092  protected final MetricRegistry registry;
093
094  /**
095   * The adapter from hbase-metrics module to metrics2. This adepter is the connection between the
096   * Metrics in the MetricRegistry and the Hadoop Metrics2 system. Using this adapter, existing
097   * BaseSource implementations can define new metrics using the hbase-metrics/hbase-metrics-api
098   * module interfaces and still be able to make use of metrics2 sinks (including JMX). Existing
099   * BaseSources should call metricsAdapter.snapshotAllMetrics() in getMetrics() method. See
100   * {@link MetricsRegionServerSourceImpl}.
101   */
102  protected final HBaseMetrics2HadoopMetricsAdapter metricsAdapter;
103
104  public BaseSourceImpl(
105      String metricsName,
106      String metricsDescription,
107      String metricsContext,
108      String metricsJmxContext) {
109
110    this.metricsName = metricsName;
111    this.metricsDescription = metricsDescription;
112    this.metricsContext = metricsContext;
113    this.metricsJmxContext = metricsJmxContext;
114
115    metricsRegistry = new DynamicMetricsRegistry(metricsName).setContext(metricsContext);
116    DefaultMetricsSystemInitializer.INSTANCE.init(metricsName);
117
118    //Register this instance.
119    DefaultMetricsSystem.instance().register(metricsJmxContext, metricsDescription, this);
120
121    // hbase-metrics module based metrics are registered in the hbase MetricsRegistry.
122    registry = MetricRegistries.global().create(this.getMetricRegistryInfo());
123    metricsAdapter = new HBaseMetrics2HadoopMetricsAdapter();
124
125    init();
126
127  }
128
129  public void init() {
130    this.metricsRegistry.clearMetrics();
131  }
132
133  /**
134   * Set a single gauge to a value.
135   *
136   * @param gaugeName gauge name
137   * @param value     the new value of the gauge.
138   */
139  public void setGauge(String gaugeName, long value) {
140    MutableGaugeLong gaugeInt = metricsRegistry.getGauge(gaugeName, value);
141    gaugeInt.set(value);
142  }
143
144  /**
145   * Add some amount to a gauge.
146   *
147   * @param gaugeName The name of the gauge to increment.
148   * @param delta     The amount to increment the gauge by.
149   */
150  public void incGauge(String gaugeName, long delta) {
151    MutableGaugeLong gaugeInt = metricsRegistry.getGauge(gaugeName, 0L);
152    gaugeInt.incr(delta);
153  }
154
155  /**
156   * Decrease the value of a named gauge.
157   *
158   * @param gaugeName The name of the gauge.
159   * @param delta     the ammount to subtract from a gauge value.
160   */
161  public void decGauge(String gaugeName, long delta) {
162    MutableGaugeLong gaugeInt = metricsRegistry.getGauge(gaugeName, 0L);
163    gaugeInt.decr(delta);
164  }
165
166  /**
167   * Increment a named counter by some value.
168   *
169   * @param key   the name of the counter
170   * @param delta the ammount to increment
171   */
172  public void incCounters(String key, long delta) {
173    MutableFastCounter counter = metricsRegistry.getCounter(key, 0L);
174    counter.incr(delta);
175
176  }
177
178  @Override
179  public void updateHistogram(String name, long value) {
180    MutableHistogram histo = metricsRegistry.getHistogram(name);
181    histo.add(value);
182  }
183
184  /**
185   * Remove a named gauge.
186   *
187   * @param key the key of the gauge to remove
188   */
189  public void removeMetric(String key) {
190    metricsRegistry.removeMetric(key);
191    JmxCacheBuster.clearJmxCache();
192  }
193
194  @Override
195  public void getMetrics(MetricsCollector metricsCollector, boolean all) {
196    metricsRegistry.snapshot(metricsCollector.addRecord(metricsRegistry.info()), all);
197  }
198
199  public DynamicMetricsRegistry getMetricsRegistry() {
200    return metricsRegistry;
201  }
202
203  public String getMetricsContext() {
204    return metricsContext;
205  }
206
207  public String getMetricsDescription() {
208    return metricsDescription;
209  }
210
211  public String getMetricsJmxContext() {
212    return metricsJmxContext;
213  }
214
215  public String getMetricsName() {
216    return metricsName;
217  }
218
219}