0001
0002
0003
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
0030
0031
0032
0033 public class GangliaReporter extends ScheduledReporter {
0034
0035 private static final Pattern SLASHES = Pattern.compile("\\\\");
0036
0037
0038
0039
0040
0041
0042
0043 public static Builder forRegistry(MetricRegistry registry) {
0044 return new Builder(registry);
0045 }
0046
0047
0048
0049
0050
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
0077
0078
0079
0080
0081
0082
0083 public Builder shutdownExecutorOnStop(boolean shutdownExecutorOnStop) {
0084 this.shutdownExecutorOnStop = shutdownExecutorOnStop;
0085 return this;
0086 }
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 public Builder scheduleOn(ScheduledExecutorService executor) {
0097 this.executor = executor;
0098 return this;
0099 }
0100
0101
0102
0103
0104
0105
0106
0107 public Builder withTMax(int tMax) {
0108 this.tMax = tMax;
0109 return this;
0110 }
0111
0112
0113
0114
0115
0116
0117
0118 public Builder prefixedWith(String prefix) {
0119 this.prefix = prefix;
0120 return this;
0121 }
0122
0123
0124
0125
0126
0127
0128
0129 public Builder withDMax(int dMax) {
0130 this.dMax = dMax;
0131 return this;
0132 }
0133
0134
0135
0136
0137
0138
0139
0140 public Builder convertRatesTo(TimeUnit rateUnit) {
0141 this.rateUnit = rateUnit;
0142 return this;
0143 }
0144
0145
0146
0147
0148
0149
0150
0151 public Builder convertDurationsTo(TimeUnit durationUnit) {
0152 this.durationUnit = durationUnit;
0153 return this;
0154 }
0155
0156
0157
0158
0159
0160
0161
0162 public Builder filter(MetricFilter filter) {
0163 this.filter = filter;
0164 return this;
0165 }
0166
0167
0168
0169
0170
0171
0172
0173
0174 public Builder disabledMetricAttributes(Set<MetricAttribute> disabledMetricAttributes) {
0175 this.disabledMetricAttributes = disabledMetricAttributes;
0176 return this;
0177 }
0178
0179
0180
0181
0182
0183
0184
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
0193
0194
0195
0196
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
0423 private String escapeSlashes(String name) {
0424 return SLASHES.matcher(name).replaceAll("_");
0425 }
0426 }