package com.twitter.common.stats; import java.util.concurrent.atomic.AtomicLong; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Ticker; import com.twitter.common.base.MorePreconditions; import com.twitter.common.quantity.Amount; import com.twitter.common.quantity.Time; import com.twitter.common.util.Clock; /** * A stat that exports the amount of time since it was last reset. * * @author William Farner */ public class Elapsed { private final Ticker ticker; private final AtomicLong lastEventNs = new AtomicLong(); /** * Calls {@link #Elapsed(String, Time)} using a default granularity of nanoseconds. * * @param name Name of the stat to export. */ public Elapsed(String name) { this(name, Time.NANOSECONDS); } /** * Equivalent to calling {@link #Elapsed(String, Time, Ticker)} passing {@code name}, * {@code granularity} and {@link com.google.common.base.Ticker#systemTicker()}. * <br/> * @param name Name of the stat to export. * @param granularity Time unit granularity to export. */ public Elapsed(String name, Time granularity) { this(name, granularity, Ticker.systemTicker()); } /** * Creates and exports a new stat that maintains the difference between the tick time * and the time since it was last reset. Upon export, the counter will act as though it were just * reset. * <br/> * @param name Name of stat to export * @param granularity Time unit granularity to export. * @param ticker Ticker implementation */ public Elapsed(String name, final Time granularity, final Ticker ticker) { MorePreconditions.checkNotBlank(name); Preconditions.checkNotNull(granularity); this.ticker = Preconditions.checkNotNull(ticker); reset(); Stats.export(new StatImpl<Long>(name) { @Override public Long read() { return Amount.of(ticker.read() - lastEventNs.get(), Time.NANOSECONDS).as(granularity); } }); } public void reset() { lastEventNs.set(ticker.read()); } }