1   /*
2    * Copyright 2011 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  
21  package org.apache.hadoop.hbase.regionserver;
22  
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Map;
26  import java.util.Random;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  import org.apache.hadoop.conf.Configuration;
31  import org.apache.hadoop.hbase.HBaseTestingUtility;
32  import org.apache.hadoop.hbase.ipc.HBaseRpcMetrics;
33  import org.apache.hadoop.metrics.ContextFactory;
34  import org.apache.hadoop.metrics.MetricsContext;
35  import org.apache.hadoop.metrics.MetricsUtil;
36  import org.apache.hadoop.metrics.spi.AbstractMetricsContext;
37  import org.apache.hadoop.metrics.spi.OutputRecord;
38  import org.junit.AfterClass;
39  import org.junit.BeforeClass;
40  import org.junit.Test;
41  
42  import static org.junit.Assert.*;
43  
44  public class TestRpcMetrics {
45    /**
46     * Defines test methods to register with HBaseRpcMetrics
47     */
48    public interface TestMetrics {
49      public void test();
50    }
51  
52    /**
53     * HRegionServer sub-class to register custom metrics
54     */
55    public static class TestRegionServer extends HRegionServer {
56  
57      public TestRegionServer(Configuration conf)
58          throws IOException, InterruptedException {
59        super(conf);
60  
61        // register custom metrics interface
62        getRpcMetrics().createMetrics(new Class[]{TestMetrics.class}, true);
63      }
64  
65      public void incTest(int amt) {
66        HBaseRpcMetrics metrics = getRpcMetrics();
67        // force an increment so we have something to check for
68        metrics.inc(metrics.getMetricName(TestMetrics.class, "test"), amt);
69      }
70    }
71  
72    /**
73     * Dummy metrics context to allow retrieval of values
74     */
75    public static class MockMetricsContext extends AbstractMetricsContext {
76  
77      public MockMetricsContext() {
78        // update every 1 sec.
79        setPeriod(1);
80      }
81  
82      @Override
83      protected void emitRecord(String contextName, String recordName,
84          OutputRecord outputRecord) throws IOException {
85        for (String name : outputRecord.getMetricNames()) {
86          Number val = outputRecord.getMetric(name);
87          if (val != null && val.intValue() > 0) {
88            METRICS.put(name, Boolean.TRUE);
89            LOG.debug("Set metric "+name+" to "+val);
90          }
91        }
92      }
93    }
94    private static Map<String,Boolean> METRICS = new HashMap<String,Boolean>();
95  
96    private static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
97    private static Log LOG = LogFactory.getLog(TestRpcMetrics.class);
98  
99    @BeforeClass
100   public static void setupBeforeClass() throws Exception {
101     // set custom metrics context
102     ContextFactory factory = ContextFactory.getFactory();
103     factory.setAttribute("rpc.class", MockMetricsContext.class.getName());
104     // make sure metrics context is setup, otherwise updating won't start
105     MetricsContext ctx = MetricsUtil.getContext("rpc");
106     assertTrue("Wrong MetricContext implementation class",
107         (ctx instanceof MockMetricsContext));
108 
109     TEST_UTIL.startMiniZKCluster();
110   }
111 
112   @AfterClass
113   public static void tearDownAfterClass() throws Exception {
114     TEST_UTIL.shutdownMiniZKCluster();
115   }
116 
117   @Test
118   public void testCustomMetrics() throws Exception {
119     TEST_UTIL.getConfiguration().setInt("hbase.regionserver.port", 0);
120     TestRegionServer rs = new TestRegionServer(TEST_UTIL.getConfiguration());
121     rs.incTest(5);
122 
123     // wait for metrics context update
124     Thread.sleep(1000);
125 
126     String metricName = HBaseRpcMetrics.getMetricName(TestMetrics.class, "test");
127     assertTrue("Metric should have set incremented for "+metricName,
128         wasSet(metricName + "_num_ops"));
129   }
130 
131   public boolean wasSet(String name) {
132     return METRICS.get(name) != null ? METRICS.get(name) : false;
133   }
134 }