forked from snxraven/peardock
Holesail is on unless ENABLE_HOLESAIL=0/false/off. The holesail package remains a required dependency; docs and UI copy match the new default.
102 lines
2.7 KiB
JavaScript
102 lines
2.7 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: process.env.ENABLE_SWARM === '1' || process.env.ENABLE_SWARM === 'true',
|
|
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',
|
|
},
|
|
}
|
|
}
|