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