package io.pcp.parfait.timing;
/**
* <p>
* A {@link StepMeasurementSink} which collects only a particular fraction of
* events (e.g. for performance or log-space-saving reasons). A record is kept
* of what fraction of 'candidate' StepMeasurements have already been passed to
* the delegate; an incoming event will be passed through if and only if to
* ignore it would take that fraction below the desired sampling fraction
* specified at construction time.
* </p>
* <p>
* Note that this class makes a slight sacrifice of accuracy for performance;
* interleaving during increment of the internal counters may mean that very
* slightly more or fewer events than the desired fraction end up being captured
* in the long term.
* </p>
* <p>
* Note also that this class will only pass on 'top-level' events (depth = 0).
* </p>
*/
public class SamplingMeasurementSink implements StepMeasurementSink {
private volatile long candidateEvents;
private volatile long eventsSampled;
private final float samplingFraction;
private final StepMeasurementSink delegate;
public SamplingMeasurementSink(StepMeasurementSink delegate, float samplingFraction) {
this.samplingFraction = samplingFraction;
this.delegate = delegate;
}
@Override
public void handle(StepMeasurements measurements, int level) {
if (level > 0) {
return;
}
candidateEvents++;
double fractionSampledSoFar = (double) eventsSampled / candidateEvents;
if (fractionSampledSoFar < samplingFraction) {
eventsSampled++;
delegate.handle(measurements, level);
}
}
}