pandora-metrics
Version: 
## Overview
123 lines • 3.96 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Counter_1 = require("./Counter");
const MetricType_1 = require("../MetricType");
class BucketDeque {
    constructor(length = 11) {
        this.queue = [];
        this.current = 0;
        this.size = 11;
        this.size = length;
        // init buckets
        for (let i = 0; i < length; i++) {
            this.queue[i] = {
                timestamp: -1,
                count: 0,
            };
        }
    }
    addLast(e) {
        this.current = (this.current + 1) % this.size;
        this.queue[this.current] = e;
    }
    peek() {
        return this.queue[this.current];
    }
    /**
     * Example1:
     *      10:00   10:01  10:02   09:57   09:58   09:59
     *      70      80     90      40      50      60
     *              |       \
     *            startPos  latestIndex
     * Example2:
     *      10:00   09:55  09:56   09:57   09:58   09:59
     *      70      20     30      40      50      60
     *      |                                      |
     *      latestIndex                            startPos
     */
    getBucketList() {
        let length = this.queue.length - 1;
        let bucketList = [];
        let startPos = this.current;
        let startTs = this.queue[this.current].timestamp;
        if (startPos < 0) {
            startPos = 0;
        }
        for (let i = startPos; i >= 0 && startPos - i < length; i--) {
            bucketList.push(this.queue[i]);
        }
        for (let i = length; i > startPos + 1; i--) {
            if (this.queue[i].timestamp > startTs) {
                // the current index has been update during this iteration
                // therefore the data shall not be collected
            }
            else {
                bucketList.push(this.queue[i]);
            }
        }
        return bucketList;
    }
}
class BucketCounter extends Counter_1.BaseCounter {
    constructor(interval = 1, numberOfBucket = 10, updateTotalCount = true) {
        super();
        this.type = MetricType_1.MetricType.COUNTER;
        /**
         * 是否更新总次数
         */
        this.updateTotalCount = false;
        this.totalCount = new Counter_1.BaseCounter();
        this.interval = interval;
        this.buckets = new BucketDeque(numberOfBucket + 1);
        this.updateTotalCount = updateTotalCount;
    }
    update(n = 1) {
        if (this.updateTotalCount) {
            this.totalCount.inc(n);
        }
        let curTs = this.calculateCurrentTimestamp(Date.now());
        let lastBucket = this.buckets.peek();
        if (curTs > lastBucket.timestamp) {
            // create a new bucket and evict the oldest one
            let newBucket = {
                count: 0,
                timestamp: curTs
            };
            this.buckets.addLast(newBucket);
            lastBucket = newBucket;
        }
        lastBucket.count += n;
    }
    /**
     * Return the bucket count, keyed by timestamp
     * @return the bucket count, keyed by timestamp
     */
    getBucketCounts(startTime = 0) {
        let counts = new Map();
        let curTs = this.calculateCurrentTimestamp(Date.now());
        for (let bucket of this.buckets.getBucketList()) {
            if (1000 * bucket.timestamp >= startTime && bucket.timestamp <= curTs) {
                counts.set(bucket.timestamp * 1000, bucket.count);
            }
        }
        return counts;
    }
    calculateCurrentTimestamp(timestamp) {
        // transform to seconds and discard fractional part
        return Math.floor(Math.floor(timestamp / 1000) / this.interval) * this.interval;
    }
    getCount() {
        return this.totalCount.getCount();
    }
    inc(n) {
        this.update(n);
    }
    dec(n = 1) {
        this.update(-n);
    }
    getBucketInterval() {
        return this.interval;
    }
}
exports.BucketCounter = BucketCounter;
//# sourceMappingURL=BucketCounter.js.map