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