Files
peardock/server/services/metrics.js
T
Raven Scott 42a69c6dc7 Ship Track G UX, multi-shell terminals, Swarm default-on, install.peardock.boats
Probe bash/sh/ash and related shells until a container terminal works, enable Swarm APIs by default, add keyboard go-chords and appearance prefs, and point install docs at https://install.peardock.boats.
2026-07-11 18:06:46 -04:00

105 lines
2.8 KiB
JavaScript

/**
* Lightweight process / RPC metrics for production observability.
*/
const startedAt = Date.now()
const counters = {
rpcTotal: 0,
rpcErrors: 0,
rpcDenied: 0,
peersConnected: 0,
peersDisconnected: 0,
pushes: 0,
}
/** @type {Map<string, number>} */
const methodCounts = new Map()
/** @type {number[]} */
const latencies = []
const MAX_LATENCIES = 500
export function recordRpc(method, { ok = true, denied = false, latencyMs = 0 } = {}) {
counters.rpcTotal += 1
if (!ok) counters.rpcErrors += 1
if (denied) counters.rpcDenied += 1
methodCounts.set(method, (methodCounts.get(method) || 0) + 1)
if (latencyMs > 0) {
latencies.push(latencyMs)
if (latencies.length > MAX_LATENCIES) latencies.shift()
}
}
export function recordPeerConnect() {
counters.peersConnected += 1
}
export function recordPeerDisconnect() {
counters.peersDisconnected += 1
}
export function recordPush() {
counters.pushes += 1
}
function percentile(arr, p) {
if (!arr.length) return 0
const sorted = [...arr].sort((a, b) => a - b)
const idx = Math.min(sorted.length - 1, Math.floor((p / 100) * sorted.length))
return sorted[idx]
}
/**
* Snapshot for getMetrics RPC.
* @param {{ peerCount?: number }} [extra]
*/
export function getMetricsSnapshot(extra = {}) {
const mem = process.memoryUsage()
return {
success: true,
type: 'metrics',
uptimeMs: Date.now() - startedAt,
startedAt: new Date(startedAt).toISOString(),
process: {
pid: process.pid,
node: process.version,
rss: mem.rss,
heapUsed: mem.heapUsed,
heapTotal: mem.heapTotal,
external: mem.external,
},
rpc: {
total: counters.rpcTotal,
errors: counters.rpcErrors,
denied: counters.rpcDenied,
byMethod: Object.fromEntries(methodCounts),
latencyMs: {
p50: percentile(latencies, 50),
p95: percentile(latencies, 95),
p99: percentile(latencies, 99),
samples: latencies.length,
},
},
peers: {
connectEvents: counters.peersConnected,
disconnectEvents: counters.peersDisconnected,
live: extra.peerCount ?? null,
},
pushes: counters.pushes,
features: {
swarm: (() => {
const v = String(process.env.ENABLE_SWARM ?? '1').trim().toLowerCase()
return !(v === '0' || v === 'false' || v === 'off' || v === 'no')
})(),
plugins: process.env.ENABLE_PLUGINS === '1' || process.env.ENABLE_PLUGINS === 'true',
holesail: (() => {
const v = String(process.env.ENABLE_HOLESAIL ?? '1').trim().toLowerCase()
return !(v === '0' || v === 'false' || v === 'off' || v === 'no')
})(),
peerAllowlist:
process.env.PEARDOCK_PEER_ALLOWLIST === '1' ||
process.env.PEARDOCK_PEER_ALLOWLIST === 'true',
},
}
}