/*
* ToroDB
* Copyright © 2014 8Kdata Technology (www.8kdata.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.torodb.core.metrics;
import com.codahale.metrics.Counter;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.ObjectNameFactory;
import com.codahale.metrics.Reservoir;
import com.codahale.metrics.Timer;
import org.mpierce.metrics.reservoir.hdrhistogram.HdrHistogramReservoir;
import org.mpierce.metrics.reservoir.hdrhistogram.HdrHistogramResetOnSnapshotReservoir;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.management.ObjectName;
public class ToroMetricRegistry extends MetricRegistry {
private final MbeanNameFactory mbeanNameFactory = new MbeanNameFactory();
public ToroMetricRegistry() {
super();
final JmxReporter reporter = JmxReporter
.forRegistry(this)
.createsObjectNamesWith(mbeanNameFactory)
.build();
reporter.start();
}
public Counter counter(MetricName name) {
mbeanNameFactory.registerName(name);
Counter counter = counter(name.getMetricName());
return counter;
}
public Meter meter(MetricName name) {
mbeanNameFactory.registerName(name);
Meter meter = meter(name.getMetricName());
return meter;
}
public Histogram histogram(MetricName name) {
Histogram histogram = register(name, new Histogram(new HdrHistogramReservoir()));
return histogram;
}
/**
*
* @param name
* @param resetOnSnapshot This is usually true if you're using snapshots as a means of defining
* the window in which you want to calculate, say, the 99.9th percentile
* @return
*/
public Histogram histogram(MetricName name, boolean resetOnSnapshot) {
Reservoir reservoir;
if (resetOnSnapshot) {
reservoir = new HdrHistogramResetOnSnapshotReservoir();
} else {
reservoir = new HdrHistogramReservoir();
}
Histogram histogram = register(name, new Histogram(reservoir));
return histogram;
}
public Timer timer(MetricName name) {
Timer timer = register(name, new Timer(new HdrHistogramReservoir()));
return timer;
}
/**
*
* @param name
* @param resetOnSnapshot This is usually true if you're using snapshots as a means of defining
* the window in which you want to calculate, say, the 99.9th percentile
* @return
*/
public Timer timer(MetricName name, boolean resetOnSnapshot) {
Reservoir reservoir;
if (resetOnSnapshot) {
reservoir = new HdrHistogramResetOnSnapshotReservoir();
} else {
reservoir = new HdrHistogramReservoir();
}
Timer timer = register(name, new Timer(reservoir));
return timer;
}
public <T> SettableGauge<T> gauge(MetricName name) {
SettableGauge<T> gauge = register(name, new SettableGauge<T>());
return gauge;
}
@SuppressWarnings("unchecked")
public <T extends Metric> T register(MetricName name, T metric) {
mbeanNameFactory.registerName(name);
try {
register(name.getMetricName(), metric);
return metric;
} catch (IllegalArgumentException e) {
Metric existing = this.getMetrics().get(name.getMetricName());
return (T) existing;
}
}
public boolean remove(MetricName name) {
boolean removed = remove(name.getMetricName());
return removed;
}
private static class MbeanNameFactory implements ObjectNameFactory {
private Map<String, ObjectName> names = new ConcurrentHashMap<>();
private void registerName(MetricName name) {
names.put(name.getMetricName(), name.getMBeanName());
}
@Override
public ObjectName createName(String type, String domain, String name) {
return names.computeIfAbsent(name, n -> {
try {
return new ObjectName(domain, type, name);
} catch (Exception e) {
return null;
}
});
}
}
}