package com.bizo.asperatus.rates;
import static com.bizo.asperatus.model.Unit.CountSecond;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.logging.Level.WARNING;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import com.bizo.asperatus.model.Dimension;
import com.bizo.asperatus.tracker.MetricTracker;
/**
* Helper class that will schedule flushing the rate reported by a RateTracker to an Asperatus MetricTracker using a
* ScheduledExecutorService. By default, this class will push metrics once per minute; this can be adjusted via the
* frequency and frequencyUnit parameters provided that the scheduler is stopped.
*
* Note that this class is not thread safe. Additionally, the start/stop methods are not idempotent; they will throw
* IllegalStateExceptions if called out of order.
*/
public final class AsperatusRateTrackerScheduler {
private static final Logger LOGGER = Logger.getLogger(AsperatusRateTrackerScheduler.class.getName());
private final ScheduledExecutorService executor;
private final Runnable runnable;
private ScheduledFuture<?> currentFuture = null;
private int frequency = 1;
private TimeUnit frequencyUnit = MINUTES;
/**
* Creates a new AsperatusRateTrackerScheduler in the stopped state.
*/
public AsperatusRateTrackerScheduler(
final MetricTracker metricTracker,
final String metricName,
final List<Dimension> dimensions,
final RateTracker rateTracker,
final ScheduledExecutorService executor) {
this.executor = executor;
runnable = new Runnable() {
public void run() {
try {
final double rate = rateTracker.getRateAndResetPeriod();
metricTracker.track(metricName, rate, CountSecond, dimensions);
} catch (final Exception e) {
LOGGER.log(WARNING, "Exception flushing rate to Asperatus for metric " + metricName, e);
}
}
};
}
public void start() {
if (currentFuture != null) {
throw new IllegalStateException("This AsperatusRateTrackerScheduler has already been started.");
}
currentFuture = executor.scheduleAtFixedRate(runnable, frequency, frequency, frequencyUnit);
}
public void stop() {
if (currentFuture == null) {
throw new IllegalStateException("This AsperatusRateTrackerScheduler has already been stopped.");
}
currentFuture.cancel(true);
}
public boolean isStarted() {
return currentFuture != null;
}
public int getFrequency() {
return frequency;
}
public void setFrequency(final int frequency) {
if (isStarted()) {
throw new IllegalStateException("The AsperatusRateTrackerScheduler must be stopped to adjust the frequency.");
}
this.frequency = frequency;
}
public TimeUnit getFrequencyUnit() {
return frequencyUnit;
}
public void setFrequencyUnit(final TimeUnit frequencyUnit) {
if (isStarted()) {
throw new IllegalStateException("The AsperatusRateTrackerScheduler must be stopped to adjust the frequencyUnit.");
}
this.frequencyUnit = frequencyUnit;
}
}