Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
 package io.tehuti.metrics.stats;
 import java.util.List;
A SampledStat records a single scalar value measured over one or more samples. Each sample is recorded over a configurable window. The window can be defined by number of events or elapsed time (or both, if both are given the window is complete when either the event count or elapsed time criterion is met). All the samples are combined to produce the measurement. When a window is complete the oldest sample is cleared and recycled to begin recording the next sample. Subclasses of this class define different statistics measured using this basic pattern.
 public abstract class SampledStat implements MeasurableStat {
     protected double initialValue;
     private int current = 0;
     protected List<Samplesamples;
     public SampledStat(double initialValue) {
         this. = initialValue;
         this. = new ArrayList<Sample>(2);
     public void record(MetricConfig configdouble valuelong timeMs) {
         Sample sample = current(configtimeMs);
         if (sample.isComplete(timeMsconfig))
             sample = advance(configtimeMs);
         sample.eventCount += 1;
     private Sample advance(MetricConfig configlong timeMs) {
         this. = (this. + 1) % config.samples();
         if (this. >= .size()) {
             Sample sample = newSample(timeMs);
             return sample;
         } else {
             Sample sample = current(configtimeMs);
             return sample;
     protected Sample newSample(long timeMs) {
         return new Sample(this.timeMs);
     public double measure(MetricConfig configlong now) {
         return combine(this.confignow);
     public Sample current(MetricConfig configlong timeMs) {
         return this..get(this.);
     public Sample oldest(MetricConfig configlong now) {
         Sample oldest = this..get(0);
         for (int i = 1; i < this..size(); i++) {
             Sample curr = this..get(i);
             if (curr.lastWindowMs < oldest.lastWindowMs)
                 oldest = curr;
         return oldest;

Checks that the sample windows are properly initialized. In case there are no initialized sample yet, this creates two windows: one that begins now, as well as the previous window before that. This ensures that any measurement won't be calculated over an elapsed time of zero or few milliseconds. This is particularly significant for Rate, which can otherwise report disproportionately high values in those conditions. The downside of this approach is that Rates will under-report their values initially by virtue of carrying one empty window in their samples.
     private void checkInit(MetricConfig configlong now) {
        if (.size() == 0) {
            this..add(newSample(now - config.timeWindowMs()));
    protected abstract void update(Sample sampleMetricConfig configdouble valuelong timeMs);
    public abstract double combine(List<SamplesamplesMetricConfig configlong now);

Timeout any windows that have expired in the absence of any events
    protected void purgeObsoleteSamples(MetricConfig configlong now) {
        long expireAge = config.samples() * config.timeWindowMs();
        for (int i = 0; i < .size(); i++) {
            Sample sample = this..get(i);
            if (now - sample.lastWindowMs >= expireAge) {
                // The samples array is used as a circular list. The rank represents how many spots behind the current
                // window is window #i at. The current sample is rank 0, the next older sample is 1 and so on until
                // the oldest sample, which has a rank equal to samples.size() - 1.
                int rank =  - i;
                if (rank < 0) {
                    rank += .size();
                // Here we reset the expired window to a time in the past that is offset proportionally to its rank.
                sample.reset(now - rank * config.timeWindowMs());
    protected static class Sample {
        public double initialValue;
        public long eventCount;
        public long lastWindowMs;
        public double value;
        public Sample(double initialValuelong now) {
            this. = initialValue;
            this. = 0;
            this. = now;
            this. = initialValue;
        public void reset(long now) {
            this. = 0;
            this. = now;
            this. = ;


a boolean indicating if the sample is past its time-based or event count-based limits.
        public boolean isComplete(long timeMsMetricConfig config) {
            return timeMs -  >= config.timeWindowMs() ||  >= config.eventWindow();
        public String toString() {
            return "Sample(initialValue = " +  +
                    "; eventCount = " +  +
                    "; lastWindowMs = " +  +
                    "; value = " +  + ")";
New to GrepCode? Check out our FAQ X