1 /* 2 * Copyright 2018, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.contrib.dropwizard; 18 19 import com.codahale.metrics.Counter; 20 import com.codahale.metrics.Gauge; 21 import com.codahale.metrics.Histogram; 22 import com.codahale.metrics.Meter; 23 import com.codahale.metrics.Timer; 24 import io.opencensus.common.Clock; 25 import io.opencensus.common.Timestamp; 26 import io.opencensus.implcore.common.MillisClock; 27 import io.opencensus.internal.DefaultVisibilityForTesting; 28 import io.opencensus.internal.Utils; 29 import io.opencensus.metrics.LabelKey; 30 import io.opencensus.metrics.LabelValue; 31 import io.opencensus.metrics.export.Metric; 32 import io.opencensus.metrics.export.MetricDescriptor; 33 import io.opencensus.metrics.export.MetricDescriptor.Type; 34 import io.opencensus.metrics.export.MetricProducer; 35 import io.opencensus.metrics.export.Point; 36 import io.opencensus.metrics.export.Summary; 37 import io.opencensus.metrics.export.Summary.Snapshot; 38 import io.opencensus.metrics.export.Summary.Snapshot.ValueAtPercentile; 39 import io.opencensus.metrics.export.TimeSeries; 40 import io.opencensus.metrics.export.Value; 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.Collection; 44 import java.util.Collections; 45 import java.util.List; 46 import java.util.Map.Entry; 47 import javax.annotation.Nullable; 48 49 /** 50 * Collects DropWizard metrics from a list {@link com.codahale.metrics.MetricRegistry}s. 51 * 52 * <p>A {@link io.opencensus.metrics.export.MetricProducer} that wraps a DropWizardMetrics. 53 * 54 * @since 0.17 55 */ 56 public class DropWizardMetrics extends MetricProducer { 57 @DefaultVisibilityForTesting static final String DEFAULT_UNIT = "1"; 58 private final List<com.codahale.metrics.MetricRegistry> metricRegistryList; 59 private final Clock clock; 60 private final Timestamp cumulativeStartTimestamp; 61 62 /** 63 * Hook the Dropwizard registry into the OpenCensus registry. 64 * 65 * @param metricRegistryList a list of {@link com.codahale.metrics.MetricRegistry}s. 66 * @since 0.17 67 */ DropWizardMetrics(List<com.codahale.metrics.MetricRegistry> metricRegistryList)68 public DropWizardMetrics(List<com.codahale.metrics.MetricRegistry> metricRegistryList) { 69 Utils.checkNotNull(metricRegistryList, "metricRegistryList"); 70 Utils.checkListElementNotNull(metricRegistryList, "metricRegistryList"); 71 this.metricRegistryList = metricRegistryList; 72 clock = MillisClock.getInstance(); 73 cumulativeStartTimestamp = clock.now(); 74 } 75 76 /** 77 * Returns a {@code Metric} collected from {@link Gauge}. 78 * 79 * @param dropwizardName the metric name. 80 * @param gauge the gauge object to collect. 81 * @return a {@code Metric}. 82 */ 83 @SuppressWarnings("rawtypes") collectGauge(String dropwizardName, Gauge gauge)84 private @Nullable Metric collectGauge(String dropwizardName, Gauge gauge) { 85 String metricName = DropWizardUtils.generateFullMetricName(dropwizardName, "gauge"); 86 String metricDescription = DropWizardUtils.generateFullMetricDescription(dropwizardName, gauge); 87 88 // Figure out which gauge instance and call the right method to get value 89 Type type; 90 Value value; 91 92 Object obj = gauge.getValue(); 93 if (obj instanceof Number) { 94 type = Type.GAUGE_DOUBLE; 95 value = Value.doubleValue(((Number) obj).doubleValue()); 96 } else if (obj instanceof Boolean) { 97 type = Type.GAUGE_INT64; 98 value = Value.longValue(((Boolean) obj) ? 1 : 0); 99 } else { 100 // Ignoring Gauge (gauge.getKey()) with unhandled type. 101 return null; 102 } 103 104 MetricDescriptor metricDescriptor = 105 MetricDescriptor.create( 106 metricName, metricDescription, DEFAULT_UNIT, type, Collections.<LabelKey>emptyList()); 107 TimeSeries timeSeries = 108 TimeSeries.createWithOnePoint( 109 Collections.<LabelValue>emptyList(), Point.create(value, clock.now()), null); 110 return Metric.createWithOneTimeSeries(metricDescriptor, timeSeries); 111 } 112 113 /** 114 * Returns a {@code Metric} collected from {@link Counter}. 115 * 116 * @param dropwizardName the metric name. 117 * @param counter the counter object to collect. 118 * @return a {@code Metric}. 119 */ collectCounter(String dropwizardName, Counter counter)120 private Metric collectCounter(String dropwizardName, Counter counter) { 121 String metricName = DropWizardUtils.generateFullMetricName(dropwizardName, "counter"); 122 String metricDescription = 123 DropWizardUtils.generateFullMetricDescription(dropwizardName, counter); 124 125 MetricDescriptor metricDescriptor = 126 MetricDescriptor.create( 127 metricName, 128 metricDescription, 129 DEFAULT_UNIT, 130 Type.GAUGE_INT64, 131 Collections.<LabelKey>emptyList()); 132 TimeSeries timeSeries = 133 TimeSeries.createWithOnePoint( 134 Collections.<LabelValue>emptyList(), 135 Point.create(Value.longValue(counter.getCount()), clock.now()), 136 null); 137 return Metric.createWithOneTimeSeries(metricDescriptor, timeSeries); 138 } 139 140 /** 141 * Returns a {@code Metric} collected from {@link Meter}. 142 * 143 * @param dropwizardName the metric name. 144 * @param meter the meter object to collect 145 * @return a {@code Metric}. 146 */ collectMeter(String dropwizardName, Meter meter)147 private Metric collectMeter(String dropwizardName, Meter meter) { 148 String metricName = DropWizardUtils.generateFullMetricName(dropwizardName, "meter"); 149 String metricDescription = DropWizardUtils.generateFullMetricDescription(dropwizardName, meter); 150 151 MetricDescriptor metricDescriptor = 152 MetricDescriptor.create( 153 metricName, 154 metricDescription, 155 DEFAULT_UNIT, 156 Type.CUMULATIVE_INT64, 157 Collections.<LabelKey>emptyList()); 158 TimeSeries timeSeries = 159 TimeSeries.createWithOnePoint( 160 Collections.<LabelValue>emptyList(), 161 Point.create(Value.longValue(meter.getCount()), clock.now()), 162 null); 163 164 return Metric.createWithOneTimeSeries(metricDescriptor, timeSeries); 165 } 166 167 /** 168 * Returns a {@code Metric} collected from {@link Histogram}. 169 * 170 * @param dropwizardName the metric name. 171 * @param histogram the histogram object to collect 172 * @return a {@code Metric}. 173 */ collectHistogram(String dropwizardName, Histogram histogram)174 private Metric collectHistogram(String dropwizardName, Histogram histogram) { 175 String metricName = DropWizardUtils.generateFullMetricName(dropwizardName, "histogram"); 176 String metricDescription = 177 DropWizardUtils.generateFullMetricDescription(dropwizardName, histogram); 178 return collectSnapshotAndCount( 179 metricName, metricDescription, histogram.getSnapshot(), histogram.getCount()); 180 } 181 182 /** 183 * Returns a {@code Metric} collected from {@link Timer}. 184 * 185 * @param dropwizardName the metric name. 186 * @param timer the timer object to collect 187 * @return a {@code Metric}. 188 */ collectTimer(String dropwizardName, Timer timer)189 private Metric collectTimer(String dropwizardName, Timer timer) { 190 String metricName = DropWizardUtils.generateFullMetricName(dropwizardName, "timer"); 191 String metricDescription = DropWizardUtils.generateFullMetricDescription(dropwizardName, timer); 192 return collectSnapshotAndCount( 193 metricName, metricDescription, timer.getSnapshot(), timer.getCount()); 194 } 195 196 /** 197 * Returns a {@code Metric} collected from {@link Snapshot}. 198 * 199 * @param metricName the metric name. 200 * @param metricDescription the metric description. 201 * @param codahaleSnapshot the snapshot object to collect 202 * @param count the value or count 203 * @return a {@code Metric}. 204 */ collectSnapshotAndCount( String metricName, String metricDescription, com.codahale.metrics.Snapshot codahaleSnapshot, long count)205 private Metric collectSnapshotAndCount( 206 String metricName, 207 String metricDescription, 208 com.codahale.metrics.Snapshot codahaleSnapshot, 209 long count) { 210 List<ValueAtPercentile> valueAtPercentiles = 211 Arrays.asList( 212 ValueAtPercentile.create(50.0, codahaleSnapshot.getMedian()), 213 ValueAtPercentile.create(75.0, codahaleSnapshot.get75thPercentile()), 214 ValueAtPercentile.create(98.0, codahaleSnapshot.get98thPercentile()), 215 ValueAtPercentile.create(99.0, codahaleSnapshot.get99thPercentile()), 216 ValueAtPercentile.create(99.9, codahaleSnapshot.get999thPercentile())); 217 218 Snapshot snapshot = Snapshot.create((long) codahaleSnapshot.size(), 0.0, valueAtPercentiles); 219 Point point = 220 Point.create(Value.summaryValue(Summary.create(count, 0.0, snapshot)), clock.now()); 221 222 // TODO(mayurkale): OPTIMIZATION: Cache the MetricDescriptor objects. 223 MetricDescriptor metricDescriptor = 224 MetricDescriptor.create( 225 metricName, 226 metricDescription, 227 DEFAULT_UNIT, 228 Type.SUMMARY, 229 Collections.<LabelKey>emptyList()); 230 TimeSeries timeSeries = 231 TimeSeries.createWithOnePoint( 232 Collections.<LabelValue>emptyList(), point, cumulativeStartTimestamp); 233 234 return Metric.createWithOneTimeSeries(metricDescriptor, timeSeries); 235 } 236 237 @Override 238 @SuppressWarnings("rawtypes") getMetrics()239 public Collection<Metric> getMetrics() { 240 ArrayList<Metric> metrics = new ArrayList<Metric>(); 241 242 for (com.codahale.metrics.MetricRegistry metricRegistry : metricRegistryList) { 243 for (Entry<String, Counter> counterEntry : metricRegistry.getCounters().entrySet()) { 244 metrics.add(collectCounter(counterEntry.getKey(), counterEntry.getValue())); 245 } 246 247 for (Entry<String, Gauge> gaugeEntry : metricRegistry.getGauges().entrySet()) { 248 Metric metric = collectGauge(gaugeEntry.getKey(), gaugeEntry.getValue()); 249 if (metric != null) { 250 metrics.add(metric); 251 } 252 } 253 254 for (Entry<String, Meter> counterEntry : metricRegistry.getMeters().entrySet()) { 255 metrics.add(collectMeter(counterEntry.getKey(), counterEntry.getValue())); 256 } 257 258 for (Entry<String, Histogram> counterEntry : metricRegistry.getHistograms().entrySet()) { 259 metrics.add(collectHistogram(counterEntry.getKey(), counterEntry.getValue())); 260 } 261 262 for (Entry<String, Timer> counterEntry : metricRegistry.getTimers().entrySet()) { 263 metrics.add(collectTimer(counterEntry.getKey(), counterEntry.getValue())); 264 } 265 } 266 267 return metrics; 268 } 269 } 270