All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.split.client.metrics.CachedMetrics Maven / Gradle / Ivy

There is a newer version: 4.14.0
Show newest version

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