Back to home page

OSCL-LXR

 
 

    


0001 // Copied from
0002 // https://raw.githubusercontent.com/dropwizard/metrics/v3.2.6/metrics-ganglia/
0003 //   src/main/java/com/codahale/metrics/ganglia/GangliaReporter.java
0004 
0005 package com.codahale.metrics.ganglia;
0006 
0007 import com.codahale.metrics.*;
0008 import com.codahale.metrics.MetricAttribute;
0009 import info.ganglia.gmetric4j.gmetric.GMetric;
0010 import info.ganglia.gmetric4j.gmetric.GMetricSlope;
0011 import info.ganglia.gmetric4j.gmetric.GMetricType;
0012 import info.ganglia.gmetric4j.gmetric.GangliaException;
0013 
0014 import org.slf4j.Logger;
0015 import org.slf4j.LoggerFactory;
0016 
0017 import java.util.Collections;
0018 import java.util.Map;
0019 import java.util.Set;
0020 import java.util.SortedMap;
0021 import java.util.concurrent.ScheduledExecutorService;
0022 import java.util.concurrent.TimeUnit;
0023 import java.util.regex.Pattern;
0024 
0025 import static com.codahale.metrics.MetricRegistry.name;
0026 import static com.codahale.metrics.MetricAttribute.*;
0027 
0028 /**
0029  * A reporter which announces metric values to a Ganglia cluster.
0030  *
0031  * @see <a href="http://ganglia.sourceforge.net/">Ganglia Monitoring System</a>
0032  */
0033 public class GangliaReporter extends ScheduledReporter {
0034 
0035     private static final Pattern SLASHES = Pattern.compile("\\\\");
0036 
0037     /**
0038      * Returns a new {@link Builder} for {@link GangliaReporter}.
0039      *
0040      * @param registry the registry to report
0041      * @return a {@link Builder} instance for a {@link GangliaReporter}
0042      */
0043     public static Builder forRegistry(MetricRegistry registry) {
0044         return new Builder(registry);
0045     }
0046 
0047     /**
0048      * A builder for {@link GangliaReporter} instances. Defaults to using a {@code tmax} of {@code 60},
0049      * a {@code dmax} of {@code 0}, converting rates to events/second, converting durations to
0050      * milliseconds, and not filtering metrics.
0051      */
0052     public static class Builder {
0053         private final MetricRegistry registry;
0054         private String prefix;
0055         private int tMax;
0056         private int dMax;
0057         private TimeUnit rateUnit;
0058         private TimeUnit durationUnit;
0059         private MetricFilter filter;
0060         private ScheduledExecutorService executor;
0061         private boolean shutdownExecutorOnStop;
0062         private Set<MetricAttribute> disabledMetricAttributes = Collections.emptySet();
0063 
0064         private Builder(MetricRegistry registry) {
0065             this.registry = registry;
0066             this.tMax = 60;
0067             this.dMax = 0;
0068             this.rateUnit = TimeUnit.SECONDS;
0069             this.durationUnit = TimeUnit.MILLISECONDS;
0070             this.filter = MetricFilter.ALL;
0071             this.executor = null;
0072             this.shutdownExecutorOnStop = true;
0073         }
0074 
0075         /**
0076          * Specifies whether or not, the executor (used for reporting) will be stopped with same time with reporter.
0077          * Default value is true.
0078          * Setting this parameter to false, has the sense in combining with providing external managed executor via {@link #scheduleOn(ScheduledExecutorService)}.
0079          *
0080          * @param shutdownExecutorOnStop if true, then executor will be stopped in same time with this reporter
0081          * @return {@code this}
0082          */
0083         public Builder shutdownExecutorOnStop(boolean shutdownExecutorOnStop) {
0084             this.shutdownExecutorOnStop = shutdownExecutorOnStop;
0085             return this;
0086         }
0087 
0088         /**
0089          * Specifies the executor to use while scheduling reporting of metrics.
0090          * Default value is null.
0091          * Null value leads to executor will be auto created on start.
0092          *
0093          * @param executor the executor to use while scheduling reporting of metrics.
0094          * @return {@code this}
0095          */
0096         public Builder scheduleOn(ScheduledExecutorService executor) {
0097             this.executor = executor;
0098             return this;
0099         }
0100 
0101         /**
0102          * Use the given {@code tmax} value when announcing metrics.
0103          *
0104          * @param tMax the desired gmond {@code tmax} value
0105          * @return {@code this}
0106          */
0107         public Builder withTMax(int tMax) {
0108             this.tMax = tMax;
0109             return this;
0110         }
0111 
0112         /**
0113          * Prefix all metric names with the given string.
0114          *
0115          * @param prefix the prefix for all metric names
0116          * @return {@code this}
0117          */
0118         public Builder prefixedWith(String prefix) {
0119             this.prefix = prefix;
0120             return this;
0121         }
0122 
0123         /**
0124          * Use the given {@code dmax} value when announcing metrics.
0125          *
0126          * @param dMax the desired gmond {@code dmax} value
0127          * @return {@code this}
0128          */
0129         public Builder withDMax(int dMax) {
0130             this.dMax = dMax;
0131             return this;
0132         }
0133 
0134         /**
0135          * Convert rates to the given time unit.
0136          *
0137          * @param rateUnit a unit of time
0138          * @return {@code this}
0139          */
0140         public Builder convertRatesTo(TimeUnit rateUnit) {
0141             this.rateUnit = rateUnit;
0142             return this;
0143         }
0144 
0145         /**
0146          * Convert durations to the given time unit.
0147          *
0148          * @param durationUnit a unit of time
0149          * @return {@code this}
0150          */
0151         public Builder convertDurationsTo(TimeUnit durationUnit) {
0152             this.durationUnit = durationUnit;
0153             return this;
0154         }
0155 
0156         /**
0157          * Only report metrics which match the given filter.
0158          *
0159          * @param filter a {@link MetricFilter}
0160          * @return {@code this}
0161          */
0162         public Builder filter(MetricFilter filter) {
0163             this.filter = filter;
0164             return this;
0165         }
0166 
0167         /**
0168          * Don't report the passed metric attributes for all metrics (e.g. "p999", "stddev" or "m15").
0169          * See {@link MetricAttribute}.
0170          *
0171          * @param disabledMetricAttributes a {@link MetricFilter}
0172          * @return {@code this}
0173          */
0174         public Builder disabledMetricAttributes(Set<MetricAttribute> disabledMetricAttributes) {
0175             this.disabledMetricAttributes = disabledMetricAttributes;
0176             return this;
0177         }
0178 
0179         /**
0180          * Builds a {@link GangliaReporter} with the given properties, announcing metrics to the
0181          * given {@link GMetric} client.
0182          *
0183          * @param gmetric the client to use for announcing metrics
0184          * @return a {@link GangliaReporter}
0185          */
0186         public GangliaReporter build(GMetric gmetric) {
0187             return new GangliaReporter(registry, gmetric, null, prefix, tMax, dMax, rateUnit, durationUnit, filter,
0188                     executor, shutdownExecutorOnStop, disabledMetricAttributes);
0189         }
0190 
0191         /**
0192          * Builds a {@link GangliaReporter} with the given properties, announcing metrics to the
0193          * given {@link GMetric} client.
0194          *
0195          * @param gmetrics the clients to use for announcing metrics
0196          * @return a {@link GangliaReporter}
0197          */
0198         public GangliaReporter build(GMetric... gmetrics) {
0199             return new GangliaReporter(registry, null, gmetrics, prefix, tMax, dMax, rateUnit, durationUnit,
0200                     filter, executor, shutdownExecutorOnStop , disabledMetricAttributes);
0201         }
0202     }
0203 
0204     private static final Logger LOGGER = LoggerFactory.getLogger(GangliaReporter.class);
0205 
0206     private final GMetric gmetric;
0207     private final GMetric[] gmetrics;
0208     private final String prefix;
0209     private final int tMax;
0210     private final int dMax;
0211 
0212     private GangliaReporter(MetricRegistry registry,
0213                             GMetric gmetric,
0214                             GMetric[] gmetrics,
0215                             String prefix,
0216                             int tMax,
0217                             int dMax,
0218                             TimeUnit rateUnit,
0219                             TimeUnit durationUnit,
0220                             MetricFilter filter,
0221                             ScheduledExecutorService executor,
0222                             boolean shutdownExecutorOnStop,
0223                             Set<MetricAttribute> disabledMetricAttributes) {
0224         super(registry, "ganglia-reporter", filter, rateUnit, durationUnit, executor, shutdownExecutorOnStop,
0225                 disabledMetricAttributes);
0226         this.gmetric = gmetric;
0227         this.gmetrics = gmetrics;
0228         this.prefix = prefix;
0229         this.tMax = tMax;
0230         this.dMax = dMax;
0231     }
0232 
0233     @Override
0234     public void report(SortedMap<String, Gauge> gauges,
0235                        SortedMap<String, Counter> counters,
0236                        SortedMap<String, Histogram> histograms,
0237                        SortedMap<String, Meter> meters,
0238                        SortedMap<String, Timer> timers) {
0239         for (Map.Entry<String, Gauge> entry : gauges.entrySet()) {
0240             reportGauge(entry.getKey(), entry.getValue());
0241         }
0242 
0243         for (Map.Entry<String, Counter> entry : counters.entrySet()) {
0244             reportCounter(entry.getKey(), entry.getValue());
0245         }
0246 
0247         for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
0248             reportHistogram(entry.getKey(), entry.getValue());
0249         }
0250 
0251         for (Map.Entry<String, Meter> entry : meters.entrySet()) {
0252             reportMeter(entry.getKey(), entry.getValue());
0253         }
0254 
0255         for (Map.Entry<String, Timer> entry : timers.entrySet()) {
0256             reportTimer(entry.getKey(), entry.getValue());
0257         }
0258     }
0259 
0260     private void reportTimer(String name, Timer timer) {
0261         final String sanitizedName = escapeSlashes(name);
0262         final String group = group(name);
0263         try {
0264             final Snapshot snapshot = timer.getSnapshot();
0265 
0266             announceIfEnabled(MAX, sanitizedName, group, convertDuration(snapshot.getMax()), getDurationUnit());
0267             announceIfEnabled(MEAN, sanitizedName, group, convertDuration(snapshot.getMean()), getDurationUnit());
0268             announceIfEnabled(MIN, sanitizedName, group, convertDuration(snapshot.getMin()), getDurationUnit());
0269             announceIfEnabled(STDDEV, sanitizedName, group, convertDuration(snapshot.getStdDev()), getDurationUnit());
0270 
0271             announceIfEnabled(P50, sanitizedName, group, convertDuration(snapshot.getMedian()), getDurationUnit());
0272             announceIfEnabled(P75, sanitizedName,
0273                      group,
0274                      convertDuration(snapshot.get75thPercentile()),
0275                      getDurationUnit());
0276             announceIfEnabled(P95, sanitizedName,
0277                      group,
0278                      convertDuration(snapshot.get95thPercentile()),
0279                      getDurationUnit());
0280             announceIfEnabled(P98, sanitizedName,
0281                      group,
0282                      convertDuration(snapshot.get98thPercentile()),
0283                      getDurationUnit());
0284             announceIfEnabled(P99, sanitizedName,
0285                      group,
0286                      convertDuration(snapshot.get99thPercentile()),
0287                      getDurationUnit());
0288             announceIfEnabled(P999, sanitizedName,
0289                      group,
0290                      convertDuration(snapshot.get999thPercentile()),
0291                      getDurationUnit());
0292 
0293             reportMetered(sanitizedName, timer, group, "calls");
0294         } catch (GangliaException e) {
0295             LOGGER.warn("Unable to report timer {}", sanitizedName, e);
0296         }
0297     }
0298 
0299     private void reportMeter(String name, Meter meter) {
0300         final String sanitizedName = escapeSlashes(name);
0301         final String group = group(name);
0302         try {
0303             reportMetered(sanitizedName, meter, group, "events");
0304         } catch (GangliaException e) {
0305             LOGGER.warn("Unable to report meter {}", name, e);
0306         }
0307     }
0308 
0309     private void reportMetered(String name, Metered meter, String group, String eventName) throws GangliaException {
0310         final String unit = eventName + '/' + getRateUnit();
0311         announceIfEnabled(COUNT, name, group, meter.getCount(), eventName);
0312         announceIfEnabled(M1_RATE, name, group, convertRate(meter.getOneMinuteRate()), unit);
0313         announceIfEnabled(M5_RATE, name, group, convertRate(meter.getFiveMinuteRate()), unit);
0314         announceIfEnabled(M15_RATE, name, group, convertRate(meter.getFifteenMinuteRate()), unit);
0315         announceIfEnabled(MEAN_RATE, name, group, convertRate(meter.getMeanRate()), unit);
0316     }
0317 
0318     private void reportHistogram(String name, Histogram histogram) {
0319         final String sanitizedName = escapeSlashes(name);
0320         final String group = group(name);
0321         try {
0322             final Snapshot snapshot = histogram.getSnapshot();
0323 
0324             announceIfEnabled(COUNT, sanitizedName, group, histogram.getCount(), "");
0325             announceIfEnabled(MAX, sanitizedName, group, snapshot.getMax(), "");
0326             announceIfEnabled(MEAN, sanitizedName, group, snapshot.getMean(), "");
0327             announceIfEnabled(MIN, sanitizedName, group, snapshot.getMin(), "");
0328             announceIfEnabled(STDDEV, sanitizedName, group, snapshot.getStdDev(), "");
0329             announceIfEnabled(P50, sanitizedName, group, snapshot.getMedian(), "");
0330             announceIfEnabled(P75, sanitizedName, group, snapshot.get75thPercentile(), "");
0331             announceIfEnabled(P95, sanitizedName, group, snapshot.get95thPercentile(), "");
0332             announceIfEnabled(P98, sanitizedName, group, snapshot.get98thPercentile(), "");
0333             announceIfEnabled(P99, sanitizedName, group, snapshot.get99thPercentile(), "");
0334             announceIfEnabled(P999, sanitizedName, group, snapshot.get999thPercentile(), "");
0335         } catch (GangliaException e) {
0336             LOGGER.warn("Unable to report histogram {}", sanitizedName, e);
0337         }
0338     }
0339 
0340     private void reportCounter(String name, Counter counter) {
0341         final String sanitizedName = escapeSlashes(name);
0342         final String group = group(name);
0343         try {
0344             announce(prefix(sanitizedName, COUNT.getCode()), group, Long.toString(counter.getCount()), GMetricType.DOUBLE, "");
0345         } catch (GangliaException e) {
0346             LOGGER.warn("Unable to report counter {}", name, e);
0347         }
0348     }
0349 
0350     private void reportGauge(String name, Gauge gauge) {
0351         final String sanitizedName = escapeSlashes(name);
0352         final String group = group(name);
0353         final Object obj = gauge.getValue();
0354         final String value = String.valueOf(obj);
0355         final GMetricType type = detectType(obj);
0356         try {
0357             announce(name(prefix, sanitizedName), group, value, type, "");
0358         } catch (GangliaException e) {
0359             LOGGER.warn("Unable to report gauge {}", name, e);
0360         }
0361     }
0362 
0363     private static final double MIN_VAL = 1E-300;
0364 
0365     private void announceIfEnabled(MetricAttribute metricAttribute, String metricName, String group, double value, String units)
0366             throws GangliaException {
0367         if (getDisabledMetricAttributes().contains(metricAttribute)) {
0368             return;
0369         }
0370         final String string = Math.abs(value) < MIN_VAL ? "0" : Double.toString(value);
0371         announce(prefix(metricName, metricAttribute.getCode()), group, string, GMetricType.DOUBLE, units);
0372     }
0373 
0374     private void announceIfEnabled(MetricAttribute metricAttribute, String metricName, String group, long value, String units)
0375             throws GangliaException {
0376         if (getDisabledMetricAttributes().contains(metricAttribute)) {
0377             return;
0378         }
0379         announce(prefix(metricName, metricAttribute.getCode()), group, Long.toString(value), GMetricType.DOUBLE, units);
0380     }
0381 
0382     private void announce(String name, String group, String value, GMetricType type, String units)
0383             throws GangliaException {
0384         if (gmetric != null) {
0385             gmetric.announce(name, value, type, units, GMetricSlope.BOTH, tMax, dMax, group);
0386         } else {
0387             for (GMetric gmetric : gmetrics) {
0388                 gmetric.announce(name, value, type, units, GMetricSlope.BOTH, tMax, dMax, group);
0389             }
0390         }
0391     }
0392 
0393     private GMetricType detectType(Object o) {
0394         if (o instanceof Float) {
0395             return GMetricType.FLOAT;
0396         } else if (o instanceof Double) {
0397             return GMetricType.DOUBLE;
0398         } else if (o instanceof Byte) {
0399             return GMetricType.INT8;
0400         } else if (o instanceof Short) {
0401             return GMetricType.INT16;
0402         } else if (o instanceof Integer) {
0403             return GMetricType.INT32;
0404         } else if (o instanceof Long) {
0405             return GMetricType.DOUBLE;
0406         }
0407         return GMetricType.STRING;
0408     }
0409 
0410     private String group(String name) {
0411         final int i = name.lastIndexOf('.');
0412         if (i < 0) {
0413             return "";
0414         }
0415         return name.substring(0, i);
0416     }
0417 
0418     private String prefix(String name, String n) {
0419         return name(prefix, name, n);
0420     }
0421 
0422     // ganglia metric names can't contain slashes.
0423     private String escapeSlashes(String name) {
0424         return SLASHES.matcher(name).replaceAll("_");
0425     }
0426 }