Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clear historical stats from Java codahale Metrics Timers

Am using the codahale Metrics API for Java.

We are using Timers all over our system to collect latencies.

During perf testing we are connecting to our system via JMX to collect stats, such as Mean latencies, 75th Percentile latencies etc.

Problem is, short of deleting all Metrics objects and re-creating them (which appears as if it will take much refactoring), is there a way to clear historical data so that when we start a new test, we don't need to restart out systems?

Any help would be appreciated.

like image 495
Ben Avatar asked Oct 31 '22 20:10

Ben


1 Answers

I don't know an existing way but you could extend and add resetTimers() functionality to MetricRegistry. You would have to implement your own Reservoir or branch from codahale metrics repo. The ResettableUniformReservoir is copied from UniformReservoir. The default Reservoir implementation is ExponentiallyDecayingReservoir but that's more code to copy :)

public class MyRegistry extends MetricRegistry {

    private final ConcurrentMap<String, ResettableUniformReservoir> reservoirs = new ConcurrentHashMap<>();

    @Override
    public Timer timer(String name) {
         ResettableUniformReservoir reservoir = new ResettableUniformReservoir();
         reservoirs.put(name, reservoir);
         return super.register(name, new Timer(reservoir));
    }

    public void resetTimers() {
        for (ResettableUniformReservoir reservoir : reservoirs.values()) {
            reservoir.reset();
        }
    }


    static class ResettableUniformReservoir implements Reservoir {

        private static final int DEFAULT_SIZE = 1028;
        private static final int BITS_PER_LONG = 63;

        private final AtomicLong count = new AtomicLong();
        private volatile AtomicLongArray values = new AtomicLongArray(DEFAULT_SIZE);

        @Override
        public int size() {
            final long c = count.get();
            if (c > values.length()) {
                return values.length();
            }
            return (int) c;
        }

        @Override
        public void update(long value) {
            final long c = count.incrementAndGet();
            if (c <= values.length()) {
                values.set((int) c - 1, value);
            } else {
                final long r = nextLong(c);
                if (r < values.length()) {
                    values.set((int) r, value);
                }
            }
        }

        private static long nextLong(long n) {
            long bits, val;
            do {
                bits = ThreadLocalRandom.current().nextLong() & (~(1L << BITS_PER_LONG));
                val = bits % n;
            } while (bits - val + (n - 1) < 0L);
            return val;
        }

        @Override
        public Snapshot getSnapshot() {
            final int s = size();
            final List<Long> copy = new ArrayList<Long>(s);
            for (int i = 0; i < s; i++) {
                copy.add(values.get(i));
            }
            return new UniformSnapshot(copy);
        }

        public void reset() {
            count.set(0);
            values = new AtomicLongArray(DEFAULT_SIZE);
        }
    }
}
like image 78
itaimarks Avatar answered Nov 12 '22 15:11

itaimarks