blob: 63c28c421263060ba7085ae17f858c5929fa0e5b [file] [log] [blame]
package brooklyn.enricher;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import brooklyn.enricher.basic.AbstractTypeTransformingEnricher;
import brooklyn.entity.Entity;
import brooklyn.event.AttributeSensor;
import brooklyn.event.Sensor;
import brooklyn.event.SensorEvent;
/**
* Converts an absolute measure of time into a fraction of time, based on the delta between consecutive values
* and the elapsed time between those values.
*
* For example, if the values are for ProcessCpuTime (i.e. microseconds of CPU time for the given process), then
* this would convert it into a fraction (i.e. 100th of the percentage): (newVal-prevVal)/(newTimestamp/prevTimestamp).
*
* It also configured with the time units for the values.
*/
public class TimeFractionDeltaEnricher<T extends Number> extends AbstractTypeTransformingEnricher<T,Double> {
private static final Logger LOG = LoggerFactory.getLogger(TimeFractionDeltaEnricher.class);
private final long nanosPerOrigUnit;
protected Number lastValue;
protected long lastTimestamp = -1;
public TimeFractionDeltaEnricher(Entity producer, Sensor<T> source, Sensor<Double> target, TimeUnit origUnits) {
this(producer, source, target, origUnits.toNanos(1));
}
public TimeFractionDeltaEnricher(Entity producer, Sensor<T> source, Sensor<Double> target, long nanosPerOrigUnit) {
super(producer, source, target);
this.nanosPerOrigUnit = nanosPerOrigUnit;
}
@Override
public void onEvent(SensorEvent<T> event) {
onEvent(event, event.getTimestamp());
}
public void onEvent(SensorEvent<T> event, long eventTimestamp) {
Number current = event.getValue();
if (current == null) {
// Can't compute a delta;
// don't assume current=zero because then things like requestCount->requestsPerSecond is negative!
// instead don't publish anything
if (LOG.isTraceEnabled()) LOG.trace("ignoring null value in {}, at {}", new Object[] {this, eventTimestamp});
return;
}
if (eventTimestamp > lastTimestamp) {
if (lastValue == null) {
// cannot calculate delta with a single value
if (LOG.isTraceEnabled()) LOG.trace("{} received event but no last value so will not emit, null -> {} at {}",
new Object[] {this, current, eventTimestamp});
} else if (lastTimestamp < 0) {
LOG.warn("{} has lastValue {} but last timestamp {}; new value is {} at {}; not publishing",
new Object[] {this, lastValue, lastTimestamp, current, eventTimestamp});
} else {
long duration = eventTimestamp - lastTimestamp;
double fraction = toNanos(current.doubleValue() - lastValue.doubleValue(), nanosPerOrigUnit) / TimeUnit.MILLISECONDS.toNanos(duration);
entity.setAttribute((AttributeSensor<Double>)target, fraction);
if (LOG.isTraceEnabled()) LOG.trace("set {} to {}, {} -> {} at {} (previous at {})",
new Object[] {this, fraction, lastValue, current, eventTimestamp, lastTimestamp});
}
lastValue = current;
lastTimestamp = eventTimestamp;
}
}
private double toNanos(double val, long nanosPerOrigUnit) {
return val*nanosPerOrigUnit;
}
}