@dudousxd/nestjs-telescope
Version:
Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.
79 lines • 3.41 kB
JavaScript
// packages/core/src/rollup/rollup-store.ts
/** One minute is the base rollup granularity. */
export const ROLLUP_BUCKET_MS = 60_000;
/**
* Upper boundaries (inclusive, in ms) for the pre-aggregated latency histogram.
* Bucket `i` counts durations `d` where `d <= LATENCY_BOUNDARIES_MS[i]` and
* `d > LATENCY_BOUNDARIES_MS[i-1]`. A final OVERFLOW bucket (index
* `LATENCY_BOUNDARIES_MS.length`) counts everything greater than the last
* boundary, so a histogram always has `LATENCY_BOUNDARIES_MS.length + 1` cells.
*/
export const LATENCY_BOUNDARIES_MS = [
1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000,
];
/** The fixed cell count of every latency histogram (boundaries + 1 overflow). */
export const HISTOGRAM_BUCKET_COUNT = LATENCY_BOUNDARIES_MS.length + 1;
/** A fresh, all-zeros histogram of the canonical fixed length. */
export function emptyHistogram() {
return new Array(HISTOGRAM_BUCKET_COUNT).fill(0);
}
/**
* The histogram cell a duration falls in: the first index `i` where
* `durationMs <= LATENCY_BOUNDARIES_MS[i]`, else the overflow index. Negative or
* zero durations land in cell 0.
*/
export function histogramBucketIndex(durationMs) {
for (let index = 0; index < LATENCY_BOUNDARIES_MS.length; index += 1) {
const boundary = LATENCY_BOUNDARIES_MS[index];
if (boundary !== undefined && durationMs <= boundary)
return index;
}
return LATENCY_BOUNDARIES_MS.length;
}
/**
* Increments the histogram cell for `durationMs` by one, in place. Safe against
* the index typing (always a valid in-range cell of a fixed-length array).
*/
export function incrementHistogram(histogram, durationMs) {
const index = histogramBucketIndex(durationMs);
histogram[index] = (histogram[index] ?? 0) + 1;
}
/**
* Normalizes a (possibly legacy/undefined) stored histogram into a fixed-length
* zero-padded array. Legacy rollup rows with no histogram read back as all-zeros
* of the canonical length — never NaN, never a wrong width.
*/
export function normalizeHistogram(histogram) {
const normalized = emptyHistogram();
if (!Array.isArray(histogram))
return normalized;
for (let index = 0; index < HISTOGRAM_BUCKET_COUNT; index += 1) {
const value = histogram[index];
normalized[index] = typeof value === 'number' && Number.isFinite(value) ? value : 0;
}
return normalized;
}
/**
* Element-wise additive merge of `addend` into `target` (mutates and returns
* `target`). Both are normalized first, so legacy/short arrays are safe.
*/
export function mergeHistograms(target, addend) {
const left = normalizeHistogram(target);
const right = normalizeHistogram(addend);
for (let index = 0; index < HISTOGRAM_BUCKET_COUNT; index += 1) {
left[index] = (left[index] ?? 0) + (right[index] ?? 0);
}
return left;
}
/** Floors an epoch-ms timestamp to the start of its 1-minute rollup bucket. */
export function floorToBucket(epochMs) {
return Math.floor(epochMs / ROLLUP_BUCKET_MS) * ROLLUP_BUCKET_MS;
}
function hasFunction(value, key) {
return key in value && typeof Reflect.get(value, key) === 'function';
}
/** Duck-types `s` as a {@link RollupStore} (recordRollups & queryRollups present). */
export function isRollupStore(s) {
return hasFunction(s, 'recordRollups') && hasFunction(s, 'queryRollups');
}
//# sourceMappingURL=rollup-store.js.map