
io.split.client.metrics.CachedMetrics Maven / Gradle / Ivy
package io.split.client.metrics;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.primitives.Ints;
import com.google.common.primitives.Longs;
import io.split.api.CounterDTO;
import io.split.api.GaugeDTO;
import io.split.api.LatencyDTO;
import io.split.engine.metrics.Metrics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Created by adilaijaz on 9/4/15.
*/
public class CachedMetrics implements Metrics {
private final HttpMetrics _httpMetrics;
private final Map _latencyMap;
private final Map _countMap;
private final Map _gaugeMap;
private final Object _latencyLock = new Object();
private AtomicLong _latencyLastUpdateTimeMillis = new AtomicLong(System.currentTimeMillis());
private final Object _counterLock = new Object();
private AtomicLong _counterLastUpdateTimeMillis = new AtomicLong(System.currentTimeMillis());
private final Object _gaugeLock = new Object();
private AtomicLong _gaugeLastUpdateTimeMillis = new AtomicLong(System.currentTimeMillis());
private long _refreshPeriodInMillis;
private final int _queueForTheseManyCalls;
/**
* For unit testing only.
*
* @param httpMetrics
* @param queueForTheseManyCalls
*/
/*package private*/ CachedMetrics(HttpMetrics httpMetrics, int queueForTheseManyCalls) {
this(httpMetrics, queueForTheseManyCalls, TimeUnit.MINUTES.toMillis(1));
}
public CachedMetrics(HttpMetrics httpMetrics, long refreshPeriodInMillis) {
this(httpMetrics, 100, refreshPeriodInMillis);
}
private CachedMetrics(HttpMetrics httpMetrics, int queueForTheseManyCalls, long refreshPeriodInMillis) {
_httpMetrics = httpMetrics;
_latencyMap = Maps.newHashMap();
_countMap = Maps.newHashMap();
_gaugeMap = Maps.newHashMap();
checkArgument(queueForTheseManyCalls > 0, "queue for cache should be greater than zero");
_queueForTheseManyCalls = queueForTheseManyCalls;
_refreshPeriodInMillis = refreshPeriodInMillis;
}
@Override
public void count(String counter, long delta) {
if (delta <= 0) {
return;
}
if (counter == null || counter.trim().isEmpty()) {
return;
}
synchronized (_counterLock) {
SumAndCount sumAndCount = _countMap.get(counter);
if (sumAndCount == null) {
sumAndCount = new SumAndCount();
_countMap.put(counter, sumAndCount);
}
sumAndCount.addDelta(delta);
if (sumAndCount._count >= _queueForTheseManyCalls || hasTimeElapsed(_counterLastUpdateTimeMillis)) {
CounterDTO dto = CounterDTO.builder()
.name(counter)
.delta(sumAndCount._sum)
.build();
sumAndCount.clear();
_counterLastUpdateTimeMillis.set(System.currentTimeMillis());
_httpMetrics.count(dto);
}
}
}
private boolean hasTimeElapsed(AtomicLong lastRefreshTime) {
return (System.currentTimeMillis() - lastRefreshTime.get()) > _refreshPeriodInMillis;
}
@Override
public void gauge(String gauge, double value) {
if (gauge == null || gauge.trim().isEmpty()) {
return;
}
synchronized (_gaugeLock) {
ValueAndCount ifPresent = _gaugeMap.get(gauge);
if (ifPresent == null) {
ifPresent = new ValueAndCount();
_gaugeMap.put(gauge, ifPresent);
}
ifPresent.setValue(value);
if (ifPresent._count >= _queueForTheseManyCalls || hasTimeElapsed(_gaugeLastUpdateTimeMillis)) {
GaugeDTO dto = GaugeDTO.builder()
.name(gauge)
.value(ifPresent._value)
.build();
ifPresent.clear();
_gaugeLastUpdateTimeMillis.set(System.currentTimeMillis());
_httpMetrics.gauge(dto);
}
}
}
@Override
public void time(String operation, long timeInMs) {
if (operation == null || operation.trim().isEmpty() || timeInMs < 0L) {
// error
return;
}
synchronized (_latencyLock) {
if (!_latencyMap.containsKey(operation)) {
ILatencyTracker latencies = new BinarySearchLatencyTracker();
_latencyMap.put(operation, latencies);
}
ILatencyTracker tracker = _latencyMap.get(operation);
tracker.addLatencyMillis((int) timeInMs);
if (hasTimeElapsed(_latencyLastUpdateTimeMillis)) {
LatencyDTO dto = LatencyDTO.builder()
.name(operation)
.latencies(Longs.asList(tracker.getLatencies()))
.build();
tracker.clear();
_latencyLastUpdateTimeMillis.set(System.currentTimeMillis());
_httpMetrics.time(dto);
}
}
}
private static final class SumAndCount {
private int _count = 0;
private long _sum = 0L;
public void addDelta(long delta) {
_count++;
_sum += delta;
}
public void clear() {
_count = 0;
_sum = 0L;
}
}
private static final class ValueAndCount {
private int _count = 0;
private double _value= 0L;
public void setValue(double value) {
_count++;
_value = value;
}
public void clear() {
_count = 0;
_value = 0d;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy