Updates
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
/**
|
||||
* Metrics wall taxonomy — maps chart catalog entries into sections/groups.
|
||||
* Versioned independently so new collectors can land without UI rewrites.
|
||||
*/
|
||||
|
||||
export const TAXONOMY_VERSION = 1
|
||||
|
||||
/** @typedef {{ id: string, title: string, order: number, match: (id: string, meta: object) => boolean }} SectionDef */
|
||||
|
||||
/** @type {SectionDef[]} */
|
||||
export const SECTIONS = [
|
||||
{
|
||||
id: 'system',
|
||||
title: 'System',
|
||||
order: 10,
|
||||
match: (id, meta) =>
|
||||
starts(id, [
|
||||
'system.',
|
||||
'cpu.',
|
||||
'mem.',
|
||||
'disk_',
|
||||
'disk.',
|
||||
'net.',
|
||||
'ip.',
|
||||
'ipv4.',
|
||||
'ipv6.',
|
||||
'processes.',
|
||||
]) || ctxStarts(meta, ['system.', 'cpu.', 'mem.', 'disk.', 'net.', 'ip.']),
|
||||
},
|
||||
{
|
||||
id: 'containers',
|
||||
title: 'Containers',
|
||||
order: 20,
|
||||
match: (id, meta) =>
|
||||
starts(id, ['docker.', 'cgroup.', 'peardock.']) ||
|
||||
ctxStarts(meta, ['docker.', 'cgroup.', 'peardock.']),
|
||||
},
|
||||
{
|
||||
id: 'storage',
|
||||
title: 'Storage',
|
||||
order: 30,
|
||||
match: (id, meta) =>
|
||||
starts(id, ['zfs.', 'bcache.', 'dmcache.', 'md.', 'mdstat.', 'smart.', 'fs.', 'ioping.']) ||
|
||||
ctxStarts(meta, ['zfs.', 'bcache.', 'dmcache.', 'md.', 'smart.', 'fs.']),
|
||||
},
|
||||
{
|
||||
id: 'hardware',
|
||||
title: 'Hardware',
|
||||
order: 40,
|
||||
match: (id, meta) =>
|
||||
starts(id, ['sensors.', 'gpu.', 'nvidia.', 'ipmi.', 'system.power', 'power.']) ||
|
||||
ctxStarts(meta, ['sensors.', 'gpu.', 'ipmi.', 'power.']),
|
||||
},
|
||||
{
|
||||
id: 'applications',
|
||||
title: 'Applications',
|
||||
order: 50,
|
||||
match: (id, meta) =>
|
||||
starts(id, [
|
||||
'nginx.',
|
||||
'apache.',
|
||||
'redis.',
|
||||
'mysql.',
|
||||
'postgres.',
|
||||
'memcached.',
|
||||
'mongodb.',
|
||||
'rabbitmq.',
|
||||
'kafka.',
|
||||
'nats.',
|
||||
'unbound.',
|
||||
]) ||
|
||||
ctxStarts(meta, [
|
||||
'nginx.',
|
||||
'apache.',
|
||||
'redis.',
|
||||
'mysql.',
|
||||
'postgres.',
|
||||
'memcached.',
|
||||
'mongodb.',
|
||||
'rabbitmq.',
|
||||
'kafka.',
|
||||
'nats.',
|
||||
'unbound.',
|
||||
]),
|
||||
},
|
||||
{
|
||||
id: 'network-svc',
|
||||
title: 'Network services',
|
||||
order: 60,
|
||||
match: (id, meta) =>
|
||||
starts(id, ['sockets.', 'net.conntrack', 'system.softnet', 'ip.tcp', 'ip.udp']) ||
|
||||
ctxStarts(meta, ['sockets.', 'net.conntrack']),
|
||||
},
|
||||
{
|
||||
id: 'observability',
|
||||
title: 'Observability',
|
||||
order: 70,
|
||||
match: (id, meta) =>
|
||||
starts(id, ['ebpf.', 'statsd.', 'prometheus.', 'peardata.', 'self.']) ||
|
||||
ctxStarts(meta, ['ebpf.', 'statsd.', 'prometheus.', 'peardata.']),
|
||||
},
|
||||
{
|
||||
id: 'fleet',
|
||||
title: 'Fleet',
|
||||
order: 80,
|
||||
match: (id, meta) => starts(id, ['fleet.']) || ctxStarts(meta, ['fleet.']),
|
||||
},
|
||||
{
|
||||
id: 'other',
|
||||
title: 'Other',
|
||||
order: 900,
|
||||
match: () => true,
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {string[]} prefixes
|
||||
*/
|
||||
function starts(id, prefixes) {
|
||||
const s = String(id || '')
|
||||
return prefixes.some((p) => s === p || s.startsWith(p))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} meta
|
||||
* @param {string[]} prefixes
|
||||
*/
|
||||
function ctxStarts(meta, prefixes) {
|
||||
const c = String(meta?.context || meta?.name || '')
|
||||
return prefixes.some((p) => c === p || c.startsWith(p))
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {object} meta
|
||||
*/
|
||||
export function sectionForChart(id, meta = {}) {
|
||||
for (const sec of SECTIONS) {
|
||||
if (sec.id === 'other') continue
|
||||
if (sec.match(id, meta)) return sec
|
||||
}
|
||||
return SECTIONS[SECTIONS.length - 1]
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, object>} catalog
|
||||
* @param {string} [filter]
|
||||
* @returns {{
|
||||
* sections: Array<{
|
||||
* id: string,
|
||||
* title: string,
|
||||
* order: number,
|
||||
* count: number,
|
||||
* groups: Array<{ family: string, charts: Array<{ id: string, meta: object }> }>
|
||||
* }>
|
||||
* }}
|
||||
*/
|
||||
export function groupCatalog(catalog, filter = '') {
|
||||
const q = String(filter || '')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
/** @type {Map<string, { id: string, title: string, order: number, families: Map<string, Array<{ id: string, meta: object }>> }>} */
|
||||
const bySection = new Map()
|
||||
for (const sec of SECTIONS) {
|
||||
bySection.set(sec.id, {
|
||||
id: sec.id,
|
||||
title: sec.title,
|
||||
order: sec.order,
|
||||
families: new Map(),
|
||||
})
|
||||
}
|
||||
|
||||
const ids = Object.keys(catalog || {})
|
||||
for (const id of ids) {
|
||||
const meta = catalog[id] || {}
|
||||
if (q && !matchesFilter(id, meta, q)) continue
|
||||
const sec = sectionForChart(id, meta)
|
||||
const bucket = bySection.get(sec.id)
|
||||
if (!bucket) continue
|
||||
const family = String(meta.family || meta.context || '_default')
|
||||
if (!bucket.families.has(family)) bucket.families.set(family, [])
|
||||
bucket.families.get(family).push({ id, meta })
|
||||
}
|
||||
|
||||
const sections = [...bySection.values()]
|
||||
.map((sec) => {
|
||||
const groups = [...sec.families.entries()]
|
||||
.map(([family, charts]) => ({
|
||||
family,
|
||||
charts: charts.sort(compareCharts),
|
||||
}))
|
||||
.sort((a, b) => a.family.localeCompare(b.family))
|
||||
const count = groups.reduce((n, g) => n + g.charts.length, 0)
|
||||
return { id: sec.id, title: sec.title, order: sec.order, count, groups }
|
||||
})
|
||||
.filter((s) => s.count > 0)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
|
||||
return { sections }
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {object} meta
|
||||
* @param {string} q lowercase
|
||||
*/
|
||||
function matchesFilter(id, meta, q) {
|
||||
const hay = [
|
||||
id,
|
||||
meta.title,
|
||||
meta.name,
|
||||
meta.context,
|
||||
meta.family,
|
||||
meta.plugin,
|
||||
meta.units,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
return hay.includes(q)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{ id: string, meta: object }} a
|
||||
* @param {{ id: string, meta: object }} b
|
||||
*/
|
||||
function compareCharts(a, b) {
|
||||
const pa = Number(a.meta?.priority) || 99999
|
||||
const pb = Number(b.meta?.priority) || 99999
|
||||
if (pa !== pb) return pa - pb
|
||||
return a.id.localeCompare(b.id)
|
||||
}
|
||||
|
||||
/** Time presets for the global metrics bar (seconds of history). */
|
||||
export const TIME_PRESETS = [
|
||||
{ id: '1m', label: '1m', seconds: 60 },
|
||||
{ id: '5m', label: '5m', seconds: 300 },
|
||||
{ id: '15m', label: '15m', seconds: 900 },
|
||||
{ id: '1h', label: '1h', seconds: 3600 },
|
||||
{ id: '6h', label: '6h', seconds: 21600 },
|
||||
]
|
||||
Reference in New Issue
Block a user