View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.omid.metrics;
19  
20  import com.codahale.metrics.ConsoleReporter;
21  import com.codahale.metrics.CsvReporter;
22  import com.codahale.metrics.MetricFilter;
23  import com.codahale.metrics.MetricRegistry;
24  import com.codahale.metrics.ScheduledReporter;
25  import com.codahale.metrics.Slf4jReporter;
26  import com.codahale.metrics.Timer.Context;
27  import com.codahale.metrics.graphite.Graphite;
28  import com.codahale.metrics.graphite.GraphiteReporter;
29  import com.google.common.base.Strings;
30  import com.google.common.net.HostAndPort;
31  import org.apache.commons.io.FileUtils;
32  import org.apache.omid.metrics.CodahaleMetricsConfig.Reporter;
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  
36  import java.io.File;
37  import java.io.IOException;
38  import java.net.InetSocketAddress;
39  import java.util.ArrayList;
40  import java.util.List;
41  import java.util.concurrent.TimeUnit;
42  
43  public class CodahaleMetricsProvider implements MetricsProvider, MetricsRegistry {
44  
45      private static final Logger LOG = LoggerFactory.getLogger(CodahaleMetricsProvider.class);
46  
47      private MetricRegistry metrics = new MetricRegistry();
48      private List<ScheduledReporter> reporters = new ArrayList<>();
49  
50      private final int metricsOutputFrequencyInSecs;
51  
52      public CodahaleMetricsProvider(CodahaleMetricsConfig conf) throws IOException {
53          metricsOutputFrequencyInSecs = conf.getOutputFreqInSecs();
54          int reporterCount = 0;
55          for (Reporter reporter : conf.getReporters()) {
56              ScheduledReporter codahaleReporter = null;
57              switch (reporter) {
58                  case CONSOLE:
59                      codahaleReporter = createAndGetConfiguredConsoleReporter();
60                      break;
61                  case GRAPHITE:
62                      codahaleReporter = createAndGetConfiguredGraphiteReporter(conf.getPrefix(),
63                                                                                conf.getGraphiteHostConfig());
64                      break;
65                  case CSV:
66                      codahaleReporter = createAndGetConfiguredCSVReporter(conf.getPrefix(),
67                                                                           conf.getCsvDir());
68                      break;
69                  case SLF4J:
70                      codahaleReporter = createAndGetConfiguredSlf4jReporter(conf.getSlf4jLogger());
71                      break;
72              }
73              if (codahaleReporter != null) {
74                  reporters.add(codahaleReporter);
75                  reporterCount++;
76              }
77          }
78          if (reporterCount == 0) {
79              LOG.warn("No metric reporters found, so metrics won't be available");
80          }
81          startMetrics();
82      }
83  
84      @Override
85      public void startMetrics() {
86          for (ScheduledReporter r : reporters) {
87              LOG.info("Starting metrics reporter {} reporting every {} Secs",
88                       r.getClass().getCanonicalName(), metricsOutputFrequencyInSecs);
89              r.start(metricsOutputFrequencyInSecs, TimeUnit.SECONDS);
90          }
91      }
92  
93      @Override
94      public void stopMetrics() {
95          for (ScheduledReporter r : reporters) {
96              r.report();
97              LOG.info("Stopping reporter {}", r.toString());
98              r.stop();
99          }
100     }
101 
102     @Override
103     public <T extends Number> void gauge(String name, Gauge<T> appGauge) {
104         metrics.register(name, new CodahaleGauge<>(appGauge));
105     }
106 
107     @Override
108     public Counter counter(String name) {
109         com.codahale.metrics.Counter counter = metrics.counter(name);
110         return new CodahaleCounterWrapper(counter);
111     }
112 
113 
114     @Override
115     public Timer timer(String name) {
116         com.codahale.metrics.Timer timer = metrics.timer(name);
117         return new CodahaleTimerWrapper(timer);
118     }
119 
120     @Override
121     public Meter meter(String name) {
122         com.codahale.metrics.Meter meter = metrics.meter(name);
123         return new CodahaleMeterWrapper(meter);
124     }
125 
126     @Override
127     public Histogram histogram(String name) {
128         com.codahale.metrics.Histogram histogram = metrics.histogram(name);
129         return new CodahaleHistogramWrapper(histogram);
130     }
131 
132     private ScheduledReporter createAndGetConfiguredConsoleReporter() {
133         return ConsoleReporter.forRegistry(metrics)
134                 .convertRatesTo(TimeUnit.SECONDS)
135                 .convertDurationsTo(TimeUnit.MILLISECONDS)
136                 .build();
137     }
138 
139     private ScheduledReporter createAndGetConfiguredGraphiteReporter(String prefix, String graphiteHost) {
140         LOG.info("Configuring Graphite reporter. Sendig data to host:port {}", graphiteHost);
141         HostAndPort addr = HostAndPort.fromString(graphiteHost);
142 
143         final Graphite graphite = new Graphite(
144                 new InetSocketAddress(addr.getHostText(), addr.getPort()));
145 
146         return GraphiteReporter.forRegistry(metrics)
147                 .prefixedWith(prefix)
148                 .convertRatesTo(TimeUnit.SECONDS)
149                 .convertDurationsTo(TimeUnit.MILLISECONDS)
150                 .filter(MetricFilter.ALL)
151                 .build(graphite);
152     }
153 
154     private ScheduledReporter createAndGetConfiguredCSVReporter(String prefix, String csvDir) throws IOException {
155         // NOTE:
156         // 1) metrics output files are exclusive to a given process
157         // 2) the output directory must exist
158         // 3) if output files already exist they are not overwritten and there is no metrics output
159         File outputDir;
160         if (Strings.isNullOrEmpty(prefix)) {
161             outputDir = new File(csvDir, prefix);
162         } else {
163             outputDir = new File(csvDir);
164         }
165         FileUtils.forceMkdir(outputDir);
166         LOG.info("Configuring stats with csv output to directory [{}]", outputDir.getAbsolutePath());
167         return CsvReporter.forRegistry(metrics)
168                 .convertRatesTo(TimeUnit.SECONDS)
169                 .convertDurationsTo(TimeUnit.MILLISECONDS)
170                 .build(outputDir);
171     }
172 
173 
174     private ScheduledReporter createAndGetConfiguredSlf4jReporter(String slf4jLogger) {
175         LOG.info("Configuring stats with SLF4J with logger {}", slf4jLogger);
176         return Slf4jReporter.forRegistry(metrics)
177                 .outputTo(LoggerFactory.getLogger(slf4jLogger))
178                 .convertRatesTo(TimeUnit.SECONDS)
179                 .convertDurationsTo(TimeUnit.MILLISECONDS)
180                 .build();
181     }
182 
183     /**
184      * Metrics wrapper implementations
185      */
186 
187     private static class CodahaleGauge<T extends Number> implements com.codahale.metrics.Gauge<T> {
188 
189         private final Gauge<T> omidGauge;
190 
191         CodahaleGauge(Gauge<T> omidGauge) {
192             this.omidGauge = omidGauge;
193         }
194 
195         @Override
196         public T getValue() {
197             return omidGauge.getValue();
198         }
199 
200     }
201 
202     private static class CodahaleCounterWrapper implements Counter {
203 
204         private final com.codahale.metrics.Counter counter;
205 
206         CodahaleCounterWrapper(com.codahale.metrics.Counter counter) {
207             this.counter = counter;
208         }
209 
210         @Override
211         public void inc() {
212             counter.inc();
213         }
214 
215         @Override
216         public void inc(long n) {
217             counter.inc(n);
218         }
219 
220         @Override
221         public void dec() {
222             counter.dec();
223         }
224 
225         @Override
226         public void dec(long n) {
227             counter.dec(n);
228         }
229 
230     }
231 
232     private static class CodahaleTimerWrapper implements Timer {
233 
234         private final com.codahale.metrics.Timer timer;
235 
236         private Context context;
237 
238         CodahaleTimerWrapper(com.codahale.metrics.Timer timer) {
239             this.timer = timer;
240         }
241 
242         @Override
243         public void start() {
244             context = timer.time();
245         }
246 
247         @Override
248         public void stop() {
249             context.stop();
250         }
251 
252         @Override
253         public void update(long durationInNs) {
254             timer.update(durationInNs, TimeUnit.NANOSECONDS);
255         }
256 
257     }
258 
259     private static class CodahaleMeterWrapper implements Meter {
260 
261         private com.codahale.metrics.Meter meter;
262 
263         CodahaleMeterWrapper(com.codahale.metrics.Meter meter) {
264             this.meter = meter;
265         }
266 
267         @Override
268         public void mark() {
269             meter.mark();
270         }
271 
272         @Override
273         public void mark(long n) {
274             meter.mark(n);
275         }
276 
277     }
278 
279     private static class CodahaleHistogramWrapper implements Histogram {
280 
281         private com.codahale.metrics.Histogram histogram;
282 
283         CodahaleHistogramWrapper(com.codahale.metrics.Histogram histogram) {
284             this.histogram = histogram;
285         }
286 
287         @Override
288         public void update(int value) {
289             histogram.update(value);
290         }
291 
292         @Override
293         public void update(long value) {
294             histogram.update(value);
295         }
296 
297     }
298 
299 }