@adalo/metrics 0.1.82 → 0.1.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/metricsClient.d.ts.map +1 -1
- package/lib/metricsClient.js +2 -0
- package/lib/metricsClient.js.map +1 -1
- package/lib/metricsDatabaseClient.d.ts +9 -4
- package/lib/metricsDatabaseClient.d.ts.map +1 -1
- package/lib/metricsDatabaseClient.js +25 -16
- package/lib/metricsDatabaseClient.js.map +1 -1
- package/lib/metricsRedisClient.d.ts.map +1 -1
- package/lib/metricsRedisClient.js +9 -2
- package/lib/metricsRedisClient.js.map +1 -1
- package/package.json +1 -1
- package/src/metricsClient.js +6 -0
- package/src/metricsDatabaseClient.js +29 -11
- package/src/metricsRedisClient.js +11 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../src/metricsClient.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH;IACE;;;;;;;;;;;;;OAaG;IACH;QAZ2B,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAuD7C;IApDC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,iBAAuE;IACvE,mBAC+D;IAC/D,uBACoE;IACpE,kBAC0E;IAC1E,oBAGI;IACJ,wCAAiD;IAEjD,mBAAyF;IAEzF,uEAAsC;IAGtC;;;;MAIC;IAED,wEAOC;IACD,WAAgB;IAChB,aAAkB;IAClB,sBAA2B;IAE3B,mEAAmE;IACnE;YADkB,MAAM,SAAc,MAAM,GAAG,QAAQ,MAAM,CAAC;MACvC;IACvB,yBAAyB;IACzB,uBAAgC;IASlC;;;OAGG;IACH,4BAmDC;IAED;;;;;;;;OAQG;IACH;QAN2B,IAAI,EAApB,MAAM;QACU,IAAI,EAApB,MAAM;QACuC,QAAQ,UAAzC,MAAM,GAAC,QAAQ,MAAM,CAAC;QACf,UAAU;UAC3B,OAAO,aAAa,EAAE,KAAK,CAuBvC;IAED;;;;;;;;;;;OAWG;IACH;QAR0B,IAAI,EAAnB,MAAM;QACS,IAAI,EAAnB,MAAM;QACY,UAAU;kBAEhB,MAAM,mBAAmB,MAAM,KAAK,IAAI,CAuB9D;IAED;;;OAGG;IACH,0BAFa,MAAM,CA2BlB;IAED;;;OAGG;IACH,oBAFa,MAAM,CAiBlB;IAED;;;OAGG;IACH,2BAFa,MAAM,CAWlB;IAED;;;OAGG;IACH,2BAFa,MAAM,CAgBlB;IAED;;;OAGG;IACH,cAFa,QAAQ,MAAM,CAAC,CAO3B;IAED;;;OAGG;IACH,
|
|
1
|
+
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../src/metricsClient.js"],"names":[],"mappings":"AAKA;;;GAGG;AACH;IACE;;;;;;;;;;;;;OAaG;IACH;QAZ2B,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAuD7C;IApDC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,iBAAuE;IACvE,mBAC+D;IAC/D,uBACoE;IACpE,kBAC0E;IAC1E,oBAGI;IACJ,wCAAiD;IAEjD,mBAAyF;IAEzF,uEAAsC;IAGtC;;;;MAIC;IAED,wEAOC;IACD,WAAgB;IAChB,aAAkB;IAClB,sBAA2B;IAE3B,mEAAmE;IACnE;YADkB,MAAM,SAAc,MAAM,GAAG,QAAQ,MAAM,CAAC;MACvC;IACvB,yBAAyB;IACzB,uBAAgC;IASlC;;;OAGG;IACH,4BAmDC;IAED;;;;;;;;OAQG;IACH;QAN2B,IAAI,EAApB,MAAM;QACU,IAAI,EAApB,MAAM;QACuC,QAAQ,UAAzC,MAAM,GAAC,QAAQ,MAAM,CAAC;QACf,UAAU;UAC3B,OAAO,aAAa,EAAE,KAAK,CAuBvC;IAED;;;;;;;;;;;OAWG;IACH;QAR0B,IAAI,EAAnB,MAAM;QACS,IAAI,EAAnB,MAAM;QACY,UAAU;kBAEhB,MAAM,mBAAmB,MAAM,KAAK,IAAI,CAuB9D;IAED;;;OAGG;IACH,0BAFa,MAAM,CA2BlB;IAED;;;OAGG;IACH,oBAFa,MAAM,CAiBlB;IAED;;;OAGG;IACH,2BAFa,MAAM,CAWlB;IAED;;;OAGG;IACH,2BAFa,MAAM,CAgBlB;IAED;;;OAGG;IACH,cAFa,QAAQ,MAAM,CAAC,CAO3B;IAED;;;OAGG;IACH,oEAoCC;IAED;;OAEG;IACH,6BAEC;IAED;;OAEG;IACH,iCAgCC;IAED,sEAuBC;IAED;;;;;;;;;OASG;IACH,iFAEC;IAED;;;OAGG;IACH,eAFa,QAAQ,IAAI,CAAC,CAOzB;IAED;;;;;;;;;OASG;IACH,yBAuDC;IAED;;;;;;;;;OASG;IACH;;;;;;sBAFa,QAAQ,IAAI,CAAC,CAUzB;IAED;;;;;;;OAOG;IACH;;;sBAFa,QAAQ,IAAI,CAAC,CAYzB;IAED;;;;;;OAMG;IACH,6BAHW,MAAM,EAAE,KACN,MAAM,EAAE,CAIpB;IAED;;;;MAEC;IAED,gCAGC;IAID,8BAEC;IAED,gCAEC;IAED,4EAEC;CACF"}
|
package/lib/metricsClient.js
CHANGED
|
@@ -273,6 +273,7 @@ class MetricsClient {
|
|
|
273
273
|
const route = req.originalUrl || req.url || 'unknown';
|
|
274
274
|
const appId = req.params?.appId || req.body?.appId || req.query?.appId || '';
|
|
275
275
|
const databaseId = req.params?.databaseId || req.body?.databaseId || req.query?.databaseId || req.params?.datasourceId || req.body?.datasourceId || req.query?.datasourceId || '';
|
|
276
|
+
const customActionId = req.params?.customActionId || req.body?.customActionId || req.query?.customActionId || '';
|
|
276
277
|
this.countersFunctions?.app_http_requests_total({
|
|
277
278
|
method: req.method,
|
|
278
279
|
route,
|
|
@@ -280,6 +281,7 @@ class MetricsClient {
|
|
|
280
281
|
status_code: res.statusCode,
|
|
281
282
|
appId,
|
|
282
283
|
databaseId,
|
|
284
|
+
customActionId,
|
|
283
285
|
duration: Date.now() - start,
|
|
284
286
|
requestSize: req.headers['content-length'] ? parseInt(req.headers['content-length'], 10) : 0
|
|
285
287
|
});
|
package/lib/metricsClient.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.js","names":["client","require","fs","os","https","MetricsClient","constructor","config","appName","process","env","BUILD_APP_NAME","dynoId","HOSTNAME","processType","BUILD_DYNO_PROCESS_TYPE","enabled","METRICS_ENABLED","logValues","METRICS_LOG_VALUES","pushgatewayUrl","METRICS_PUSHGATEWAY_URL","authToken","pushgatewaySecret","METRICS_PUSHGATEWAY_SECRET","intervalSec","parseInt","METRICS_INTERVAL_SEC","startupValidation","prefixLogs","_registry","Registry","collectDefaultMetrics","register","defaultLabels","app","dyno_id","process_type","gateway","Pushgateway","headers","Authorization","agent","Agent","keepAlive","gauges","counters","countersFunctions","gaugeUpdaters","_lastUsageMicros","_lastCheckTime","Date","now","_clearOldWorkers","removeOldMetrics","scripDefaultMetrics","_initDefaultMetrics","_setCleanupHandlers","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","uptime","createCounter","labelNames","withDefaultLabels","Object","keys","g","Gauge","registers","c","Counter","data","value","inc","stat","readFileSync","match","currentUsage","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","cpus","length","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","countHttpRequestMiddleware","req","res","next","on","endpoint","route","originalUrl","url","appId","params","body","query","databaseId","datasourceId","app_http_requests_total","method","status_code","statusCode","duration","requestSize","clearAllCounters","values","forEach","counter","reset","pushMetrics","entries","result","undefined","set","err","console","error","gatewayPush","metrics","getMetricsAsJSON","log","JSON","stringify","_startPush","interval","customPushMetics","warn","setInterval","catch","startPush","cleanup","gatewayDelete","exit","fetch","Accept","ok","status","text","regex","RegExp","instances","Set","exec","instance","add","size","groupings","delete","jobName","push","labels","getDefaultLabels","metricsEnabled","metricsLogValues","registry","module","exports"],"sources":["../src/metricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst fs = require('fs')\nconst os = require('os')\nconst https = require('https')\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n * Supports gauges, counters, default metrics, and custom metrics.\n */\nclass MetricsClient {\n /**\n * @param {Object} config\n * @param {string} [config.appName] Name of the application\n * @param {string} [config.dynoId] Dyno/instance ID\n * @param {string} [config.processType] Process type (web, worker, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] PushGateway URL\n * @param {string} [config.pushgatewaySecret] PushGateway secret token\n * @param {number} [config.intervalSec] Interval in seconds for pushing metrics\n * @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name\n * @param {boolean} [config.scripDefaultMetrics] Enable to scip default metrics creation\n * @param {function} [config.startupValidation] Add to validate on start push.\n */\n constructor(config = {}) {\n this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno'\n this.processType =\n config.processType ||\n process.env.BUILD_DYNO_PROCESS_TYPE ||\n 'undefined_build_dyno_type'\n this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true'\n this.logValues =\n config.logValues ?? process.env.METRICS_LOG_VALUES === 'true'\n this.pushgatewayUrl =\n config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || ''\n this.authToken =\n config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || ''\n this.intervalSec =\n config.intervalSec ||\n parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||\n 15\n this.startupValidation = config.startupValidation\n\n this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`\n\n this._registry = new client.Registry()\n client.collectDefaultMetrics({ register: this._registry })\n\n this.defaultLabels = {\n app: this.appName,\n dyno_id: this.dynoId,\n process_type: this.processType,\n }\n\n this.gateway = new client.Pushgateway(\n this.pushgatewayUrl,\n {\n headers: { Authorization: `Basic ${this.authToken}` },\n agent: new https.Agent({ keepAlive: true }),\n },\n this._registry\n )\n this.gauges = {}\n this.counters = {}\n this.countersFunctions = {}\n\n /** @type {Object<string, function(): number | Promise<number>>} */\n this.gaugeUpdaters = {}\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._clearOldWorkers(config.removeOldMetrics)\n if (!config.scripDefaultMetrics) {\n this._initDefaultMetrics()\n }\n this._setCleanupHandlers()\n }\n\n /**\n * Register all built-in default Gauges and Counters.\n * @private\n */\n _initDefaultMetrics = () => {\n this.createGauge({\n name: 'app_process_cpu_usage_percent',\n help: 'Current CPU usage of the Node.js process in percent',\n updateFn: this.getCpuUsagePercent,\n })\n\n this.createGauge({\n name: 'app_available_cpu_count',\n help: 'How many CPU cores are available to this process',\n updateFn: this.getAvailableCPUs,\n })\n\n this.createGauge({\n name: 'app_container_memory_usage_bytes',\n help: 'Current container RAM usage from cgroup',\n updateFn: this.getContainerMemoryUsage,\n })\n\n this.createGauge({\n name: 'app_event_loop_lag_ms',\n help: 'Estimated event loop lag in milliseconds',\n updateFn: this.measureLag,\n })\n\n this.createGauge({\n name: 'app_container_memory_limit_bytes',\n help: 'Max RAM available to container from cgroup (memory.max)',\n updateFn: this.getContainerMemoryLimit,\n })\n\n this.createGauge({\n name: 'app_uptime_seconds',\n help: 'How long the process has been running',\n updateFn: process.uptime,\n })\n\n this.createCounter({\n name: 'app_http_requests_total',\n help: 'Total number of HTTP requests handled by this process',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'endpoint',\n 'appId',\n 'databaseId',\n 'duration',\n 'requestSize',\n 'status_code',\n ]),\n })\n }\n\n /**\n * Create a gauge metric.\n * @param {Object} options - Gauge configuration\n * @param {string} options.name - Name of the gauge\n * @param {string} options.help - Help text describing the gauge\n * @param {function(): number|Promise<number>} [options.updateFn] - Optional function returning the gauge value\n * @param {string[]} [options.labelNames] - Optional custom label names\n * @returns {import('prom-client').Gauge} The created Prometheus gauge\n */\n createGauge = ({\n name,\n help,\n updateFn,\n labelNames = Object.keys(this.defaultLabels),\n }) => {\n if (this.gauges[name]) return this.gauges[name]\n\n const g = new client.Gauge({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.gauges[name] = g\n\n if (updateFn && typeof updateFn === 'function') {\n this.gaugeUpdaters[name] = updateFn\n }\n\n return g\n }\n\n /**\n * Create a Prometheus Counter metric.\n *\n * @param {Object} params - Counter configuration\n * @param {string} params.name - Metric name\n * @param {string} params.help - Metric description\n * @param {string[]} [params.labelNames] - Optional list of label names. Defaults to this.defaultLabels keys.\n *\n * @returns {(labels?: Object, incrementValue?: number) => void}\n * A function to increment the counter.\n * Usage: (labels?, incrementValue?)\n */\n createCounter({ name, help, labelNames = Object.keys(this.defaultLabels) }) {\n if (this.counters[name]) return this.countersFunctions[name]\n\n const c = new client.Counter({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.counters[name] = c\n\n this.countersFunctions = {\n ...this.countersFunctions,\n [name]: (data = {}, value = 1) => {\n c.inc({ ...this.defaultLabels, ...data }, value)\n },\n }\n\n return this.countersFunctions[name]\n }\n\n /**\n * Get CPU usage percent (cgroup-aware)\n * @returns {number}\n */\n getCpuUsagePercent = () => {\n try {\n const stat = fs.readFileSync('/sys/fs/cgroup/cpu.stat', 'utf-8')\n const match = stat.match(/usage_usec (\\d+)/)\n if (!match) return 0\n\n const now = Date.now()\n const currentUsage = parseInt(match[1], 10)\n\n if (this._lastUsageMicros === 0) {\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n return 0\n }\n\n const deltaUsage = currentUsage - this._lastUsageMicros\n const deltaTime = now - this._lastCheckTime\n\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n\n return (deltaUsage / (deltaTime * 1000)) * 100\n } catch {\n return 0\n }\n }\n\n /**\n * Get available CPU cores.\n * @returns {number}\n */\n getAvailableCPUs() {\n try {\n const cpuMaxPath = '/sys/fs/cgroup/cpu.max'\n if (fs.existsSync(cpuMaxPath)) {\n const [quotaStr, periodStr] = fs\n .readFileSync(cpuMaxPath, 'utf8')\n .trim()\n .split(' ')\n if (quotaStr === 'max') return os.cpus().length\n return parseInt(quotaStr, 10) / parseInt(periodStr, 10)\n }\n return os.cpus().length\n } catch {\n return 1\n }\n }\n\n /**\n * Get container memory usage in bytes.\n * @returns {number}\n */\n getContainerMemoryUsage() {\n try {\n return parseInt(\n fs.readFileSync('/sys/fs/cgroup/memory.current', 'utf-8').trim(),\n 10\n )\n } catch {\n return process.memoryUsage().rss\n }\n }\n\n /**\n * Get container memory limit in bytes.\n * @returns {number}\n */\n getContainerMemoryLimit() {\n try {\n const path = '/sys/fs/cgroup/memory.max'\n if (fs.existsSync(path)) {\n const val = fs.readFileSync(path, 'utf-8').trim()\n if (val !== 'max') {\n const parsed = parseInt(val, 10)\n if (parsed && parsed < os.totalmem()) return parsed\n }\n }\n return os.totalmem()\n } catch {\n return os.totalmem()\n }\n }\n\n /**\n * Measure event loop lag in ms.\n * @returns {Promise<number>}\n */\n measureLag() {\n return new Promise(resolve => {\n const start = Date.now()\n setImmediate(() => resolve(Date.now() - start))\n })\n }\n\n /**\n * Express middleware to count HTTP requests.\n * Increments the `app_http_requests_total` counter.\n */\n countHttpRequestMiddleware = (req, res, next) => {\n const start = Date.now()\n res.on('finish', () => {\n const endpoint = req.route?.path || req.path || 'unknown'\n const route = req.originalUrl || req.url || 'unknown'\n const appId =\n req.params?.appId || req.body?.appId || req.query?.appId || ''\n const databaseId =\n req.params?.databaseId ||\n req.body?.databaseId ||\n req.query?.databaseId ||\n req.params?.datasourceId ||\n req.body?.datasourceId ||\n req.query?.datasourceId ||\n ''\n this.countersFunctions?.app_http_requests_total({\n method: req.method,\n route,\n endpoint,\n status_code: res.statusCode,\n appId,\n databaseId,\n duration: Date.now() - start,\n requestSize: req.headers['content-length']\n ? parseInt(req.headers['content-length'], 10)\n : 0,\n })\n })\n\n next()\n }\n\n /**\n * Clear all collected counters\n */\n clearAllCounters = () => {\n Object.values(this.counters).forEach(counter => counter.reset())\n }\n\n /**\n * Push all gauges and counters to PushGateway and optionally log.\n */\n pushMetrics = async () => {\n try {\n for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {\n try {\n if (!updateFn) {\n return\n }\n const result = updateFn()\n const val = result instanceof Promise ? await result : result\n if (val !== undefined) this.gauges[name].set(this.defaultLabels, val)\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to update gauge ${name}:`,\n err\n )\n }\n }\n\n await this.gatewayPush()\n\n this.clearAllCounters()\n\n if (this.logValues) {\n const metrics = await this._registry.getMetricsAsJSON()\n console.log(\n `${this.prefixLogs} Metrics:\\n`,\n JSON.stringify(metrics, null, 2)\n )\n }\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n }\n }\n\n _startPush = (interval = this.intervalSec, customPushMetics = undefined) => {\n if (!this.enabled) {\n console.warn(`${this.prefixLogs} Metrics disabled`)\n return\n }\n\n if (this.startupValidation && !this.startupValidation()) {\n return\n }\n\n if (customPushMetics && typeof customPushMetics === 'function') {\n setInterval(() => customPushMetics(), interval * 1000)\n } else {\n setInterval(() => {\n this.pushMetrics().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n })\n }, interval * 1000)\n }\n\n console.warn(\n `${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s)`\n )\n }\n\n /**\n * Start periodic metrics collection and push.\n *\n * This method wraps the internal `_startPush` method.\n * If a `customPushMetrics` function is provided, it will be executed\n * at the given interval instead of the default `pushMetrics` behavior.\n *\n * @param {number} [interval=this.intervalSec] - Interval in seconds between pushes.\n * @param {() => void | Promise<void>} [customPushMetrics] - Optional custom push function. If provided, Prometheus push is skipped.\n */\n startPush = (interval, customPushMetics = undefined) => {\n this._startPush(interval, customPushMetics)\n }\n\n /**\n * Cleanup metrics and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n if (this.enabled) {\n await this.gatewayDelete()\n }\n process.exit(0)\n }\n\n /**\n * Remove old/stale dyno/instance metrics from PushGateway.\n *\n * Compares existing PushGateway metrics for this job and deletes any instances\n * that do not match the current dynoId.\n *\n * @param {boolean} removeOldMetrics If true, performs cleanup; otherwise does nothing\n * @returns {Promise<void>}\n * @private\n */\n _clearOldWorkers = async removeOldMetrics => {\n if (!removeOldMetrics) return\n\n try {\n const url = `${this.pushgatewayUrl}/metrics`\n const res = await fetch(url, {\n headers: {\n Authorization: `Basic ${this.authToken}`,\n Accept: 'text/plain',\n },\n })\n\n if (!res.ok) {\n console.error(\n `${this.prefixLogs} Failed to fetch metrics: ${res.status}`\n )\n return\n }\n\n const text = await res.text()\n\n const regex = new RegExp(\n `(?:instance=\"([^\"]+)\".*job=\"${this.appName}\"|job=\"${this.appName}\".*instance=\"([^\"]+)\")`,\n 'g'\n )\n const instances = new Set()\n let match\n // eslint-disable-next-line no-cond-assign\n while ((match = regex.exec(text)) !== null) {\n const instance = match[1] || match[2]\n if (instance && instance !== this.dynoId) instances.add(instance)\n }\n\n if (instances.size === 0) {\n console.log(`${this.prefixLogs} No old dynos to delete.`)\n return\n }\n\n for (const instance of instances) {\n await this.gatewayDelete({\n groupings: {\n instance,\n },\n })\n console.log(\n `${this.prefixLogs} Deleted metrics for old dyno: ${instance}`\n )\n }\n\n console.log(\n `${this.prefixLogs} Cleared all old instances for job ${this.appName}`\n )\n } catch (err) {\n console.error(`${this.prefixLogs} Error deleting old metrics:`, err)\n }\n }\n\n /**\n * Delete metrics for this job/instance from PushGateway.\n *\n * @param {Object} [params]\n * @param {string} [params.jobName] Job name (defaults to appName)\n * @param {Object} [params.groupings] Grouping labels\n * @param {string} [params.groupings.process_type] Process type label\n * @param {string} [params.groupings.instance] Instance/dyno ID\n * @returns {Promise<void>}\n */\n gatewayDelete = async (params = {}) => {\n return this.gateway.delete({\n jobName: params.jobName || this.appName,\n groupings: {\n process_type: params.groupings?.process_type || this.processType,\n instance: params.groupings?.instance || this.dynoId,\n },\n })\n }\n\n /**\n * Push metrics to PushGateway.\n *\n * @param {object} [params]\n * @param {string} [params.jobName]\n * @param {object} [params.groupings]\n * @returns {Promise<void>}\n */\n gatewayPush = async (params = {}) => {\n const groupings = {\n process_type: this.processType,\n instance: this.dynoId,\n ...(params.groupings || {}),\n }\n return this.gateway.push({\n jobName: params.jobName || this.appName,\n groupings,\n })\n }\n\n /**\n * Merge the default metric labels (`app`, `dyno_id`, `process_type`)\n * with custom label names.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabels = (labels = []) => {\n return [...Object.keys(this.defaultLabels), ...labels]\n }\n\n getDefaultLabels = (labels = []) => {\n return this.defaultLabels\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n // GETTERS\n\n get metricsEnabled() {\n return this.enabled\n }\n\n get metricsLogValues() {\n return this.logValues\n }\n\n get registry() {\n return this._registry\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsClient.js","names":["client","require","fs","os","https","MetricsClient","constructor","config","appName","process","env","BUILD_APP_NAME","dynoId","HOSTNAME","processType","BUILD_DYNO_PROCESS_TYPE","enabled","METRICS_ENABLED","logValues","METRICS_LOG_VALUES","pushgatewayUrl","METRICS_PUSHGATEWAY_URL","authToken","pushgatewaySecret","METRICS_PUSHGATEWAY_SECRET","intervalSec","parseInt","METRICS_INTERVAL_SEC","startupValidation","prefixLogs","_registry","Registry","collectDefaultMetrics","register","defaultLabels","app","dyno_id","process_type","gateway","Pushgateway","headers","Authorization","agent","Agent","keepAlive","gauges","counters","countersFunctions","gaugeUpdaters","_lastUsageMicros","_lastCheckTime","Date","now","_clearOldWorkers","removeOldMetrics","scripDefaultMetrics","_initDefaultMetrics","_setCleanupHandlers","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","uptime","createCounter","labelNames","withDefaultLabels","Object","keys","g","Gauge","registers","c","Counter","data","value","inc","stat","readFileSync","match","currentUsage","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","cpus","length","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","countHttpRequestMiddleware","req","res","next","on","endpoint","route","originalUrl","url","appId","params","body","query","databaseId","datasourceId","customActionId","app_http_requests_total","method","status_code","statusCode","duration","requestSize","clearAllCounters","values","forEach","counter","reset","pushMetrics","entries","result","undefined","set","err","console","error","gatewayPush","metrics","getMetricsAsJSON","log","JSON","stringify","_startPush","interval","customPushMetics","warn","setInterval","catch","startPush","cleanup","gatewayDelete","exit","fetch","Accept","ok","status","text","regex","RegExp","instances","Set","exec","instance","add","size","groupings","delete","jobName","push","labels","getDefaultLabels","metricsEnabled","metricsLogValues","registry","module","exports"],"sources":["../src/metricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst fs = require('fs')\nconst os = require('os')\nconst https = require('https')\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n * Supports gauges, counters, default metrics, and custom metrics.\n */\nclass MetricsClient {\n /**\n * @param {Object} config\n * @param {string} [config.appName] Name of the application\n * @param {string} [config.dynoId] Dyno/instance ID\n * @param {string} [config.processType] Process type (web, worker, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] PushGateway URL\n * @param {string} [config.pushgatewaySecret] PushGateway secret token\n * @param {number} [config.intervalSec] Interval in seconds for pushing metrics\n * @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name\n * @param {boolean} [config.scripDefaultMetrics] Enable to scip default metrics creation\n * @param {function} [config.startupValidation] Add to validate on start push.\n */\n constructor(config = {}) {\n this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno'\n this.processType =\n config.processType ||\n process.env.BUILD_DYNO_PROCESS_TYPE ||\n 'undefined_build_dyno_type'\n this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true'\n this.logValues =\n config.logValues ?? process.env.METRICS_LOG_VALUES === 'true'\n this.pushgatewayUrl =\n config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || ''\n this.authToken =\n config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || ''\n this.intervalSec =\n config.intervalSec ||\n parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||\n 15\n this.startupValidation = config.startupValidation\n\n this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`\n\n this._registry = new client.Registry()\n client.collectDefaultMetrics({ register: this._registry })\n\n this.defaultLabels = {\n app: this.appName,\n dyno_id: this.dynoId,\n process_type: this.processType,\n }\n\n this.gateway = new client.Pushgateway(\n this.pushgatewayUrl,\n {\n headers: { Authorization: `Basic ${this.authToken}` },\n agent: new https.Agent({ keepAlive: true }),\n },\n this._registry\n )\n this.gauges = {}\n this.counters = {}\n this.countersFunctions = {}\n\n /** @type {Object<string, function(): number | Promise<number>>} */\n this.gaugeUpdaters = {}\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._clearOldWorkers(config.removeOldMetrics)\n if (!config.scripDefaultMetrics) {\n this._initDefaultMetrics()\n }\n this._setCleanupHandlers()\n }\n\n /**\n * Register all built-in default Gauges and Counters.\n * @private\n */\n _initDefaultMetrics = () => {\n this.createGauge({\n name: 'app_process_cpu_usage_percent',\n help: 'Current CPU usage of the Node.js process in percent',\n updateFn: this.getCpuUsagePercent,\n })\n\n this.createGauge({\n name: 'app_available_cpu_count',\n help: 'How many CPU cores are available to this process',\n updateFn: this.getAvailableCPUs,\n })\n\n this.createGauge({\n name: 'app_container_memory_usage_bytes',\n help: 'Current container RAM usage from cgroup',\n updateFn: this.getContainerMemoryUsage,\n })\n\n this.createGauge({\n name: 'app_event_loop_lag_ms',\n help: 'Estimated event loop lag in milliseconds',\n updateFn: this.measureLag,\n })\n\n this.createGauge({\n name: 'app_container_memory_limit_bytes',\n help: 'Max RAM available to container from cgroup (memory.max)',\n updateFn: this.getContainerMemoryLimit,\n })\n\n this.createGauge({\n name: 'app_uptime_seconds',\n help: 'How long the process has been running',\n updateFn: process.uptime,\n })\n\n this.createCounter({\n name: 'app_http_requests_total',\n help: 'Total number of HTTP requests handled by this process',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'endpoint',\n 'appId',\n 'databaseId',\n 'duration',\n 'requestSize',\n 'status_code',\n ]),\n })\n }\n\n /**\n * Create a gauge metric.\n * @param {Object} options - Gauge configuration\n * @param {string} options.name - Name of the gauge\n * @param {string} options.help - Help text describing the gauge\n * @param {function(): number|Promise<number>} [options.updateFn] - Optional function returning the gauge value\n * @param {string[]} [options.labelNames] - Optional custom label names\n * @returns {import('prom-client').Gauge} The created Prometheus gauge\n */\n createGauge = ({\n name,\n help,\n updateFn,\n labelNames = Object.keys(this.defaultLabels),\n }) => {\n if (this.gauges[name]) return this.gauges[name]\n\n const g = new client.Gauge({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.gauges[name] = g\n\n if (updateFn && typeof updateFn === 'function') {\n this.gaugeUpdaters[name] = updateFn\n }\n\n return g\n }\n\n /**\n * Create a Prometheus Counter metric.\n *\n * @param {Object} params - Counter configuration\n * @param {string} params.name - Metric name\n * @param {string} params.help - Metric description\n * @param {string[]} [params.labelNames] - Optional list of label names. Defaults to this.defaultLabels keys.\n *\n * @returns {(labels?: Object, incrementValue?: number) => void}\n * A function to increment the counter.\n * Usage: (labels?, incrementValue?)\n */\n createCounter({ name, help, labelNames = Object.keys(this.defaultLabels) }) {\n if (this.counters[name]) return this.countersFunctions[name]\n\n const c = new client.Counter({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.counters[name] = c\n\n this.countersFunctions = {\n ...this.countersFunctions,\n [name]: (data = {}, value = 1) => {\n c.inc({ ...this.defaultLabels, ...data }, value)\n },\n }\n\n return this.countersFunctions[name]\n }\n\n /**\n * Get CPU usage percent (cgroup-aware)\n * @returns {number}\n */\n getCpuUsagePercent = () => {\n try {\n const stat = fs.readFileSync('/sys/fs/cgroup/cpu.stat', 'utf-8')\n const match = stat.match(/usage_usec (\\d+)/)\n if (!match) return 0\n\n const now = Date.now()\n const currentUsage = parseInt(match[1], 10)\n\n if (this._lastUsageMicros === 0) {\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n return 0\n }\n\n const deltaUsage = currentUsage - this._lastUsageMicros\n const deltaTime = now - this._lastCheckTime\n\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n\n return (deltaUsage / (deltaTime * 1000)) * 100\n } catch {\n return 0\n }\n }\n\n /**\n * Get available CPU cores.\n * @returns {number}\n */\n getAvailableCPUs() {\n try {\n const cpuMaxPath = '/sys/fs/cgroup/cpu.max'\n if (fs.existsSync(cpuMaxPath)) {\n const [quotaStr, periodStr] = fs\n .readFileSync(cpuMaxPath, 'utf8')\n .trim()\n .split(' ')\n if (quotaStr === 'max') return os.cpus().length\n return parseInt(quotaStr, 10) / parseInt(periodStr, 10)\n }\n return os.cpus().length\n } catch {\n return 1\n }\n }\n\n /**\n * Get container memory usage in bytes.\n * @returns {number}\n */\n getContainerMemoryUsage() {\n try {\n return parseInt(\n fs.readFileSync('/sys/fs/cgroup/memory.current', 'utf-8').trim(),\n 10\n )\n } catch {\n return process.memoryUsage().rss\n }\n }\n\n /**\n * Get container memory limit in bytes.\n * @returns {number}\n */\n getContainerMemoryLimit() {\n try {\n const path = '/sys/fs/cgroup/memory.max'\n if (fs.existsSync(path)) {\n const val = fs.readFileSync(path, 'utf-8').trim()\n if (val !== 'max') {\n const parsed = parseInt(val, 10)\n if (parsed && parsed < os.totalmem()) return parsed\n }\n }\n return os.totalmem()\n } catch {\n return os.totalmem()\n }\n }\n\n /**\n * Measure event loop lag in ms.\n * @returns {Promise<number>}\n */\n measureLag() {\n return new Promise(resolve => {\n const start = Date.now()\n setImmediate(() => resolve(Date.now() - start))\n })\n }\n\n /**\n * Express middleware to count HTTP requests.\n * Increments the `app_http_requests_total` counter.\n */\n countHttpRequestMiddleware = (req, res, next) => {\n const start = Date.now()\n res.on('finish', () => {\n const endpoint = req.route?.path || req.path || 'unknown'\n const route = req.originalUrl || req.url || 'unknown'\n const appId =\n req.params?.appId || req.body?.appId || req.query?.appId || ''\n const databaseId =\n req.params?.databaseId ||\n req.body?.databaseId ||\n req.query?.databaseId ||\n req.params?.datasourceId ||\n req.body?.datasourceId ||\n req.query?.datasourceId ||\n ''\n const customActionId =\n req.params?.customActionId ||\n req.body?.customActionId ||\n req.query?.customActionId ||\n ''\n this.countersFunctions?.app_http_requests_total({\n method: req.method,\n route,\n endpoint,\n status_code: res.statusCode,\n appId,\n databaseId,\n customActionId,\n duration: Date.now() - start,\n requestSize: req.headers['content-length']\n ? parseInt(req.headers['content-length'], 10)\n : 0,\n })\n })\n\n next()\n }\n\n /**\n * Clear all collected counters\n */\n clearAllCounters = () => {\n Object.values(this.counters).forEach(counter => counter.reset())\n }\n\n /**\n * Push all gauges and counters to PushGateway and optionally log.\n */\n pushMetrics = async () => {\n try {\n for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {\n try {\n if (!updateFn) {\n return\n }\n const result = updateFn()\n const val = result instanceof Promise ? await result : result\n if (val !== undefined) this.gauges[name].set(this.defaultLabels, val)\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to update gauge ${name}:`,\n err\n )\n }\n }\n\n await this.gatewayPush()\n\n this.clearAllCounters()\n\n if (this.logValues) {\n const metrics = await this._registry.getMetricsAsJSON()\n console.log(\n `${this.prefixLogs} Metrics:\\n`,\n JSON.stringify(metrics, null, 2)\n )\n }\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n }\n }\n\n _startPush = (interval = this.intervalSec, customPushMetics = undefined) => {\n if (!this.enabled) {\n console.warn(`${this.prefixLogs} Metrics disabled`)\n return\n }\n\n if (this.startupValidation && !this.startupValidation()) {\n return\n }\n\n if (customPushMetics && typeof customPushMetics === 'function') {\n setInterval(() => customPushMetics(), interval * 1000)\n } else {\n setInterval(() => {\n this.pushMetrics().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n })\n }, interval * 1000)\n }\n\n console.warn(\n `${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s)`\n )\n }\n\n /**\n * Start periodic metrics collection and push.\n *\n * This method wraps the internal `_startPush` method.\n * If a `customPushMetrics` function is provided, it will be executed\n * at the given interval instead of the default `pushMetrics` behavior.\n *\n * @param {number} [interval=this.intervalSec] - Interval in seconds between pushes.\n * @param {() => void | Promise<void>} [customPushMetrics] - Optional custom push function. If provided, Prometheus push is skipped.\n */\n startPush = (interval, customPushMetics = undefined) => {\n this._startPush(interval, customPushMetics)\n }\n\n /**\n * Cleanup metrics and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n if (this.enabled) {\n await this.gatewayDelete()\n }\n process.exit(0)\n }\n\n /**\n * Remove old/stale dyno/instance metrics from PushGateway.\n *\n * Compares existing PushGateway metrics for this job and deletes any instances\n * that do not match the current dynoId.\n *\n * @param {boolean} removeOldMetrics If true, performs cleanup; otherwise does nothing\n * @returns {Promise<void>}\n * @private\n */\n _clearOldWorkers = async removeOldMetrics => {\n if (!removeOldMetrics) return\n\n try {\n const url = `${this.pushgatewayUrl}/metrics`\n const res = await fetch(url, {\n headers: {\n Authorization: `Basic ${this.authToken}`,\n Accept: 'text/plain',\n },\n })\n\n if (!res.ok) {\n console.error(\n `${this.prefixLogs} Failed to fetch metrics: ${res.status}`\n )\n return\n }\n\n const text = await res.text()\n\n const regex = new RegExp(\n `(?:instance=\"([^\"]+)\".*job=\"${this.appName}\"|job=\"${this.appName}\".*instance=\"([^\"]+)\")`,\n 'g'\n )\n const instances = new Set()\n let match\n // eslint-disable-next-line no-cond-assign\n while ((match = regex.exec(text)) !== null) {\n const instance = match[1] || match[2]\n if (instance && instance !== this.dynoId) instances.add(instance)\n }\n\n if (instances.size === 0) {\n console.log(`${this.prefixLogs} No old dynos to delete.`)\n return\n }\n\n for (const instance of instances) {\n await this.gatewayDelete({\n groupings: {\n instance,\n },\n })\n console.log(\n `${this.prefixLogs} Deleted metrics for old dyno: ${instance}`\n )\n }\n\n console.log(\n `${this.prefixLogs} Cleared all old instances for job ${this.appName}`\n )\n } catch (err) {\n console.error(`${this.prefixLogs} Error deleting old metrics:`, err)\n }\n }\n\n /**\n * Delete metrics for this job/instance from PushGateway.\n *\n * @param {Object} [params]\n * @param {string} [params.jobName] Job name (defaults to appName)\n * @param {Object} [params.groupings] Grouping labels\n * @param {string} [params.groupings.process_type] Process type label\n * @param {string} [params.groupings.instance] Instance/dyno ID\n * @returns {Promise<void>}\n */\n gatewayDelete = async (params = {}) => {\n return this.gateway.delete({\n jobName: params.jobName || this.appName,\n groupings: {\n process_type: params.groupings?.process_type || this.processType,\n instance: params.groupings?.instance || this.dynoId,\n },\n })\n }\n\n /**\n * Push metrics to PushGateway.\n *\n * @param {object} [params]\n * @param {string} [params.jobName]\n * @param {object} [params.groupings]\n * @returns {Promise<void>}\n */\n gatewayPush = async (params = {}) => {\n const groupings = {\n process_type: this.processType,\n instance: this.dynoId,\n ...(params.groupings || {}),\n }\n return this.gateway.push({\n jobName: params.jobName || this.appName,\n groupings,\n })\n }\n\n /**\n * Merge the default metric labels (`app`, `dyno_id`, `process_type`)\n * with custom label names.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabels = (labels = []) => {\n return [...Object.keys(this.defaultLabels), ...labels]\n }\n\n getDefaultLabels = (labels = []) => {\n return this.defaultLabels\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n // GETTERS\n\n get metricsEnabled() {\n return this.enabled\n }\n\n get metricsLogValues() {\n return this.logValues\n }\n\n get registry() {\n return this._registry\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -8,7 +8,8 @@ export class DatabaseMetricsClient extends MetricsClient {
|
|
|
8
8
|
/**
|
|
9
9
|
* @param {Object} options
|
|
10
10
|
* @param {string} options.databaseUrl - Required main database URL
|
|
11
|
-
* @param {string
|
|
11
|
+
* @param {string} options.databaseName - Main database name for metrics
|
|
12
|
+
* @param {Object<string, string>} [options.additional_database_urls] - Optional additional DBs, keyed by custom name with URL as value
|
|
12
13
|
* @param {string} [options.appName] - Application name (from MetricsClient)
|
|
13
14
|
* @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
|
|
14
15
|
* @param {string} [options.processType] - Process type (from MetricsClient)
|
|
@@ -21,9 +22,12 @@ export class DatabaseMetricsClient extends MetricsClient {
|
|
|
21
22
|
* @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation
|
|
22
23
|
* @param {function} [options.startupValidation] - Function to validate startup
|
|
23
24
|
*/
|
|
24
|
-
constructor({ databaseUrl, additional_database_urls, ...metricsConfig }?: {
|
|
25
|
+
constructor({ databaseUrl, databaseName, additional_database_urls, ...metricsConfig }?: {
|
|
25
26
|
databaseUrl: string;
|
|
26
|
-
|
|
27
|
+
databaseName: string;
|
|
28
|
+
additional_database_urls?: {
|
|
29
|
+
[x: string]: string;
|
|
30
|
+
} | undefined;
|
|
27
31
|
appName?: string | undefined;
|
|
28
32
|
dynoId?: string | undefined;
|
|
29
33
|
processType?: string | undefined;
|
|
@@ -36,9 +40,10 @@ export class DatabaseMetricsClient extends MetricsClient {
|
|
|
36
40
|
scripDefaultMetrics?: boolean | undefined;
|
|
37
41
|
startupValidation?: Function | undefined;
|
|
38
42
|
});
|
|
39
|
-
databasePools:
|
|
43
|
+
databasePools: any[];
|
|
40
44
|
/** Gauge for Database connections */
|
|
41
45
|
databaseConnectionsGauge: import("prom-client").Gauge<string>;
|
|
46
|
+
_addPool: (url: any, dbKey: any) => Pool;
|
|
42
47
|
/**
|
|
43
48
|
* @param {Pool} pool - PG connection pool
|
|
44
49
|
* @returns {Promise<{ current: number, max: number, dbName: string }>}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsDatabaseClient.d.ts","sourceRoot":"","sources":["../src/metricsDatabaseClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"metricsDatabaseClient.d.ts","sourceRoot":"","sources":["../src/metricsDatabaseClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IACE;;;;;;;;;;;;;;;;OAgBG;IACH;QAf2B,WAAW,EAA3B,MAAM;QACU,YAAY,EAA5B,MAAM;QAC2B,wBAAwB;;;QACxC,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAmF9C;IAtBC,qBAAuB;IAUvB,qCAAqC;IACrC,8DAQE;IAKJ,yCAKC;IAED;;;OAGG;IACH,gCAHW,IAAI,KACF,QAAQ;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CA4BrE;IAED;;;OAGG;IACH,8BAFa,QAAQ,IAAI,CAAC,CAsBzB;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAoBzB;IAED;;;OAGG;IACH,sDAMC;CAwBF"}
|
|
@@ -17,7 +17,8 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {Object} options
|
|
19
19
|
* @param {string} options.databaseUrl - Required main database URL
|
|
20
|
-
* @param {string
|
|
20
|
+
* @param {string} options.databaseName - Main database name for metrics
|
|
21
|
+
* @param {Object<string, string>} [options.additional_database_urls] - Optional additional DBs, keyed by custom name with URL as value
|
|
21
22
|
* @param {string} [options.appName] - Application name (from MetricsClient)
|
|
22
23
|
* @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
|
|
23
24
|
* @param {string} [options.processType] - Process type (from MetricsClient)
|
|
@@ -32,10 +33,13 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
32
33
|
*/
|
|
33
34
|
constructor({
|
|
34
35
|
databaseUrl,
|
|
35
|
-
|
|
36
|
+
databaseName,
|
|
37
|
+
additional_database_urls = {},
|
|
36
38
|
...metricsConfig
|
|
37
39
|
} = {}) {
|
|
38
40
|
const intervalSec = metricsConfig.intervalSec || parseInt(process.env.METRICS_DATABASE_INTERVAL_SEC || '', 10) || 60;
|
|
41
|
+
const tmpAppName = metricsConfig.appName || process.env.BUILD_APP_NAME || 'unknown-app';
|
|
42
|
+
const mainDbName = databaseName || `${tmpAppName}_db`;
|
|
39
43
|
const startupValidation = async () => {
|
|
40
44
|
if (!databaseUrl) {
|
|
41
45
|
console.error(`[database-metrics] ❌ METRICS_DATABASE_URL is required`);
|
|
@@ -47,21 +51,21 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
47
51
|
});
|
|
48
52
|
await mainPool.query('SELECT 1');
|
|
49
53
|
await mainPool.end();
|
|
50
|
-
console.info(`[database-metrics] ✓ Main database OK`);
|
|
54
|
+
console.info(`[database-metrics] ✓ Main database OK: ${mainDbName}`);
|
|
51
55
|
} catch (err) {
|
|
52
56
|
console.error(`[database-metrics] ❌ Cannot connect to main database: ${err.message}`);
|
|
53
57
|
return false;
|
|
54
58
|
}
|
|
55
|
-
for (const url of additional_database_urls) {
|
|
59
|
+
for (const [dbKey, url] of Object.entries(additional_database_urls)) {
|
|
56
60
|
try {
|
|
57
61
|
const p = new Pool({
|
|
58
62
|
connectionString: url
|
|
59
63
|
});
|
|
60
64
|
await p.query('SELECT 1');
|
|
61
65
|
await p.end();
|
|
62
|
-
console.info(`[database-metrics] ✓ Additional database OK: ${
|
|
66
|
+
console.info(`[database-metrics] ✓ Additional database OK: ${dbKey}`);
|
|
63
67
|
} catch (err) {
|
|
64
|
-
console.error(`[database-metrics] ⚠ Skipping additional database: ${
|
|
68
|
+
console.error(`[database-metrics] ⚠ Skipping additional database: ${dbKey}`);
|
|
65
69
|
console.error(`[database-metrics] ${err.message}`);
|
|
66
70
|
}
|
|
67
71
|
}
|
|
@@ -77,24 +81,28 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
77
81
|
});
|
|
78
82
|
this.databasePools = [];
|
|
79
83
|
if (databaseUrl) {
|
|
80
|
-
this.
|
|
81
|
-
connectionString: databaseUrl
|
|
82
|
-
}));
|
|
84
|
+
this._addPool(databaseUrl, mainDbName);
|
|
83
85
|
}
|
|
84
|
-
for (const url of additional_database_urls) {
|
|
85
|
-
this.
|
|
86
|
-
connectionString: url
|
|
87
|
-
}));
|
|
86
|
+
for (const [dbKey, url] of Object.entries(additional_database_urls)) {
|
|
87
|
+
this._addPool(url, dbKey);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
/** Gauge for Database connections */
|
|
91
91
|
this.databaseConnectionsGauge = this.createGauge({
|
|
92
92
|
name: 'app_database_connections',
|
|
93
93
|
help: 'Postgres database connections',
|
|
94
|
-
labelNames: this.withDefaultLabels(['max_connections', 'database_name'])
|
|
94
|
+
labelNames: this.withDefaultLabels(['max_connections', 'database_name', 'db_key'])
|
|
95
95
|
});
|
|
96
96
|
this._setCleanupHandlers();
|
|
97
97
|
}
|
|
98
|
+
_addPool = (url, dbKey) => {
|
|
99
|
+
const pool = new Pool({
|
|
100
|
+
connectionString: url
|
|
101
|
+
});
|
|
102
|
+
pool.dbKey = dbKey;
|
|
103
|
+
this.databasePools.push(pool);
|
|
104
|
+
return pool;
|
|
105
|
+
};
|
|
98
106
|
|
|
99
107
|
/**
|
|
100
108
|
* @param {Pool} pool - PG connection pool
|
|
@@ -143,8 +151,9 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
143
151
|
} = await this.getDBConnectionsAndName(pool);
|
|
144
152
|
this.databaseConnectionsGauge.set({
|
|
145
153
|
...this.getDefaultLabels(),
|
|
146
|
-
database_name:
|
|
147
|
-
max_connections: String(max)
|
|
154
|
+
database_name: pool.dbKey,
|
|
155
|
+
max_connections: String(max),
|
|
156
|
+
db_key: dbName
|
|
148
157
|
}, current);
|
|
149
158
|
} catch (err) {
|
|
150
159
|
console.warn(`[database-metrics] Failed to collect: ${err.message}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsDatabaseClient.js","names":["Pool","require","MetricsClient","DatabaseMetricsClient","constructor","databaseUrl","additional_database_urls","metricsConfig","intervalSec","parseInt","process","env","METRICS_DATABASE_INTERVAL_SEC","startupValidation","console","error","mainPool","connectionString","query","end","info","err","message","url","p","scripDefaultMetrics","processType","databasePools","push","databaseConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","getDBConnectionsAndName","pool","currentRes","current","rows","maxRes","max","dbName","options","database","URL","pathname","replace","collectDatabaseMetrics","set","getDefaultLabels","database_name","max_connections","String","warn","pushDatabaseMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","exit","on","module","exports"],"sources":["../src/metricsDatabaseClient.js"],"sourcesContent":["const { Pool } = require('pg')\nconst { MetricsClient } = require('.')\n\n/**\n * DatabaseMetricsClient collects Postgres connection metrics\n * and pushes them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass DatabaseMetricsClient extends MetricsClient {\n /**\n * @param {Object} options\n * @param {string} options.databaseUrl - Required main database URL\n * @param {string[]} [options.additional_database_urls] - Optional additional DB URLs\n * @param {string} [options.appName] - Application name (from MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation\n * @param {function} [options.startupValidation] - Function to validate startup\n */\n constructor({\n databaseUrl,\n additional_database_urls = [],\n ...metricsConfig\n } = {}) {\n const intervalSec =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_DATABASE_INTERVAL_SEC || '', 10) ||\n 60\n\n const startupValidation = async () => {\n if (!databaseUrl) {\n console.error(`[database-metrics] ❌ METRICS_DATABASE_URL is required`)\n return false\n }\n\n try {\n const mainPool = new Pool({ connectionString: databaseUrl })\n await mainPool.query('SELECT 1')\n await mainPool.end()\n console.info(`[database-metrics] ✓ Main database OK`)\n } catch (err) {\n console.error(\n `[database-metrics] ❌ Cannot connect to main database: ${err.message}`\n )\n return false\n }\n\n for (const url of additional_database_urls) {\n try {\n const p = new Pool({ connectionString: url })\n await p.query('SELECT 1')\n await p.end()\n console.info(`[database-metrics] ✓ Additional database OK: ${url}`)\n } catch (err) {\n console.error(\n `[database-metrics] ⚠ Skipping additional database: ${url}`\n )\n console.error(`[database-metrics] ${err.message}`)\n }\n }\n\n console.info(`[database-metrics] Database metrics collection starting`)\n return true\n }\n\n super({\n ...metricsConfig,\n scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'database-metrics',\n intervalSec,\n startupValidation,\n })\n\n this.databasePools = []\n\n if (databaseUrl) {\n this.databasePools.push(new Pool({ connectionString: databaseUrl }))\n }\n\n for (const url of additional_database_urls) {\n this.databasePools.push(new Pool({ connectionString: url }))\n }\n\n /** Gauge for Database connections */\n this.databaseConnectionsGauge = this.createGauge({\n name: 'app_database_connections',\n help: 'Postgres database connections',\n labelNames: this.withDefaultLabels(['max_connections', 'database_name']),\n })\n\n this._setCleanupHandlers()\n }\n\n /**\n * @param {Pool} pool - PG connection pool\n * @returns {Promise<{ current: number, max: number, dbName: string }>}\n */\n getDBConnectionsAndName = async pool => {\n try {\n const currentRes = await pool.query(\n 'SELECT COUNT(*) AS current FROM pg_stat_activity WHERE datname = current_database()'\n )\n const current = parseInt(currentRes.rows[0]?.current || 0, 10)\n\n const maxRes = await pool.query(\n \"SELECT current_setting('max_connections') AS max\"\n )\n const max = parseInt(maxRes.rows[0]?.max || 0, 10)\n\n let dbName = pool.options?.database\n if (!dbName && pool.options?.connectionString) {\n try {\n const url = new URL(pool.options.connectionString)\n dbName = url.pathname.replace(/^\\//, '')\n } catch {\n dbName = pool.options.connectionString\n }\n }\n\n return { current, max, dbName }\n } catch (err) {\n return { current: 0, max: 0, dbName: pool.options?.database || '' }\n }\n }\n\n /**\n * Collect database connection metrics for all configured pools\n * @returns {Promise<void>}\n */\n collectDatabaseMetrics = async () => {\n for (const pool of this.databasePools) {\n try {\n const { current, max, dbName } = await this.getDBConnectionsAndName(\n pool\n )\n\n this.databaseConnectionsGauge.set(\n {\n ...this.getDefaultLabels(),\n database_name: dbName,\n max_connections: String(max),\n },\n current\n )\n } catch (err) {\n console.warn(`[database-metrics] Failed to collect: ${err.message}`)\n }\n }\n }\n\n /**\n * Push database metrics to Prometheus Pushgateway\n * @returns {Promise<void>}\n */\n pushDatabaseMetrics = async () => {\n try {\n await this.collectDatabaseMetrics()\n await this.gatewayPush()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[database-metrics] Collected DB metrics`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n console.error(\n `[database-metrics] Failed to collect DB metrics: ${error.message}`\n )\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.pushDatabaseMetrics().catch(err => {\n console.error(`[database-metrics] Failed to push DB metrics:`, err)\n })\n })\n }\n\n /**\n * Cleanup database pools and exit process\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n try {\n if (this.databasePools) {\n for (const pool of this.databasePools) {\n await pool.end()\n }\n }\n } catch (err) {\n console.error('[database-metrics] Error during cleanup:', err)\n }\n\n process.exit(0)\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n}\n\nmodule.exports = { DatabaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsDatabaseClient.js","names":["Pool","require","MetricsClient","DatabaseMetricsClient","constructor","databaseUrl","databaseName","additional_database_urls","metricsConfig","intervalSec","parseInt","process","env","METRICS_DATABASE_INTERVAL_SEC","tmpAppName","appName","BUILD_APP_NAME","mainDbName","startupValidation","console","error","mainPool","connectionString","query","end","info","err","message","dbKey","url","Object","entries","p","scripDefaultMetrics","processType","databasePools","_addPool","databaseConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","pool","push","getDBConnectionsAndName","currentRes","current","rows","maxRes","max","dbName","options","database","URL","pathname","replace","collectDatabaseMetrics","set","getDefaultLabels","database_name","max_connections","String","db_key","warn","pushDatabaseMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","exit","on","module","exports"],"sources":["../src/metricsDatabaseClient.js"],"sourcesContent":["const { Pool } = require('pg')\nconst { MetricsClient } = require('.')\n\n/**\n * DatabaseMetricsClient collects Postgres connection metrics\n * and pushes them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass DatabaseMetricsClient extends MetricsClient {\n /**\n * @param {Object} options\n * @param {string} options.databaseUrl - Required main database URL\n * @param {string} options.databaseName - Main database name for metrics\n * @param {Object<string, string>} [options.additional_database_urls] - Optional additional DBs, keyed by custom name with URL as value\n * @param {string} [options.appName] - Application name (from MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation\n * @param {function} [options.startupValidation] - Function to validate startup\n */\n constructor({\n databaseUrl,\n databaseName,\n additional_database_urls = {},\n ...metricsConfig\n } = {}) {\n const intervalSec =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_DATABASE_INTERVAL_SEC || '', 10) ||\n 60\n\n const tmpAppName =\n metricsConfig.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n const mainDbName = databaseName || `${tmpAppName}_db`\n\n const startupValidation = async () => {\n if (!databaseUrl) {\n console.error(`[database-metrics] ❌ METRICS_DATABASE_URL is required`)\n return false\n }\n\n try {\n const mainPool = new Pool({ connectionString: databaseUrl })\n await mainPool.query('SELECT 1')\n await mainPool.end()\n console.info(`[database-metrics] ✓ Main database OK: ${mainDbName}`)\n } catch (err) {\n console.error(\n `[database-metrics] ❌ Cannot connect to main database: ${err.message}`\n )\n return false\n }\n\n for (const [dbKey, url] of Object.entries(additional_database_urls)) {\n try {\n const p = new Pool({ connectionString: url })\n await p.query('SELECT 1')\n await p.end()\n console.info(`[database-metrics] ✓ Additional database OK: ${dbKey}`)\n } catch (err) {\n console.error(\n `[database-metrics] ⚠ Skipping additional database: ${dbKey}`\n )\n console.error(`[database-metrics] ${err.message}`)\n }\n }\n\n console.info(`[database-metrics] Database metrics collection starting`)\n return true\n }\n\n super({\n ...metricsConfig,\n scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'database-metrics',\n intervalSec,\n startupValidation,\n })\n\n this.databasePools = []\n\n if (databaseUrl) {\n this._addPool(databaseUrl, mainDbName)\n }\n\n for (const [dbKey, url] of Object.entries(additional_database_urls)) {\n this._addPool(url, dbKey)\n }\n\n /** Gauge for Database connections */\n this.databaseConnectionsGauge = this.createGauge({\n name: 'app_database_connections',\n help: 'Postgres database connections',\n labelNames: this.withDefaultLabels([\n 'max_connections',\n 'database_name',\n 'db_key',\n ]),\n })\n\n this._setCleanupHandlers()\n }\n\n _addPool = (url, dbKey) => {\n const pool = new Pool({ connectionString: url })\n pool.dbKey = dbKey\n this.databasePools.push(pool)\n return pool\n }\n\n /**\n * @param {Pool} pool - PG connection pool\n * @returns {Promise<{ current: number, max: number, dbName: string }>}\n */\n getDBConnectionsAndName = async pool => {\n try {\n const currentRes = await pool.query(\n 'SELECT COUNT(*) AS current FROM pg_stat_activity WHERE datname = current_database()'\n )\n const current = parseInt(currentRes.rows[0]?.current || 0, 10)\n\n const maxRes = await pool.query(\n \"SELECT current_setting('max_connections') AS max\"\n )\n const max = parseInt(maxRes.rows[0]?.max || 0, 10)\n\n let dbName = pool.options?.database\n if (!dbName && pool.options?.connectionString) {\n try {\n const url = new URL(pool.options.connectionString)\n dbName = url.pathname.replace(/^\\//, '')\n } catch {\n dbName = pool.options.connectionString\n }\n }\n\n return { current, max, dbName }\n } catch (err) {\n return { current: 0, max: 0, dbName: pool.options?.database || '' }\n }\n }\n\n /**\n * Collect database connection metrics for all configured pools\n * @returns {Promise<void>}\n */\n collectDatabaseMetrics = async () => {\n for (const pool of this.databasePools) {\n try {\n const { current, max, dbName } = await this.getDBConnectionsAndName(\n pool\n )\n\n this.databaseConnectionsGauge.set(\n {\n ...this.getDefaultLabels(),\n database_name: pool.dbKey,\n max_connections: String(max),\n db_key: dbName,\n },\n current\n )\n } catch (err) {\n console.warn(`[database-metrics] Failed to collect: ${err.message}`)\n }\n }\n }\n\n /**\n * Push database metrics to Prometheus Pushgateway\n * @returns {Promise<void>}\n */\n pushDatabaseMetrics = async () => {\n try {\n await this.collectDatabaseMetrics()\n await this.gatewayPush()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[database-metrics] Collected DB metrics`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n console.error(\n `[database-metrics] Failed to collect DB metrics: ${error.message}`\n )\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.pushDatabaseMetrics().catch(err => {\n console.error(`[database-metrics] Failed to push DB metrics:`, err)\n })\n })\n }\n\n /**\n * Cleanup database pools and exit process\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n try {\n if (this.databasePools) {\n for (const pool of this.databasePools) {\n await pool.end()\n }\n }\n } catch (err) {\n console.error('[database-metrics] Error during cleanup:', err)\n }\n\n process.exit(0)\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n}\n\nmodule.exports = { DatabaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH;QAbwB,WAAW,EAAxB,GAAG;QACc,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAyC9C;IA1BC,oCAAoC;IACpC,iBAA8B;IAC9B,wBAAsD;IAEtD,yCAAyC;IACzC,2DAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ,
|
|
1
|
+
{"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH;QAbwB,WAAW,EAAxB,GAAG;QACc,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAyC9C;IA1BC,oCAAoC;IACpC,iBAA8B;IAC9B,wBAAsD;IAEtD,yCAAyC;IACzC,2DAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ,wCAiCC;IAED,6CAuBC;IAED,gDAeC;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAgEzB;IAED;;;OAGG;IACH,wBAFa,QAAQ,IAAI,CAAC,CAoBzB;IAED;;;OAGG;IACH,sDAMC;CA4BF"}
|
|
@@ -86,14 +86,21 @@ class RedisMetricsClient extends MetricsClient {
|
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
// node-redis v4
|
|
90
|
-
if (this.redisClientType === REDIS_V4
|
|
89
|
+
// node-redis v4
|
|
90
|
+
if (this.redisClientType === REDIS_V4) {
|
|
91
91
|
try {
|
|
92
92
|
return this.redisClient.sendCommand(['CLIENT', 'LIST']);
|
|
93
93
|
} catch (err) {
|
|
94
94
|
throw new Error(`Failed to get CLIENT LIST: ${err.message}`);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
|
+
if (this.redisClientType === IOREDIS) {
|
|
98
|
+
try {
|
|
99
|
+
return this.redisClient.client('LIST');
|
|
100
|
+
} catch (err) {
|
|
101
|
+
throw new Error(`Failed to get CLIENT LIST: ${err.message}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
97
104
|
throw new Error('Unsupported Redis client type');
|
|
98
105
|
};
|
|
99
106
|
getRedisInfo = async section => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsRedisClient.js","names":["MetricsClient","require","getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","redisConnectionStableFields","redisConnectionFields","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","scripDefaultMetrics","processType","redisClientType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","getRedisConnections","Error","Promise","resolve","reject","send_command","err","result","message","sendCommand","getRedisInfo","section","info","parseRedisConnections","clientsStr","split","filter","line","trim","map","parts","client","forEach","p","k","v","includes","collectRedisMetrics","memoryInfoStr","statsInfoStr","connectionsInfoStr","all","labels","getDefaultLabels","connections","connection","id","age","flags","totMem","labelsForConnections","set","metric","parseRedisInfo","infoStr","Object","fromEntries","startsWith","length","memory","stats","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","error","console","warn","pushRedisMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const { MetricsClient } = require('.')\nconst {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('./redisUtils')\n\nconst redisConnectionStableFields = ['id', 'name', 'flags', 'metric']\nconst redisConnectionFields = ['id', 'name', 'age', 'flags', 'tot-mem']\n\n/**\n * RedisMetricsClient extends MetricsClient to collect\n * Redis metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass RedisMetricsClient extends MetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)\n */\n constructor({ redisClient, ...metricsConfig } = {}) {\n const intervalSec =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) ||\n 5\n\n super({\n ...metricsConfig,\n scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'queue-metrics',\n intervalSec,\n })\n\n /** Redis client used for metrics */\n this.redisClient = redisClient\n this.redisClientType = getRedisClientType(redisClient)\n\n /** Gauge for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections',\n help: 'Redis client connections',\n labelNames: this.withDefaultLabels(redisConnectionStableFields),\n })\n\n /** Gauge for Redis memory usage */\n this.redisMemoryGauge = this.createGauge({\n name: 'app_redis_memory_bytes',\n help: 'Redis memory usage in bytes',\n labelNames: this.withDefaultLabels(['memory_type']),\n })\n\n /** Gauge for Redis operation stats */\n this.redisStatsGauge = this.createGauge({\n name: 'app_redis_stats_total',\n help: 'Redis operation statistics',\n labelNames: this.withDefaultLabels(['operation']),\n })\n\n this._setCleanupHandlers()\n }\n\n getRedisConnections = async () => {\n if (!this.redisClient) throw new Error('Redis client not provided')\n\n // node-redis v3 (uses callback)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.send_command('CLIENT', ['LIST'], (err, result) => {\n if (err) {\n reject(new Error(`Failed to get CLIENT LIST: ${err.message}`))\n } else resolve(result)\n })\n })\n }\n\n // node-redis v4 or ioredis – Promise API\n if (this.redisClientType === REDIS_V4 || this.redisClientType === IOREDIS) {\n try {\n return this.redisClient.sendCommand(['CLIENT', 'LIST'])\n } catch (err) {\n throw new Error(`Failed to get CLIENT LIST: ${err.message}`)\n }\n }\n\n throw new Error('Unsupported Redis client type')\n }\n\n getRedisInfo = async section => {\n if (!this.redisClient) throw new Error('Redis client not provided')\n\n // node-redis v3 (uses callback)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.info(section, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n }\n\n // node-redis v4 or ioredis (info returns Promise)\n if (this.redisClientType === REDIS_V4 || this.redisClientType === IOREDIS) {\n try {\n return this.redisClient.info(section)\n } catch (err) {\n throw new Error(`Failed to get Redis INFO: ${err.message}`)\n }\n }\n\n throw new Error('Unsupported Redis client type')\n }\n\n parseRedisConnections = clientsStr => {\n return clientsStr\n .split('\\n')\n .filter(line => line.trim() !== '')\n .map(line => {\n const parts = line.split(' ')\n const client = {}\n parts.forEach(p => {\n const [k, v] = p.split('=')\n if (redisConnectionFields.includes(k)) {\n client[k] = v\n }\n })\n return client\n })\n }\n\n /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const [memoryInfoStr, statsInfoStr, connectionsInfoStr] =\n await Promise.all([\n this.getRedisInfo('memory'),\n this.getRedisInfo('stats'),\n this.getRedisConnections(),\n ])\n\n const labels = this.getDefaultLabels()\n\n const connections = this.parseRedisConnections(connectionsInfoStr)\n connections.forEach(connection => {\n const { id, name, age, flags, 'tot-mem': totMem } = connection\n const labelsForConnections = { ...labels, id, name, flags }\n this.redisConnectionsGauge.set(\n { ...labelsForConnections, metric: 'age' },\n parseInt(age, 10)\n )\n this.redisConnectionsGauge.set(\n { ...labelsForConnections, metric: 'tot-mem' },\n parseInt(totMem, 10)\n )\n })\n\n const parseRedisInfo = infoStr =>\n Object.fromEntries(\n infoStr\n .split('\\r\\n')\n .filter(line => line && !line.startsWith('#'))\n .map(line => line.split(':', 2))\n .filter(parts => parts.length === 2 && parts[0] && parts[1])\n )\n\n const memory = parseRedisInfo(memoryInfoStr)\n const stats = parseRedisInfo(statsInfoStr)\n\n if (memory.used_memory) {\n this.redisMemoryGauge.set(\n { ...labels, memory_type: 'used' },\n parseInt(memory.used_memory, 10) || 0\n )\n }\n if (memory.maxmemory) {\n this.redisMemoryGauge.set(\n { ...labels, memory_type: 'max' },\n parseInt(memory.maxmemory, 10) || 0\n )\n }\n\n if (stats.instantaneous_ops_per_sec) {\n this.redisStatsGauge.set(\n { ...labels, operation: 'ops_per_sec' },\n parseInt(stats.instantaneous_ops_per_sec, 10) || 0\n )\n }\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect Redis metrics:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all Redis and push to Prometheus Pushgateway\n * @returns {Promise<void>}\n */\n pushRedisMetrics = async () => {\n try {\n await this.collectRedisMetrics()\n await this.gatewayPush()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for Redis`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n console.error(\n `[queue-metrics] Failed to collect Redis metrics: ${error.message}`\n )\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.pushRedisMetrics().catch(err => {\n console.error(`[queue-metrics] Failed to push Redis metrics:`, err)\n })\n })\n }\n\n /**\n * Cleanup Redis client and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n try {\n if (!this.redisClient) return\n\n if (\n this.redisClientType === REDIS_V3 ||\n this.redisClientType === REDIS_V4\n ) {\n await this.redisClient.quit()\n } else if (this.redisClientType === IOREDIS) {\n await this.redisClient.disconnect()\n }\n } catch (err) {\n console.error('[queue-metrics] Error closing Redis client:', err)\n }\n process.exit(0)\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n}\n\nmodule.exports = { RedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsRedisClient.js","names":["MetricsClient","require","getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","redisConnectionStableFields","redisConnectionFields","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","scripDefaultMetrics","processType","redisClientType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","getRedisConnections","Error","Promise","resolve","reject","send_command","err","result","message","sendCommand","client","getRedisInfo","section","info","parseRedisConnections","clientsStr","split","filter","line","trim","map","parts","forEach","p","k","v","includes","collectRedisMetrics","memoryInfoStr","statsInfoStr","connectionsInfoStr","all","labels","getDefaultLabels","connections","connection","id","age","flags","totMem","labelsForConnections","set","metric","parseRedisInfo","infoStr","Object","fromEntries","startsWith","length","memory","stats","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","error","console","warn","pushRedisMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const { MetricsClient } = require('.')\nconst {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('./redisUtils')\n\nconst redisConnectionStableFields = ['id', 'name', 'flags', 'metric']\nconst redisConnectionFields = ['id', 'name', 'age', 'flags', 'tot-mem']\n\n/**\n * RedisMetricsClient extends MetricsClient to collect\n * Redis metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass RedisMetricsClient extends MetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)\n */\n constructor({ redisClient, ...metricsConfig } = {}) {\n const intervalSec =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) ||\n 5\n\n super({\n ...metricsConfig,\n scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'queue-metrics',\n intervalSec,\n })\n\n /** Redis client used for metrics */\n this.redisClient = redisClient\n this.redisClientType = getRedisClientType(redisClient)\n\n /** Gauge for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections',\n help: 'Redis client connections',\n labelNames: this.withDefaultLabels(redisConnectionStableFields),\n })\n\n /** Gauge for Redis memory usage */\n this.redisMemoryGauge = this.createGauge({\n name: 'app_redis_memory_bytes',\n help: 'Redis memory usage in bytes',\n labelNames: this.withDefaultLabels(['memory_type']),\n })\n\n /** Gauge for Redis operation stats */\n this.redisStatsGauge = this.createGauge({\n name: 'app_redis_stats_total',\n help: 'Redis operation statistics',\n labelNames: this.withDefaultLabels(['operation']),\n })\n\n this._setCleanupHandlers()\n }\n\n getRedisConnections = async () => {\n if (!this.redisClient) throw new Error('Redis client not provided')\n\n // node-redis v3 (uses callback)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.send_command('CLIENT', ['LIST'], (err, result) => {\n if (err) {\n reject(new Error(`Failed to get CLIENT LIST: ${err.message}`))\n } else resolve(result)\n })\n })\n }\n\n // node-redis v4\n if (this.redisClientType === REDIS_V4) {\n try {\n return this.redisClient.sendCommand(['CLIENT', 'LIST'])\n } catch (err) {\n throw new Error(`Failed to get CLIENT LIST: ${err.message}`)\n }\n }\n\n if (this.redisClientType === IOREDIS) {\n try {\n return this.redisClient.client('LIST')\n } catch (err) {\n throw new Error(`Failed to get CLIENT LIST: ${err.message}`)\n }\n }\n\n\n throw new Error('Unsupported Redis client type')\n }\n\n getRedisInfo = async section => {\n if (!this.redisClient) throw new Error('Redis client not provided')\n\n // node-redis v3 (uses callback)\n if (this.redisClientType === REDIS_V3) {\n return new Promise((resolve, reject) => {\n this.redisClient.info(section, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n }\n\n // node-redis v4 or ioredis (info returns Promise)\n if (this.redisClientType === REDIS_V4 || this.redisClientType === IOREDIS) {\n try {\n return this.redisClient.info(section)\n } catch (err) {\n throw new Error(`Failed to get Redis INFO: ${err.message}`)\n }\n }\n\n throw new Error('Unsupported Redis client type')\n }\n\n parseRedisConnections = clientsStr => {\n return clientsStr\n .split('\\n')\n .filter(line => line.trim() !== '')\n .map(line => {\n const parts = line.split(' ')\n const client = {}\n parts.forEach(p => {\n const [k, v] = p.split('=')\n if (redisConnectionFields.includes(k)) {\n client[k] = v\n }\n })\n return client\n })\n }\n\n /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const [memoryInfoStr, statsInfoStr, connectionsInfoStr] =\n await Promise.all([\n this.getRedisInfo('memory'),\n this.getRedisInfo('stats'),\n this.getRedisConnections(),\n ])\n\n const labels = this.getDefaultLabels()\n\n const connections = this.parseRedisConnections(connectionsInfoStr)\n connections.forEach(connection => {\n const { id, name, age, flags, 'tot-mem': totMem } = connection\n const labelsForConnections = { ...labels, id, name, flags }\n this.redisConnectionsGauge.set(\n { ...labelsForConnections, metric: 'age' },\n parseInt(age, 10)\n )\n this.redisConnectionsGauge.set(\n { ...labelsForConnections, metric: 'tot-mem' },\n parseInt(totMem, 10)\n )\n })\n\n const parseRedisInfo = infoStr =>\n Object.fromEntries(\n infoStr\n .split('\\r\\n')\n .filter(line => line && !line.startsWith('#'))\n .map(line => line.split(':', 2))\n .filter(parts => parts.length === 2 && parts[0] && parts[1])\n )\n\n const memory = parseRedisInfo(memoryInfoStr)\n const stats = parseRedisInfo(statsInfoStr)\n\n if (memory.used_memory) {\n this.redisMemoryGauge.set(\n { ...labels, memory_type: 'used' },\n parseInt(memory.used_memory, 10) || 0\n )\n }\n if (memory.maxmemory) {\n this.redisMemoryGauge.set(\n { ...labels, memory_type: 'max' },\n parseInt(memory.maxmemory, 10) || 0\n )\n }\n\n if (stats.instantaneous_ops_per_sec) {\n this.redisStatsGauge.set(\n { ...labels, operation: 'ops_per_sec' },\n parseInt(stats.instantaneous_ops_per_sec, 10) || 0\n )\n }\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect Redis metrics:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all Redis and push to Prometheus Pushgateway\n * @returns {Promise<void>}\n */\n pushRedisMetrics = async () => {\n try {\n await this.collectRedisMetrics()\n await this.gatewayPush()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for Redis`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n console.error(\n `[queue-metrics] Failed to collect Redis metrics: ${error.message}`\n )\n throw error\n }\n }\n\n /**\n * Start periodic collection.\n * @param {number} [intervalSec=this.intervalSec] - Interval in seconds\n */\n startPush = (intervalSec = this.intervalSec) => {\n this._startPush(intervalSec, () => {\n this.pushRedisMetrics().catch(err => {\n console.error(`[queue-metrics] Failed to push Redis metrics:`, err)\n })\n })\n }\n\n /**\n * Cleanup Redis client and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n try {\n if (!this.redisClient) return\n\n if (\n this.redisClientType === REDIS_V3 ||\n this.redisClientType === REDIS_V4\n ) {\n await this.redisClient.quit()\n } else if (this.redisClientType === IOREDIS) {\n await this.redisClient.disconnect()\n }\n } catch (err) {\n console.error('[queue-metrics] Error closing Redis client:', err)\n }\n process.exit(0)\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n}\n\nmodule.exports = { RedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
package/src/metricsClient.js
CHANGED
|
@@ -316,6 +316,11 @@ class MetricsClient {
|
|
|
316
316
|
req.body?.datasourceId ||
|
|
317
317
|
req.query?.datasourceId ||
|
|
318
318
|
''
|
|
319
|
+
const customActionId =
|
|
320
|
+
req.params?.customActionId ||
|
|
321
|
+
req.body?.customActionId ||
|
|
322
|
+
req.query?.customActionId ||
|
|
323
|
+
''
|
|
319
324
|
this.countersFunctions?.app_http_requests_total({
|
|
320
325
|
method: req.method,
|
|
321
326
|
route,
|
|
@@ -323,6 +328,7 @@ class MetricsClient {
|
|
|
323
328
|
status_code: res.statusCode,
|
|
324
329
|
appId,
|
|
325
330
|
databaseId,
|
|
331
|
+
customActionId,
|
|
326
332
|
duration: Date.now() - start,
|
|
327
333
|
requestSize: req.headers['content-length']
|
|
328
334
|
? parseInt(req.headers['content-length'], 10)
|
|
@@ -11,7 +11,8 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
11
11
|
/**
|
|
12
12
|
* @param {Object} options
|
|
13
13
|
* @param {string} options.databaseUrl - Required main database URL
|
|
14
|
-
* @param {string
|
|
14
|
+
* @param {string} options.databaseName - Main database name for metrics
|
|
15
|
+
* @param {Object<string, string>} [options.additional_database_urls] - Optional additional DBs, keyed by custom name with URL as value
|
|
15
16
|
* @param {string} [options.appName] - Application name (from MetricsClient)
|
|
16
17
|
* @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
|
|
17
18
|
* @param {string} [options.processType] - Process type (from MetricsClient)
|
|
@@ -26,7 +27,8 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
26
27
|
*/
|
|
27
28
|
constructor({
|
|
28
29
|
databaseUrl,
|
|
29
|
-
|
|
30
|
+
databaseName,
|
|
31
|
+
additional_database_urls = {},
|
|
30
32
|
...metricsConfig
|
|
31
33
|
} = {}) {
|
|
32
34
|
const intervalSec =
|
|
@@ -34,6 +36,10 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
34
36
|
parseInt(process.env.METRICS_DATABASE_INTERVAL_SEC || '', 10) ||
|
|
35
37
|
60
|
|
36
38
|
|
|
39
|
+
const tmpAppName =
|
|
40
|
+
metricsConfig.appName || process.env.BUILD_APP_NAME || 'unknown-app'
|
|
41
|
+
const mainDbName = databaseName || `${tmpAppName}_db`
|
|
42
|
+
|
|
37
43
|
const startupValidation = async () => {
|
|
38
44
|
if (!databaseUrl) {
|
|
39
45
|
console.error(`[database-metrics] ❌ METRICS_DATABASE_URL is required`)
|
|
@@ -44,7 +50,7 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
44
50
|
const mainPool = new Pool({ connectionString: databaseUrl })
|
|
45
51
|
await mainPool.query('SELECT 1')
|
|
46
52
|
await mainPool.end()
|
|
47
|
-
console.info(`[database-metrics] ✓ Main database OK`)
|
|
53
|
+
console.info(`[database-metrics] ✓ Main database OK: ${mainDbName}`)
|
|
48
54
|
} catch (err) {
|
|
49
55
|
console.error(
|
|
50
56
|
`[database-metrics] ❌ Cannot connect to main database: ${err.message}`
|
|
@@ -52,15 +58,15 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
52
58
|
return false
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
for (const url of additional_database_urls) {
|
|
61
|
+
for (const [dbKey, url] of Object.entries(additional_database_urls)) {
|
|
56
62
|
try {
|
|
57
63
|
const p = new Pool({ connectionString: url })
|
|
58
64
|
await p.query('SELECT 1')
|
|
59
65
|
await p.end()
|
|
60
|
-
console.info(`[database-metrics] ✓ Additional database OK: ${
|
|
66
|
+
console.info(`[database-metrics] ✓ Additional database OK: ${dbKey}`)
|
|
61
67
|
} catch (err) {
|
|
62
68
|
console.error(
|
|
63
|
-
`[database-metrics] ⚠ Skipping additional database: ${
|
|
69
|
+
`[database-metrics] ⚠ Skipping additional database: ${dbKey}`
|
|
64
70
|
)
|
|
65
71
|
console.error(`[database-metrics] ${err.message}`)
|
|
66
72
|
}
|
|
@@ -81,23 +87,34 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
81
87
|
this.databasePools = []
|
|
82
88
|
|
|
83
89
|
if (databaseUrl) {
|
|
84
|
-
this.
|
|
90
|
+
this._addPool(databaseUrl, mainDbName)
|
|
85
91
|
}
|
|
86
92
|
|
|
87
|
-
for (const url of additional_database_urls) {
|
|
88
|
-
this.
|
|
93
|
+
for (const [dbKey, url] of Object.entries(additional_database_urls)) {
|
|
94
|
+
this._addPool(url, dbKey)
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
/** Gauge for Database connections */
|
|
92
98
|
this.databaseConnectionsGauge = this.createGauge({
|
|
93
99
|
name: 'app_database_connections',
|
|
94
100
|
help: 'Postgres database connections',
|
|
95
|
-
labelNames: this.withDefaultLabels([
|
|
101
|
+
labelNames: this.withDefaultLabels([
|
|
102
|
+
'max_connections',
|
|
103
|
+
'database_name',
|
|
104
|
+
'db_key',
|
|
105
|
+
]),
|
|
96
106
|
})
|
|
97
107
|
|
|
98
108
|
this._setCleanupHandlers()
|
|
99
109
|
}
|
|
100
110
|
|
|
111
|
+
_addPool = (url, dbKey) => {
|
|
112
|
+
const pool = new Pool({ connectionString: url })
|
|
113
|
+
pool.dbKey = dbKey
|
|
114
|
+
this.databasePools.push(pool)
|
|
115
|
+
return pool
|
|
116
|
+
}
|
|
117
|
+
|
|
101
118
|
/**
|
|
102
119
|
* @param {Pool} pool - PG connection pool
|
|
103
120
|
* @returns {Promise<{ current: number, max: number, dbName: string }>}
|
|
@@ -144,8 +161,9 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
144
161
|
this.databaseConnectionsGauge.set(
|
|
145
162
|
{
|
|
146
163
|
...this.getDefaultLabels(),
|
|
147
|
-
database_name:
|
|
164
|
+
database_name: pool.dbKey,
|
|
148
165
|
max_connections: String(max),
|
|
166
|
+
db_key: dbName,
|
|
149
167
|
},
|
|
150
168
|
current
|
|
151
169
|
)
|
|
@@ -86,8 +86,8 @@ class RedisMetricsClient extends MetricsClient {
|
|
|
86
86
|
})
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
// node-redis v4
|
|
90
|
-
if (this.redisClientType === REDIS_V4
|
|
89
|
+
// node-redis v4
|
|
90
|
+
if (this.redisClientType === REDIS_V4) {
|
|
91
91
|
try {
|
|
92
92
|
return this.redisClient.sendCommand(['CLIENT', 'LIST'])
|
|
93
93
|
} catch (err) {
|
|
@@ -95,6 +95,15 @@ class RedisMetricsClient extends MetricsClient {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
+
if (this.redisClientType === IOREDIS) {
|
|
99
|
+
try {
|
|
100
|
+
return this.redisClient.client('LIST')
|
|
101
|
+
} catch (err) {
|
|
102
|
+
throw new Error(`Failed to get CLIENT LIST: ${err.message}`)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
|
|
98
107
|
throw new Error('Unsupported Redis client type')
|
|
99
108
|
}
|
|
100
109
|
|