com.ajjpj.asysmon.impl.RobustScalarMeasurerWrapper Maven / Gradle / Ivy
package com.ajjpj.asysmon.impl;
import com.ajjpj.asysmon.config.log.ASysMonLogger;
import com.ajjpj.asysmon.data.AScalarDataPoint;
import com.ajjpj.asysmon.measure.scalar.AScalarMeasurer;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* This class limits the impact on A-SysMon itself if some measurer runs into problems or uses large amounts of resources
*
* @author arno
*/
class RobustScalarMeasurerWrapper {
private static final ASysMonLogger log = ASysMonLogger.get(RobustScalarMeasurerWrapper.class);
private final AScalarMeasurer inner;
private final long timeoutNanos;
private final int maxNumTimeouts;
private final AtomicInteger numTimeouts = new AtomicInteger(0);
private interface Strategy {
void prepareMeasurements(Map mementos);
void contributeMeasurements(Map data, long timestamp, Map mementos);
}
private final Strategy ENABLED = new Strategy() {
@Override public void prepareMeasurements(Map mementos) {
try {
final long start = System.nanoTime();
inner.prepareMeasurements(mementos);
handleDuration(System.nanoTime() - start);
} catch (Exception e) {
log.warn("Disabling scalar measurer " + inner.getClass().getName() + " because an exception occurred", e);
strategy = DISABLED;
}
}
private void handleDuration(long durationNanos) {
if(durationNanos > timeoutNanos) {
log.warn("Scalar measurer " + inner.getClass().getName() + " timed out (took " + durationNanos + "ns)");
numTimeouts.incrementAndGet();
strategy = TIMED_OUT;
}
}
@Override public void contributeMeasurements(Map data, long timestamp, Map mementos) {
try {
final long start = System.nanoTime();
inner.contributeMeasurements(data, timestamp, mementos);
handleDuration(System.nanoTime() - start);
} catch (Exception e) {
log.warn("Disabling scalar measurer " + inner.getClass().getName() + " because an exception occurred", e);
strategy = DISABLED;
}
}
};
private final Strategy TIMED_OUT = new Strategy() {
@Override public void prepareMeasurements(Map mementos) {
try {
final long start = System.nanoTime();
inner.prepareMeasurements(mementos);
handleDuration(System.nanoTime() - start);
} catch (Exception e) {
log.warn("Disabling scalar measurer " + inner.getClass().getName() + " because an exception occurred", e);
strategy = DISABLED;
}
}
private void handleDuration(long durationNanos) {
if(durationNanos > timeoutNanos) {
if(numTimeouts.incrementAndGet() >= maxNumTimeouts) {
log.warn("Scalar measurer " + inner.getClass().getName() + " timed out " + maxNumTimeouts + " times in row - permanently disabling");
strategy = DISABLED;
}
else {
strategy = ENABLED;
}
}
}
@Override public void contributeMeasurements(Map data, long timestamp, Map mementos) {
try {
final long start = System.nanoTime();
inner.contributeMeasurements(data, timestamp, mementos);
handleDuration(System.nanoTime() - start);
} catch (Exception e) {
log.warn("Disabling scalar measurer " + inner.getClass().getName() + " because an exception occurred", e);
strategy = DISABLED;
}
}
};
private final Strategy DISABLED = new Strategy() {
@Override public void prepareMeasurements(Map mementos) {
}
@Override public void contributeMeasurements(Map data, long timestamp, Map mementos) {
}
};
private volatile Strategy strategy = ENABLED;
RobustScalarMeasurerWrapper(AScalarMeasurer inner, long timeoutNanos, int maxNumTimeouts) {
this.inner = inner;
this.timeoutNanos = timeoutNanos;
this.maxNumTimeouts = maxNumTimeouts;
}
public void prepareMeasurements(Map mementos) {
strategy.prepareMeasurements(mementos);
}
public void contributeMeasurements(Map data, long timestamp, Map mementos) {
strategy.contributeMeasurements(data, timestamp, mementos);
}
public void shutdown() {
try {
inner.shutdown();
} catch (Exception exc) {
log.error("failed to shut down scalar measurer " + inner.getClass().getName() + ".", exc);
}
}
}