/** * 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} */ 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 }