Hot memory — 15m → 24h (or custom points) Warm memory — downsampled ring + samples-per-bucket Disk history — auto-rotate by age (1 day → 1 year, forever, or custom days) Soft disk budget + max warm points Auto prune on a configurable hour interval Dry-run prune / Prune now / Save to agent (admin role)
81 lines
2.2 KiB
JavaScript
81 lines
2.2 KiB
JavaScript
/**
|
|
* Human-readable metric formatting with automatic unit scaling.
|
|
*/
|
|
|
|
/**
|
|
* @param {number} n
|
|
* @param {number} digits
|
|
*/
|
|
function trimFixed(n, digits) {
|
|
const s = n.toFixed(digits)
|
|
if (!s.includes('.')) return s
|
|
return s.replace(/0+$/, '').replace(/\.$/, '')
|
|
}
|
|
|
|
/**
|
|
* Pick decimal places from magnitude after scaling.
|
|
* @param {number} n
|
|
*/
|
|
function autoDigits(n) {
|
|
const a = Math.abs(n)
|
|
if (a >= 100) return 0
|
|
if (a >= 10) return 1
|
|
return 2
|
|
}
|
|
|
|
/**
|
|
* Scale a magnitude through a unit ladder.
|
|
* @param {number} value absolute magnitude in base units
|
|
* @param {string[]} units
|
|
* @param {number} base
|
|
* @returns {{ n: number, unit: string }}
|
|
*/
|
|
function scaleUnit(value, units, base) {
|
|
let n = Math.abs(value)
|
|
let i = 0
|
|
while (n >= base && i < units.length - 1) {
|
|
n /= base
|
|
i++
|
|
}
|
|
return { n: value < 0 ? -n : n, unit: units[i] }
|
|
}
|
|
|
|
/**
|
|
* Format memory stored as MiB → B / KiB / MiB / GiB / TiB / PiB.
|
|
* @param {number|null|undefined} mib
|
|
* @returns {string}
|
|
*/
|
|
export function formatMib(mib) {
|
|
if (mib == null || !Number.isFinite(Number(mib))) return '—'
|
|
const bytes = Number(mib) * 1024 * 1024
|
|
if (bytes === 0) return '0 B'
|
|
const { n, unit } = scaleUnit(bytes, ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'], 1024)
|
|
return `${trimFixed(n, autoDigits(n))} ${unit}`
|
|
}
|
|
|
|
/**
|
|
* Format network rate stored as kilobits/s → b/s / kb/s / Mb/s / Gb/s / Tb/s.
|
|
* @param {number|null|undefined} kbps
|
|
* @returns {string}
|
|
*/
|
|
export function formatKilobitsPerSec(kbps) {
|
|
if (kbps == null || !Number.isFinite(Number(kbps))) return '—'
|
|
const bps = Number(kbps) * 1000
|
|
if (bps === 0) return '0 b/s'
|
|
const { n, unit } = scaleUnit(bps, ['b/s', 'kb/s', 'Mb/s', 'Gb/s', 'Tb/s'], 1000)
|
|
return `${trimFixed(n, autoDigits(n))} ${unit}`
|
|
}
|
|
|
|
/**
|
|
* Format raw bytes → B / KiB / MiB / GiB / TiB / PiB.
|
|
* @param {number|null|undefined} bytes
|
|
* @returns {string}
|
|
*/
|
|
export function formatBytes(bytes) {
|
|
if (bytes == null || !Number.isFinite(Number(bytes))) return '—'
|
|
const n0 = Number(bytes)
|
|
if (n0 === 0) return '0 B'
|
|
const { n, unit } = scaleUnit(n0, ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB'], 1024)
|
|
return `${trimFixed(n, autoDigits(n))} ${unit}`
|
|
}
|