946 lines
25 KiB
JavaScript
946 lines
25 KiB
JavaScript
/**
|
|
* Metric contexts, charts, and dimension catalog.
|
|
*
|
|
* Context IDs follow family.metric style (e.g. system.cpu).
|
|
* Static charts cover host-wide system stats; instance charts
|
|
* (per-CPU, per-disk, per-iface, per-mount) are registered at runtime.
|
|
*/
|
|
|
|
import { DEEP_STATIC_CHARTS } from './metrics-deep.js'
|
|
import { MORE_STATIC_CHARTS } from './metrics-more.js'
|
|
|
|
export const SAMPLE_INTERVAL_MS = 1000
|
|
|
|
export {
|
|
makeDiskAwaitChart,
|
|
makeDiskAvgszChart,
|
|
makeDiskQopsChart,
|
|
makeDiskBusyChart,
|
|
makeDiskIotimeChart,
|
|
makeDiskDiscardChart,
|
|
makeNetSpeedChart,
|
|
makeCgroupCpuChart,
|
|
makeCgroupMemChart,
|
|
makeCgroupIoChart,
|
|
makeSensorTempChart,
|
|
makeThermalZoneChart,
|
|
} from './metrics-deep.js'
|
|
|
|
export {
|
|
makeDiskSvctmChart,
|
|
makeDiskMergedChart,
|
|
makeDiskFlushChart,
|
|
makeNetDuplexChart,
|
|
makeNetMtuChart,
|
|
makeNetQueueChart,
|
|
makeIrqChart,
|
|
makeCpuIdleChart,
|
|
makeNumaNodeMemChart,
|
|
makeCgroupMemDetailChart,
|
|
makeCgroupThrottleChart,
|
|
} from './metrics-more.js'
|
|
|
|
/**
|
|
* @typedef {{ id: string, name: string, algorithm: 'absolute'|'incremental', multiplier?: number, divisor?: number }} DimensionDef
|
|
* @typedef {{
|
|
* id: string,
|
|
* name: string,
|
|
* context: string,
|
|
* title: string,
|
|
* units: string,
|
|
* family: string,
|
|
* chartType: 'line'|'area'|'stacked',
|
|
* priority: number,
|
|
* dimensions: DimensionDef[],
|
|
* plugin?: string,
|
|
* }} ChartDef
|
|
*/
|
|
|
|
/** @type {ChartDef[]} */
|
|
export const STATIC_CHART_DEFS = [
|
|
// ── CPU / scheduler ───────────────────────────────────────
|
|
{
|
|
id: 'system.cpu',
|
|
name: 'system.cpu',
|
|
context: 'system.cpu',
|
|
title: 'Total CPU utilization',
|
|
units: 'percentage',
|
|
family: 'cpu',
|
|
chartType: 'stacked',
|
|
priority: 100,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'guest_nice', name: 'guest_nice', algorithm: 'absolute' },
|
|
{ id: 'guest', name: 'guest', algorithm: 'absolute' },
|
|
{ id: 'steal', name: 'steal', algorithm: 'absolute' },
|
|
{ id: 'softirq', name: 'softirq', algorithm: 'absolute' },
|
|
{ id: 'irq', name: 'irq', algorithm: 'absolute' },
|
|
{ id: 'user', name: 'user', algorithm: 'absolute' },
|
|
{ id: 'system', name: 'system', algorithm: 'absolute' },
|
|
{ id: 'nice', name: 'nice', algorithm: 'absolute' },
|
|
{ id: 'iowait', name: 'iowait', algorithm: 'absolute' },
|
|
{ id: 'idle', name: 'idle', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.intr',
|
|
name: 'system.intr',
|
|
context: 'system.intr',
|
|
title: 'CPU Interrupts',
|
|
units: 'interrupts/s',
|
|
family: 'interrupts',
|
|
chartType: 'line',
|
|
priority: 110,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'interrupts', name: 'interrupts', algorithm: 'incremental' }],
|
|
},
|
|
{
|
|
id: 'system.ctxt',
|
|
name: 'system.ctxt',
|
|
context: 'system.ctxt',
|
|
title: 'CPU Context Switches',
|
|
units: 'context switches/s',
|
|
family: 'processes',
|
|
chartType: 'line',
|
|
priority: 120,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'switches', name: 'switches', algorithm: 'incremental' }],
|
|
},
|
|
{
|
|
id: 'system.forks',
|
|
name: 'system.forks',
|
|
context: 'system.forks',
|
|
title: 'Started Processes',
|
|
units: 'processes/s',
|
|
family: 'processes',
|
|
chartType: 'line',
|
|
priority: 130,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'started', name: 'started', algorithm: 'incremental' }],
|
|
},
|
|
{
|
|
id: 'system.processes',
|
|
name: 'system.processes',
|
|
context: 'system.processes',
|
|
title: 'System Processes',
|
|
units: 'processes',
|
|
family: 'processes',
|
|
chartType: 'line',
|
|
priority: 140,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'running', name: 'running', algorithm: 'absolute' },
|
|
{ id: 'blocked', name: 'blocked', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.active_processes',
|
|
name: 'system.active_processes',
|
|
context: 'system.active_processes',
|
|
title: 'System Active Processes',
|
|
units: 'processes',
|
|
family: 'processes',
|
|
chartType: 'line',
|
|
priority: 145,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'active', name: 'active', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'system.load',
|
|
name: 'system.load',
|
|
context: 'system.load',
|
|
title: 'System Load Average',
|
|
units: 'load',
|
|
family: 'load',
|
|
chartType: 'line',
|
|
priority: 150,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'load1', name: 'load1', algorithm: 'absolute' },
|
|
{ id: 'load5', name: 'load5', algorithm: 'absolute' },
|
|
{ id: 'load15', name: 'load15', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.uptime',
|
|
name: 'system.uptime',
|
|
context: 'system.uptime',
|
|
title: 'System Uptime',
|
|
units: 'seconds',
|
|
family: 'uptime',
|
|
chartType: 'line',
|
|
priority: 160,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'uptime', name: 'uptime', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'system.entropy',
|
|
name: 'system.entropy',
|
|
context: 'system.entropy',
|
|
title: 'Available Entropy',
|
|
units: 'entropy',
|
|
family: 'entropy',
|
|
chartType: 'line',
|
|
priority: 170,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'entropy', name: 'entropy', algorithm: 'absolute' }],
|
|
},
|
|
|
|
// ── Memory ────────────────────────────────────────────────
|
|
{
|
|
id: 'system.ram',
|
|
name: 'system.ram',
|
|
context: 'system.ram',
|
|
title: 'System RAM',
|
|
units: 'MiB',
|
|
family: 'ram',
|
|
chartType: 'stacked',
|
|
priority: 200,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'free', name: 'free', algorithm: 'absolute' },
|
|
{ id: 'used', name: 'used', algorithm: 'absolute' },
|
|
{ id: 'cached', name: 'cached', algorithm: 'absolute' },
|
|
{ id: 'buffers', name: 'buffers', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'mem.available',
|
|
name: 'mem.available',
|
|
context: 'mem.available',
|
|
title: 'Available RAM for applications',
|
|
units: 'MiB',
|
|
family: 'ram',
|
|
chartType: 'area',
|
|
priority: 210,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'avail', name: 'avail', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'mem.swap',
|
|
name: 'mem.swap',
|
|
context: 'mem.swap',
|
|
title: 'System Swap',
|
|
units: 'MiB',
|
|
family: 'swap',
|
|
chartType: 'stacked',
|
|
priority: 220,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'free', name: 'free', algorithm: 'absolute' },
|
|
{ id: 'used', name: 'used', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'mem.swap_cached',
|
|
name: 'mem.swap_cached',
|
|
context: 'mem.swap_cached',
|
|
title: 'Swap Cached',
|
|
units: 'MiB',
|
|
family: 'swap',
|
|
chartType: 'area',
|
|
priority: 225,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'cached', name: 'cached', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'mem.kernel',
|
|
name: 'mem.kernel',
|
|
context: 'mem.kernel',
|
|
title: 'Memory Used by Kernel',
|
|
units: 'MiB',
|
|
family: 'kernel',
|
|
chartType: 'stacked',
|
|
priority: 230,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'slab', name: 'slab', algorithm: 'absolute' },
|
|
{ id: 'kernel_stack', name: 'kernel_stack', algorithm: 'absolute' },
|
|
{ id: 'page_tables', name: 'page_tables', algorithm: 'absolute' },
|
|
{ id: 'vmalloc_used', name: 'vmalloc_used', algorithm: 'absolute' },
|
|
{ id: 'percpu', name: 'percpu', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'mem.slab',
|
|
name: 'mem.slab',
|
|
context: 'mem.slab',
|
|
title: 'Reclaimable Kernel Memory',
|
|
units: 'MiB',
|
|
family: 'slab',
|
|
chartType: 'stacked',
|
|
priority: 235,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'reclaimable', name: 'reclaimable', algorithm: 'absolute' },
|
|
{ id: 'unreclaimable', name: 'unreclaimable', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'mem.writeback',
|
|
name: 'mem.writeback',
|
|
context: 'mem.writeback',
|
|
title: 'Writeback Memory',
|
|
units: 'MiB',
|
|
family: 'writeback',
|
|
chartType: 'line',
|
|
priority: 240,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'dirty', name: 'dirty', algorithm: 'absolute' },
|
|
{ id: 'writeback', name: 'writeback', algorithm: 'absolute' },
|
|
{ id: 'FuseWriteback', name: 'FuseWriteback', algorithm: 'absolute' },
|
|
{ id: 'NfsWriteback', name: 'NfsWriteback', algorithm: 'absolute' },
|
|
{ id: 'Bounce', name: 'Bounce', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'mem.committed',
|
|
name: 'mem.committed',
|
|
context: 'mem.committed',
|
|
title: 'Committed (Allocated) Memory',
|
|
units: 'MiB',
|
|
family: 'committed',
|
|
chartType: 'area',
|
|
priority: 245,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'Committed_AS', name: 'Committed_AS', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'mem.swapio',
|
|
name: 'mem.swapio',
|
|
context: 'mem.swapio',
|
|
title: 'Swap I/O',
|
|
units: 'KiB/s',
|
|
family: 'swap',
|
|
chartType: 'area',
|
|
priority: 250,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'in', name: 'in', algorithm: 'incremental' },
|
|
{ id: 'out', name: 'out', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.pgpgio',
|
|
name: 'system.pgpgio',
|
|
context: 'system.pgpgio',
|
|
title: 'Memory Page I/O',
|
|
units: 'KiB/s',
|
|
family: 'pgpgio',
|
|
chartType: 'area',
|
|
priority: 260,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'in', name: 'in', algorithm: 'incremental' },
|
|
{ id: 'out', name: 'out', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.pgfaults',
|
|
name: 'system.pgfaults',
|
|
context: 'system.pgfaults',
|
|
title: 'Memory Page Faults',
|
|
units: 'faults/s',
|
|
family: 'pgfaults',
|
|
chartType: 'line',
|
|
priority: 270,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'minor', name: 'minor', algorithm: 'incremental' },
|
|
{ id: 'major', name: 'major', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
|
|
// ── Aggregate disk / network ──────────────────────────────
|
|
{
|
|
id: 'system.io',
|
|
name: 'system.io',
|
|
context: 'system.io',
|
|
title: 'Disk I/O',
|
|
units: 'KiB/s',
|
|
family: 'disk',
|
|
chartType: 'area',
|
|
priority: 400,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'in', name: 'in', algorithm: 'incremental' },
|
|
{ id: 'out', name: 'out', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.net',
|
|
name: 'system.net',
|
|
context: 'system.net',
|
|
title: 'Physical Network Interfaces Bandwidth',
|
|
units: 'kilobits/s',
|
|
family: 'network',
|
|
chartType: 'area',
|
|
priority: 500,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.ip',
|
|
name: 'system.ip',
|
|
context: 'system.ip',
|
|
title: 'IP Bandwidth',
|
|
units: 'kilobits/s',
|
|
family: 'ip',
|
|
chartType: 'area',
|
|
priority: 600,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.ipv6',
|
|
name: 'system.ipv6',
|
|
context: 'system.ipv6',
|
|
title: 'IPv6 Bandwidth',
|
|
units: 'kilobits/s',
|
|
family: 'ipv6',
|
|
chartType: 'area',
|
|
priority: 610,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
|
|
// ── IP / TCP / UDP aggregates ─────────────────────────────
|
|
{
|
|
id: 'ip.tcppackets',
|
|
name: 'ip.tcppackets',
|
|
context: 'ip.tcppackets',
|
|
title: 'TCP Packets',
|
|
units: 'packets/s',
|
|
family: 'tcp',
|
|
chartType: 'line',
|
|
priority: 700,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ip.tcperrors',
|
|
name: 'ip.tcperrors',
|
|
context: 'ip.tcperrors',
|
|
title: 'TCP Errors',
|
|
units: 'packets/s',
|
|
family: 'tcp',
|
|
chartType: 'line',
|
|
priority: 710,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'InErrs', name: 'InErrs', algorithm: 'incremental' },
|
|
{ id: 'InCsumErrors', name: 'InCsumErrors', algorithm: 'incremental' },
|
|
{ id: 'RetransSegs', name: 'RetransSegs', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ip.tcpopens',
|
|
name: 'ip.tcpopens',
|
|
context: 'ip.tcpopens',
|
|
title: 'TCP Connections',
|
|
units: 'connections/s',
|
|
family: 'tcp',
|
|
chartType: 'line',
|
|
priority: 720,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'active', name: 'active', algorithm: 'incremental' },
|
|
{ id: 'passive', name: 'passive', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ip.tcpsock',
|
|
name: 'ip.tcpsock',
|
|
context: 'ip.tcpsock',
|
|
title: 'TCP Connections Current',
|
|
units: 'connections',
|
|
family: 'tcp',
|
|
chartType: 'line',
|
|
priority: 725,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'connections', name: 'connections', algorithm: 'absolute' }],
|
|
},
|
|
{
|
|
id: 'ipv4.packets',
|
|
name: 'ipv4.packets',
|
|
context: 'ipv4.packets',
|
|
title: 'IPv4 Packets',
|
|
units: 'packets/s',
|
|
family: 'packets',
|
|
chartType: 'line',
|
|
priority: 740,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
{ id: 'forwarded', name: 'forwarded', algorithm: 'incremental' },
|
|
{ id: 'delivered', name: 'delivered', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ipv4.errors',
|
|
name: 'ipv4.errors',
|
|
context: 'ipv4.errors',
|
|
title: 'IPv4 Errors',
|
|
units: 'packets/s',
|
|
family: 'errors',
|
|
chartType: 'line',
|
|
priority: 750,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'InDiscards', name: 'InDiscards', algorithm: 'incremental' },
|
|
{ id: 'OutDiscards', name: 'OutDiscards', algorithm: 'incremental' },
|
|
{ id: 'InHdrErrors', name: 'InHdrErrors', algorithm: 'incremental' },
|
|
{ id: 'OutNoRoutes', name: 'OutNoRoutes', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ipv4.udppackets',
|
|
name: 'ipv4.udppackets',
|
|
context: 'ipv4.udppackets',
|
|
title: 'IPv4 UDP Packets',
|
|
units: 'packets/s',
|
|
family: 'udp',
|
|
chartType: 'line',
|
|
priority: 760,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
{
|
|
id: 'ipv4.udperrors',
|
|
name: 'ipv4.udperrors',
|
|
context: 'ipv4.udperrors',
|
|
title: 'IPv4 UDP Errors',
|
|
units: 'packets/s',
|
|
family: 'udp',
|
|
chartType: 'line',
|
|
priority: 770,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'RcvbufErrors', name: 'RcvbufErrors', algorithm: 'incremental' },
|
|
{ id: 'SndbufErrors', name: 'SndbufErrors', algorithm: 'incremental' },
|
|
{ id: 'InErrors', name: 'InErrors', algorithm: 'incremental' },
|
|
{ id: 'NoPorts', name: 'NoPorts', algorithm: 'incremental' },
|
|
],
|
|
},
|
|
|
|
// ── Pressure stall (PSI) ──────────────────────────────────
|
|
{
|
|
id: 'system.cpu_some_pressure',
|
|
name: 'system.cpu_some_pressure',
|
|
context: 'system.cpu_some_pressure',
|
|
title: 'CPU Some Pressure',
|
|
units: 'percentage',
|
|
family: 'pressure',
|
|
chartType: 'line',
|
|
priority: 800,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'some10', name: 'some10', algorithm: 'absolute' },
|
|
{ id: 'some60', name: 'some60', algorithm: 'absolute' },
|
|
{ id: 'some300', name: 'some300', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.memory_some_pressure',
|
|
name: 'system.memory_some_pressure',
|
|
context: 'system.memory_some_pressure',
|
|
title: 'Memory Some Pressure',
|
|
units: 'percentage',
|
|
family: 'pressure',
|
|
chartType: 'line',
|
|
priority: 810,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'some10', name: 'some10', algorithm: 'absolute' },
|
|
{ id: 'some60', name: 'some60', algorithm: 'absolute' },
|
|
{ id: 'some300', name: 'some300', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
{
|
|
id: 'system.io_some_pressure',
|
|
name: 'system.io_some_pressure',
|
|
context: 'system.io_some_pressure',
|
|
title: 'I/O Some Pressure',
|
|
units: 'percentage',
|
|
family: 'pressure',
|
|
chartType: 'line',
|
|
priority: 820,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'some10', name: 'some10', algorithm: 'absolute' },
|
|
{ id: 'some60', name: 'some60', algorithm: 'absolute' },
|
|
{ id: 'some300', name: 'some300', algorithm: 'absolute' },
|
|
],
|
|
},
|
|
...DEEP_STATIC_CHARTS,
|
|
...MORE_STATIC_CHARTS,
|
|
]
|
|
|
|
/** @type {Map<string, ChartDef>} */
|
|
const runtimeCharts = new Map()
|
|
|
|
/** Static (host-wide catalog) chart ids — used for warm HyperDB cardinality gating. */
|
|
const STATIC_CHART_IDS = new Set(STATIC_CHART_DEFS.map((c) => c.id))
|
|
|
|
/**
|
|
* Whether a chart should be flushed to HyperDB warm storage.
|
|
* High-cardinality instance charts (per-disk, per-iface, cgroup, docker, …)
|
|
* stay in RAM rings only unless PEARDATA_WARM_ALL_CHARTS=1.
|
|
*
|
|
* @param {string} chartId
|
|
* @returns {boolean}
|
|
*/
|
|
export function isWarmPersistableChart(chartId) {
|
|
const all = process.env.PEARDATA_WARM_ALL_CHARTS
|
|
if (all === '1' || all === 'true' || all === 'on') return true
|
|
return STATIC_CHART_IDS.has(String(chartId))
|
|
}
|
|
|
|
/**
|
|
* Register or refresh a dynamic instance chart (per-cpu / disk / iface / mount).
|
|
* @param {ChartDef} def
|
|
*/
|
|
export function registerChart(def) {
|
|
runtimeCharts.set(def.id, def)
|
|
}
|
|
|
|
/**
|
|
* @returns {ChartDef[]}
|
|
*/
|
|
export function getAllChartDefs() {
|
|
return [...STATIC_CHART_DEFS, ...runtimeCharts.values()]
|
|
}
|
|
|
|
/** Alias — prefer getAllChartDefs() when instance charts matter. */
|
|
export const CHART_DEFS = STATIC_CHART_DEFS
|
|
|
|
export const CHART_BY_ID = {
|
|
get(id) {
|
|
const sid = String(id)
|
|
return STATIC_CHART_DEFS.find((c) => c.id === sid) || runtimeCharts.get(sid) || null
|
|
},
|
|
has(id) {
|
|
return this.get(id) != null
|
|
},
|
|
keys() {
|
|
return getAllChartDefs().map((c) => c.id)
|
|
},
|
|
values() {
|
|
return getAllChartDefs()
|
|
},
|
|
get size() {
|
|
return getAllChartDefs().length
|
|
},
|
|
}
|
|
|
|
export function getContextIds() {
|
|
return [...new Set(getAllChartDefs().map((c) => c.context))]
|
|
}
|
|
|
|
/** @deprecated use getContextIds() */
|
|
export const CONTEXT_IDS = {
|
|
map(fn) {
|
|
return getContextIds().map(fn)
|
|
},
|
|
includes(id) {
|
|
return getContextIds().includes(id)
|
|
},
|
|
[Symbol.iterator]() {
|
|
return getContextIds()[Symbol.iterator]()
|
|
},
|
|
get length() {
|
|
return getContextIds().length
|
|
},
|
|
}
|
|
|
|
/**
|
|
* @param {string} context
|
|
*/
|
|
export function chartsForContext(context) {
|
|
return getAllChartDefs().filter((c) => c.context === context)
|
|
}
|
|
|
|
/**
|
|
* Instance chart helpers
|
|
*/
|
|
export function makeCpuCoreChart(coreId) {
|
|
return {
|
|
id: `cpu.cpu${coreId}`,
|
|
name: `cpu.cpu${coreId}`,
|
|
context: 'cpu.cpu',
|
|
title: `Core ${coreId} utilization`,
|
|
units: 'percentage',
|
|
family: `cpu${coreId}`,
|
|
chartType: 'stacked',
|
|
priority: 1000 + Number(coreId),
|
|
plugin: 'proc',
|
|
dimensions: STATIC_CHART_DEFS.find((c) => c.id === 'system.cpu').dimensions.slice(),
|
|
}
|
|
}
|
|
|
|
export function makeDiskIoChart(disk) {
|
|
return {
|
|
id: `disk_io.${disk}`,
|
|
name: `disk_io.${disk}`,
|
|
context: 'disk.io',
|
|
title: `Disk ${disk} I/O`,
|
|
units: 'KiB/s',
|
|
family: disk,
|
|
chartType: 'area',
|
|
priority: 2000,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'reads', name: 'reads', algorithm: 'incremental' },
|
|
{ id: 'writes', name: 'writes', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeDiskOpsChart(disk) {
|
|
return {
|
|
id: `disk_ops.${disk}`,
|
|
name: `disk_ops.${disk}`,
|
|
context: 'disk.ops',
|
|
title: `Disk ${disk} Completed I/O Operations`,
|
|
units: 'operations/s',
|
|
family: disk,
|
|
chartType: 'line',
|
|
priority: 2010,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'reads', name: 'reads', algorithm: 'incremental' },
|
|
{ id: 'writes', name: 'writes', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeDiskUtilChart(disk) {
|
|
return {
|
|
id: `disk_util.${disk}`,
|
|
name: `disk_util.${disk}`,
|
|
context: 'disk.util',
|
|
title: `Disk ${disk} Utilization Time`,
|
|
units: '% of time working',
|
|
family: disk,
|
|
chartType: 'area',
|
|
priority: 2020,
|
|
plugin: 'proc',
|
|
dimensions: [{ id: 'utilization', name: 'utilization', algorithm: 'absolute' }],
|
|
}
|
|
}
|
|
|
|
export function makeNetChart(iface) {
|
|
return {
|
|
id: `net.${iface}`,
|
|
name: `net.${iface}`,
|
|
context: 'net.net',
|
|
title: `Bandwidth ${iface}`,
|
|
units: 'kilobits/s',
|
|
family: iface,
|
|
chartType: 'area',
|
|
priority: 3000,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeNetPacketsChart(iface) {
|
|
return {
|
|
id: `net_packets.${iface}`,
|
|
name: `net_packets.${iface}`,
|
|
context: 'net.packets',
|
|
title: `Packets ${iface}`,
|
|
units: 'packets/s',
|
|
family: iface,
|
|
chartType: 'line',
|
|
priority: 3010,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'received', name: 'received', algorithm: 'incremental' },
|
|
{ id: 'sent', name: 'sent', algorithm: 'incremental' },
|
|
{ id: 'multicast', name: 'multicast', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeNetErrorsChart(iface) {
|
|
return {
|
|
id: `net_errors.${iface}`,
|
|
name: `net_errors.${iface}`,
|
|
context: 'net.errors',
|
|
title: `Interface ${iface} Errors`,
|
|
units: 'errors/s',
|
|
family: iface,
|
|
chartType: 'line',
|
|
priority: 3020,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'inbound', name: 'inbound', algorithm: 'incremental' },
|
|
{ id: 'outbound', name: 'outbound', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeNetDropsChart(iface) {
|
|
return {
|
|
id: `net_drops.${iface}`,
|
|
name: `net_drops.${iface}`,
|
|
context: 'net.drops',
|
|
title: `Interface ${iface} Drops`,
|
|
units: 'drops/s',
|
|
family: iface,
|
|
chartType: 'line',
|
|
priority: 3030,
|
|
plugin: 'proc',
|
|
dimensions: [
|
|
{ id: 'inbound', name: 'inbound', algorithm: 'incremental' },
|
|
{ id: 'outbound', name: 'outbound', algorithm: 'incremental' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeDiskSpaceChart(mountId, mountPath) {
|
|
return {
|
|
id: `disk_space.${mountId}`,
|
|
name: `disk_space.${mountId}`,
|
|
context: 'disk.space',
|
|
title: `Disk Space Usage ${mountPath}`,
|
|
units: 'GiB',
|
|
family: mountPath,
|
|
chartType: 'stacked',
|
|
priority: 4000,
|
|
plugin: 'diskspace',
|
|
dimensions: [
|
|
{ id: 'avail', name: 'avail', algorithm: 'absolute' },
|
|
{ id: 'used', name: 'used', algorithm: 'absolute' },
|
|
{ id: 'reserved_for_root', name: 'reserved_for_root', algorithm: 'absolute' },
|
|
],
|
|
}
|
|
}
|
|
|
|
export function makeDiskInodesChart(mountId, mountPath) {
|
|
return {
|
|
id: `disk_inodes.${mountId}`,
|
|
name: `disk_inodes.${mountId}`,
|
|
context: 'disk.inodes',
|
|
title: `Disk Files (inodes) Usage ${mountPath}`,
|
|
units: 'inodes',
|
|
family: mountPath,
|
|
chartType: 'stacked',
|
|
priority: 4010,
|
|
plugin: 'diskspace',
|
|
dimensions: [
|
|
{ id: 'avail', name: 'avail', algorithm: 'absolute' },
|
|
{ id: 'used', name: 'used', algorithm: 'absolute' },
|
|
{ id: 'reserved_for_root', name: 'reserved_for_root', algorithm: 'absolute' },
|
|
],
|
|
}
|
|
}
|
|
|
|
/** Static aggregate when Docker collector is enabled */
|
|
export const DOCKER_CONTAINERS_CHART = {
|
|
id: 'docker.containers',
|
|
name: 'docker.containers',
|
|
context: 'docker.containers',
|
|
title: 'Running containers',
|
|
units: 'containers',
|
|
family: 'containers',
|
|
chartType: 'line',
|
|
priority: 5000,
|
|
plugin: 'docker',
|
|
dimensions: [
|
|
{ id: 'running', name: 'running', algorithm: 'absolute' },
|
|
{ id: 'total', name: 'total', algorithm: 'absolute' },
|
|
],
|
|
}
|
|
|
|
export function makeDockerCpuChart(shortId, name) {
|
|
const id = shortId.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 64)
|
|
const display = name || `container ${id}`
|
|
return {
|
|
id: `docker.cpu.${id}`,
|
|
name: `docker.cpu.${id}`,
|
|
context: 'docker.cpu',
|
|
title: `${display} · CPU`,
|
|
units: 'percentage',
|
|
family: display,
|
|
chartType: 'area',
|
|
priority: 5100,
|
|
plugin: 'docker',
|
|
dimensions: [{ id: 'usage', name: 'usage', algorithm: 'absolute' }],
|
|
}
|
|
}
|
|
|
|
export function makeDockerMemChart(shortId, name) {
|
|
const id = shortId.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 64)
|
|
const display = name || `container ${id}`
|
|
return {
|
|
id: `docker.mem.${id}`,
|
|
name: `docker.mem.${id}`,
|
|
context: 'docker.mem',
|
|
title: `${display} · memory`,
|
|
units: 'MiB',
|
|
family: display,
|
|
chartType: 'area',
|
|
priority: 5200,
|
|
plugin: 'docker',
|
|
dimensions: [
|
|
{ id: 'usage', name: 'usage', algorithm: 'absolute' },
|
|
{ id: 'limit', name: 'limit', algorithm: 'absolute' },
|
|
],
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build a chart summary object for discovery APIs.
|
|
* @param {ChartDef} def
|
|
* @param {{ firstEntry?: number, lastEntry?: number, updateEvery?: number }} [meta]
|
|
*/
|
|
export function chartSummary(def, meta = {}) {
|
|
const dimensions = {}
|
|
for (const d of def.dimensions) {
|
|
dimensions[d.id] = {
|
|
name: d.name,
|
|
algorithm: d.algorithm,
|
|
multiplier: d.multiplier ?? 1,
|
|
divisor: d.divisor ?? 1,
|
|
}
|
|
}
|
|
return {
|
|
id: def.id,
|
|
name: def.name,
|
|
type: def.plugin || 'system',
|
|
family: def.family,
|
|
context: def.context,
|
|
title: def.title,
|
|
units: def.units,
|
|
chart_type: def.chartType,
|
|
priority: def.priority,
|
|
plugin: def.plugin || 'proc',
|
|
update_every: meta.updateEvery ?? SAMPLE_INTERVAL_MS / 1000,
|
|
first_entry: meta.firstEntry ?? 0,
|
|
last_entry: meta.lastEntry ?? 0,
|
|
dimensions,
|
|
}
|
|
}
|