nl.vpro.jmx.Counter Maven / Gradle / Ivy
package nl.vpro.jmx;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import java.time.Clock;
import java.time.Duration;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import javax.management.MXBean;
import javax.management.ObjectName;
import org.meeuw.math.windowed.WindowedEventRate;
import org.meeuw.math.windowed.WindowedLongSummaryStatistics;
import static nl.vpro.util.TimeUtils.roundToMillis;
/**
* @author Michiel Meeuwissen
* @since 1.57
*/
@MXBean
@Slf4j
@ToString(exclude = "name")
public class Counter implements CounterMXBean {
private final AtomicLong count = new AtomicLong(0L);
private final WindowedEventRate rate;
private final List durationStatistics = new ArrayList<>();
private final ObjectName name;
@lombok.Builder
protected Counter(
ObjectName name,
Duration countWindow,
Integer bucketCount,
Clock clock
) {
this.name = name;
rate = WindowedEventRate.builder()
.window(countWindow)
.bucketCount(bucketCount)
.clock(clock)
.build();
durationStatistics.add(WindowedLongSummaryStatistics.builder()
.window(countWindow)
.bucketCount(bucketCount)
.clock(clock)
.build());
if (name != null) {
MBeans.registerBean(name, this);
}
}
private WindowedLongSummaryStatistics newStatistics() {
WindowedLongSummaryStatistics template = durationStatistics.get(0);
return WindowedLongSummaryStatistics.builder()
.window(template.getTotalDuration())
.bucketCount(template.getBucketCount())
.build();
}
@Override
public long getCount() {
return count.get();
}
@Override
public double getRate() {
return rate.getRate(TimeUnit.MINUTES);
}
@Override
public String getRateWindow() {
return rate.getTotalDuration().toString();
}
@Override
public String getAverageDuration() {
return
Duration.ofMillis((long) (getDurationStatistics().getWindowValue().getAverage())).toString();
// No standard deviation (introduces commons-math for that?)
}
@Override
public Map getAverageDurations() {
return getDurationStatistics().getRanges()
.entrySet()
.stream()
.collect(Collectors.toMap(
e -> e.getKey().toString(),
e -> Duration.ofMillis((long) (e.getValue().getAverage())).toString()
));
}
public WindowedLongSummaryStatistics getDurationStatistics() {
return getDurationStatistics(0);
}
public WindowedLongSummaryStatistics getDurationStatistics(int index) {
return durationStatistics.get(index);
}
private void increment() {
rate.newEvent();
count.getAndIncrement();
}
void eventAndDuration(Duration duration, Duration... durations) {
increment();
log.debug("{} Duration {}", this, duration);
getDurationStatistics().accept(roundToMillis(duration).toMillis());
int i = 1;
for(Duration dur : durations) {
if (this.durationStatistics.size() <= i) {
this.durationStatistics.add(newStatistics());
}
this.durationStatistics.get(i++).accept(roundToMillis(dur).toMillis());
}
}
public void shutdown() {
if (name != null) {
MBeans.unregister(name);
}
rate.close();
}
}