/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tajo.util.metrics.reporter;
import com.codahale.metrics.*;
import info.ganglia.gmetric4j.gmetric.GMetric;
import info.ganglia.gmetric4j.gmetric.GMetricSlope;
import info.ganglia.gmetric4j.gmetric.GMetricType;
import info.ganglia.gmetric4j.gmetric.GangliaException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.SortedMap;
import static com.codahale.metrics.MetricRegistry.name;
public class GangliaReporter extends TajoMetricsScheduledReporter {
private static final Logger LOG = LoggerFactory.getLogger(GangliaReporter.class);
public static final String REPORTER_NAME = "ganglia";
private GMetric ganglia;
private String prefix;
private int tMax = 60;
private int dMax = 0;
@Override
protected String getReporterName() {
return REPORTER_NAME;
}
@Override
protected void afterInit() {
String server = metricsProperties.get(metricsPropertyKey + "server");
String port = metricsProperties.get(metricsPropertyKey + "port");
if(server == null || server.isEmpty()) {
LOG.warn("No " + metricsPropertyKey + "server property in tajo-metrics.properties");
return;
}
if(port == null || port.isEmpty()) {
LOG.warn("No " + metricsPropertyKey + "port property in tajo-metrics.properties");
return;
}
try {
ganglia = new GMetric(server, Integer.parseInt(port), GMetric.UDPAddressingMode.MULTICAST, 1);
} catch (Exception e) {
LOG.warn(e.getMessage(), e);
}
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void settMax(int tMax) {
this.tMax = tMax;
}
public void setdMax(int dMax) {
this.dMax = dMax;
}
@Override
public void report(SortedMap<String, Gauge> gauges,
SortedMap<String, Counter> counters,
SortedMap<String, Histogram> histograms,
SortedMap<String, Meter> meters,
SortedMap<String, Timer> timers) {
for (Map.Entry<String, Gauge> entry : gauges.entrySet()) {
reportGauge(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Counter> entry : counters.entrySet()) {
reportCounter(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Histogram> entry : histograms.entrySet()) {
reportHistogram(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Meter> entry : meters.entrySet()) {
reportMeter(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, Timer> entry : timers.entrySet()) {
reportTimer(entry.getKey(), entry.getValue());
}
}
private void reportTimer(String name, Timer timer) {
final String group = group(name);
try {
final Snapshot snapshot = timer.getSnapshot();
announce(prefix(name, "max"), group, convertDuration(snapshot.getMax()), getDurationUnit());
announce(prefix(name, "mean"), group, convertDuration(snapshot.getMean()), getDurationUnit());
announce(prefix(name, "min"), group, convertDuration(snapshot.getMin()), getDurationUnit());
announce(prefix(name, "stddev"), group, convertDuration(snapshot.getStdDev()), getDurationUnit());
announce(prefix(name, "p50"), group, convertDuration(snapshot.getMedian()), getDurationUnit());
announce(prefix(name, "p75"),
group,
convertDuration(snapshot.get75thPercentile()),
getDurationUnit());
announce(prefix(name, "p95"),
group,
convertDuration(snapshot.get95thPercentile()),
getDurationUnit());
announce(prefix(name, "p98"),
group,
convertDuration(snapshot.get98thPercentile()),
getDurationUnit());
announce(prefix(name, "p99"),
group,
convertDuration(snapshot.get99thPercentile()),
getDurationUnit());
announce(prefix(name, "p999"),
group,
convertDuration(snapshot.get999thPercentile()),
getDurationUnit());
reportMetered(name, timer, group, "calls");
} catch (GangliaException e) {
LOG.warn("Unable to report timer {}", name, e);
}
}
private void reportMeter(String name, Meter meter) {
final String group = group(name);
try {
reportMetered(name, meter, group, "events");
} catch (GangliaException e) {
LOG.warn("Unable to report meter {}", name, e);
}
}
private void reportMetered(String name, Metered meter, String group, String eventName) throws GangliaException {
final String unit = eventName + '/' + getRateUnit();
announce(prefix(name, "count"), group, meter.getCount(), eventName);
announce(prefix(name, "m1_rate"), group, convertRate(meter.getOneMinuteRate()), unit);
announce(prefix(name, "m5_rate"), group, convertRate(meter.getFiveMinuteRate()), unit);
announce(prefix(name, "m15_rate"), group, convertRate(meter.getFifteenMinuteRate()), unit);
announce(prefix(name, "mean_rate"), group, convertRate(meter.getMeanRate()), unit);
}
private void reportHistogram(String name, Histogram histogram) {
final String group = group(name);
try {
final Snapshot snapshot = histogram.getSnapshot();
announce(prefix(name, "count"), group, histogram.getCount(), "");
announce(prefix(name, "max"), group, snapshot.getMax(), "");
announce(prefix(name, "mean"), group, snapshot.getMean(), "");
announce(prefix(name, "min"), group, snapshot.getMin(), "");
announce(prefix(name, "stddev"), group, snapshot.getStdDev(), "");
announce(prefix(name, "p50"), group, snapshot.getMedian(), "");
announce(prefix(name, "p75"), group, snapshot.get75thPercentile(), "");
announce(prefix(name, "p95"), group, snapshot.get95thPercentile(), "");
announce(prefix(name, "p98"), group, snapshot.get98thPercentile(), "");
announce(prefix(name, "p99"), group, snapshot.get99thPercentile(), "");
announce(prefix(name, "p999"), group, snapshot.get999thPercentile(), "");
} catch (GangliaException e) {
LOG.warn("Unable to report histogram {}", name, e);
}
}
private void reportCounter(String name, Counter counter) {
final String group = group(name);
try {
announce(prefix(name, "count"), group, counter.getCount(), "");
} catch (GangliaException e) {
LOG.warn("Unable to report counter {}", name, e);
}
}
private void reportGauge(String name, Gauge gauge) {
final String group = group(name);
final Object obj = gauge.getValue();
try {
ganglia.announce(name(prefix, name), String.valueOf(obj), detectType(obj), "",
GMetricSlope.BOTH, tMax, dMax, group);
} catch (GangliaException e) {
LOG.warn("Unable to report gauge {}", name, e);
}
}
private void announce(String name, String group, double value, String units) throws GangliaException {
ganglia.announce(name,
Double.toString(value),
GMetricType.DOUBLE,
units,
GMetricSlope.BOTH,
tMax,
dMax,
group);
}
private void announce(String name, String group, long value, String units) throws GangliaException {
final String v = Long.toString(value);
ganglia.announce(name,
v,
GMetricType.DOUBLE,
units,
GMetricSlope.BOTH,
tMax,
dMax,
group);
}
private GMetricType detectType(Object o) {
if (o instanceof Float) {
return GMetricType.FLOAT;
} else if (o instanceof Double) {
return GMetricType.DOUBLE;
} else if (o instanceof Byte) {
return GMetricType.INT8;
} else if (o instanceof Short) {
return GMetricType.INT16;
} else if (o instanceof Integer) {
return GMetricType.INT32;
} else if (o instanceof Long) {
return GMetricType.DOUBLE;
}
return GMetricType.STRING;
}
private String group(String name) {
String[] tokens = name.split("\\.");
if(tokens.length < 3) {
return "";
}
return tokens[0] + "." + tokens[1];
}
private String prefix(String name, String n) {
return name(prefix, name, n);
}
}