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
20
21 package org.apache.hadoop.hbase.coprocessor.example;
22
23 import java.io.IOException;
24 import java.util.List;
25 import java.util.concurrent.ThreadLocalRandom;
26
27 import org.apache.hadoop.hbase.Cell;
28 import org.apache.hadoop.hbase.CoprocessorEnvironment;
29 import org.apache.hadoop.hbase.client.Get;
30 import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
31 import org.apache.hadoop.hbase.coprocessor.ObserverContext;
32 import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
33 import org.apache.hadoop.hbase.metrics.Counter;
34 import org.apache.hadoop.hbase.metrics.MetricRegistry;
35 import org.apache.hadoop.hbase.metrics.Timer;
36
37 /**
38 * An example coprocessor that collects some metrics to demonstrate the usage of exporting custom
39 * metrics from the coprocessor.
40 * <p>
41 * These metrics will be available through the regular Hadoop metrics2 sinks (ganglia, opentsdb,
42 * etc) as well as JMX output. You can view a snapshot of the metrics by going to the http web UI
43 * of the regionserver page, something like http://myregionserverhost:16030/jmx
44 * </p>
45 *
46 * @see ExampleMasterObserverWithMetrics
47 */
48 public class ExampleRegionObserverWithMetrics extends BaseRegionObserver {
49
50 private Counter preGetCounter;
51 private Timer costlyOperationTimer;
52
53 @Override
54 public void preGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get, List<Cell> results)
55 throws IOException {
56 super.preGetOp(e, get, results);
57
58 // Increment the Counter whenever the coprocessor is called
59 preGetCounter.increment();
60 }
61
62 @Override
63 public void postGetOp(ObserverContext<RegionCoprocessorEnvironment> e, Get get,
64 List<Cell> results) throws IOException {
65 super.postGetOp(e, get, results);
66
67 // do a costly (high latency) operation which we want to measure how long it takes by
68 // using a Timer (which is a Meter and a Histogram).
69 long start = System.nanoTime();
70 try {
71 performCostlyOperation();
72 } finally {
73 costlyOperationTimer.updateNanos(System.nanoTime() - start);
74 }
75 }
76
77 private void performCostlyOperation() {
78 try {
79 // simulate the operation by sleeping.
80 Thread.sleep(ThreadLocalRandom.current().nextLong(100));
81 } catch (InterruptedException ignore) {}
82 }
83
84 @Override
85 public void start(CoprocessorEnvironment env) throws IOException {
86 super.start(env);
87
88 // start for the RegionServerObserver will be called only once in the lifetime of the
89 // server. We will construct and register all metrics that we will track across method
90 // invocations.
91
92 if (env instanceof RegionCoprocessorEnvironment) {
93 // Obtain the MetricRegistry for the RegionServer. Metrics from this registry will be reported
94 // at the region server level per-regionserver.
95 MetricRegistry registry =
96 ((RegionCoprocessorEnvironment) env).getMetricRegistryForRegionServer();
97
98 if (preGetCounter == null) {
99 // Create a new Counter, or get the already registered counter.
100 // It is much better to only call this once and save the Counter as a class field instead
101 // of creating the counter every time a coprocessor method is invoked. This will negate
102 // any performance bottleneck coming from map lookups tracking metrics in the registry.
103 // Returned counter instance is shared by all coprocessors of the same class in the same
104 // region server.
105 preGetCounter = registry.counter("preGetRequests");
106 }
107
108 if (costlyOperationTimer == null) {
109 // Create a Timer to track execution times for the costly operation.
110 costlyOperationTimer = registry.timer("costlyOperation");
111 }
112 }
113 }
114
115 @Override
116 public void stop(CoprocessorEnvironment e) throws IOException {
117 // we should NOT remove / deregister the metrics in stop(). The whole registry will be
118 // removed when the last region of the table is closed.
119 super.stop(e);
120 }
121 }