package org.dcache.commons.stats;
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
import java.lang.reflect.Method;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import static org.dcache.util.Strings.toStringSignature;
/**
*
* @param <T>
* @author timur
*/
public class RequestExecutionTimeGauges<T> {
private static final Ordering<RequestExecutionTimeGauge> ORDERING =
Ordering.natural().onResultOf(new Function<RequestExecutionTimeGauge, String>()
{
@Override
public String apply(RequestExecutionTimeGauge gauge)
{
return gauge.getName();
}
});
private final String name;
private final boolean autoCreate ;
private final Map<T,RequestExecutionTimeGauge> gauges =
new HashMap<>();
/**
*
* @param name
*/
public RequestExecutionTimeGauges(String name) {
this(name,true);
}
/**
*
* @param name
* @param autoCreate
*/
public RequestExecutionTimeGauges(String name, boolean autoCreate) {
this.name = name;
this.autoCreate = autoCreate;
}
/**
*
* @return
*/
public String getName() {
return name;
}
/**
* Adds a new request execution time gauge to the collection of gauges
* name of the gauge will be computed as key.toString()
* @param key the same key will be needed in the increment and get
* functions to change or access the gauge value
*/
public void addGauge(T key) {
String gaugeName;
if(key instanceof Class) {
Class<?> ckey = (Class<?>) key;
gaugeName = ckey.getSimpleName();
} else if(key instanceof Method){
Method mkey = (Method)key;
// use '|' as delimiter to keep JMX happy
gaugeName = toStringSignature(mkey, '|');
} else {
gaugeName = key.toString();
}
addGauge(key,gaugeName);
}
/**
* Adds a new gauge to the collection of gauges
* @param key the same key will be needed in the increment and get
* functions to change or access the gauge value
* @param name name of the gauge
*/
public synchronized void addGauge(T key, String name) {
if(gauges.containsKey(key)) {
return;
}
RequestExecutionTimeGauge gauge = new RequestExecutionTimeGaugeImpl(name, this.name);
gauges.put(key,gauge);
}
/**
* @return A string representation of the RequestExecutionTimeGauges
* which is a name of the collection followed by the table of
* gauges names and values. Units are prefixed by <i>ms</i>.
*/
@Override
public String toString() {
return toString("ms");
}
public String toString(String unitSymbol) {
StringBuilder sb = new StringBuilder();
try (Formatter formatter = new Formatter(sb)) {
formatter.format("%-36s %23s %12s %12s %12s %12s %12s",
name,
"average\u00B1stderr(" + unitSymbol + ')',
"min(" + unitSymbol + ')',
"max(" + unitSymbol + ')',
"STD(" + unitSymbol + ')',
"Samples","Period");
}
synchronized(this) {
for(RequestExecutionTimeGauge gauge: ORDERING.sortedCopy(gauges.values())) {
sb.append("\n ").append(gauge);
}
}
return sb.toString();
}
/**
*
* @param gaugeKey a key corresponding to a gauge
* @return a String representation of a RequestExecutionTimeGauges
* associated with gaugeKey
* @throws NoSuchElementException if gauge for gaugeKey for is not defined
*/
public String gaugeToString(T gaugeKey) {
RequestExecutionTimeGauge gauge;
synchronized(this) {
gauge = gauges.get(gaugeKey);
}
if(gauge == null) {
throw new NoSuchElementException("gauge for key "+
gaugeKey+" is not defined in "+name+" counters" );
}
return gauge.toString();
}
/**
*
* @param gaugeKey a key corresponding to a gauge
* @return a RequestExecutionTimeGauges associated with counterKey
* @throws NoSuchElementException if counter for counterKey is not defined
*/
public RequestExecutionTimeGauge getGauge(T gaugeKey) {
synchronized(this) {
if(gauges.containsKey(gaugeKey)) {
return gauges.get(gaugeKey);
} else {
if(autoCreate) {
addGauge(gaugeKey);
return gauges.get(gaugeKey);
} else {
throw new NoSuchElementException("gauge with name "+
gaugeKey+" is not defined in "+name+" guages" );
}
}
}
}
/**
*
* @param gaugeKey a key corresponding to a gauge
* @return an average execution time of request invocations measured by
* RequestExecutionTimeGauge associated with gaugeKey
*/
public double getAverageExecutionTime(T gaugeKey) {
return getGauge(gaugeKey).getAverageExecutionTime();
}
/**
* update the gauge with the next execution time
* @param gaugeKey a key corresponding to a gauge
* @param nextExecTime
*/
public void update(T gaugeKey, long nextExecTime) {
getGauge(gaugeKey).update(nextExecTime);
}
/**
*
* @return keyset
*/
public Set<T> keySet() {
return gauges.keySet();
}
/**
* reset all gauges.
*/
public synchronized void reset() {
for (RequestExecutionTimeGauge gauge: gauges.values()) {
gauge.reset();
}
}
}