Files
peardata/server/services/collectors/mongodb.js
T
Raven Scott 2e1a3e9b06
CI / test (push) Successful in 1m24s
Release rolling / release (push) Has been cancelled
Updates
2026-07-18 19:44:32 -04:00

112 lines
3.2 KiB
JavaScript

/**
* MongoDB TCP probe (+ optional serverStatus HTTP sidecar).
* Enable: PEARDATA_MONGODB=1
* URL: PEARDATA_MONGODB_URL=127.0.0.1:27017
*/
import net from 'net'
import { CollectorPlugin } from './plugin.js'
import { registerChart } from '../../../shared/metrics.js'
export function isMongodbEnabled() {
const v = process.env.PEARDATA_MONGODB
return v === '1' || v === 'on' || v === 'true'
}
function endpoint() {
const raw = process.env.PEARDATA_MONGODB_URL || '127.0.0.1:27017'
const u = raw.replace(/^mongodb:\/\//, '')
const [host, port] = u.split(':')
return { host: host || '127.0.0.1', port: Number(port) || 27017 }
}
function probeTcp(host, port, timeoutMs = 1500) {
return new Promise((resolve) => {
const start = Date.now()
const sock = net.connect({ host, port }, () => {
const ms = Date.now() - start
sock.end()
resolve({ up: 1, latency_ms: ms })
})
sock.setTimeout(timeoutMs)
sock.on('timeout', () => {
sock.destroy()
resolve({ up: 0, latency_ms: timeoutMs })
})
sock.on('error', () => resolve({ up: 0, latency_ms: timeoutMs }))
})
}
export class MongodbCollector extends CollectorPlugin {
constructor() {
super({ name: 'mongodb' })
}
isEnabled() {
return isMongodbEnabled()
}
async collect() {
const ts = Date.now()
const { host, port } = endpoint()
const probe = await probeTcp(host, port)
registerChart({
id: 'mongodb.up',
name: 'mongodb.up',
context: 'mongodb.up',
title: 'MongoDB up',
units: 'boolean',
family: 'mongodb',
chartType: 'line',
priority: 8700,
plugin: 'mongodb',
dimensions: [
{ id: 'up', name: 'up', algorithm: 'absolute' },
{ id: 'latency_ms', name: 'latency_ms', algorithm: 'absolute' },
],
})
/** @type {Array<{ chart: string, context: string, ts: number, values: object }>} */
const batch = [
{ chart: 'mongodb.up', context: 'mongodb.up', ts, values: probe },
]
const statsUrl = process.env.PEARDATA_MONGODB_STATS_URL
if (statsUrl) {
try {
const res = await fetch(statsUrl, { signal: AbortSignal.timeout(2000) })
const text = await res.text()
/** @type {Record<string, number>} */
const vals = {}
for (const line of text.split('\n')) {
const [k, v] = line.split(/[=\s]+/)
if (k && v != null && Number.isFinite(Number(v))) vals[k] = Number(v)
}
registerChart({
id: 'mongodb.stats',
name: 'mongodb.stats',
context: 'mongodb.stats',
title: 'MongoDB stats',
units: 'value',
family: 'mongodb',
chartType: 'line',
priority: 8710,
plugin: 'mongodb',
dimensions: Object.keys(vals).map((id) => ({
id,
name: id,
algorithm: 'absolute',
})),
})
batch.push({ chart: 'mongodb.stats', context: 'mongodb.stats', ts, values: vals })
} catch {
// ignore
}
}
return batch
}
}
let singleton = null
export function getMongodbCollector() {
if (!singleton) singleton = new MongodbCollector()
return singleton
}