@adalo/metrics 0.1.128 → 0.1.130
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/metrics/baseMetricsClient.d.ts +5 -0
- package/lib/metrics/baseMetricsClient.d.ts.map +1 -1
- package/lib/metrics/baseMetricsClient.js +24 -2
- package/lib/metrics/baseMetricsClient.js.map +1 -1
- package/lib/metrics/metricsClient.d.ts.map +1 -1
- package/lib/metrics/metricsClient.js +1 -0
- package/lib/metrics/metricsClient.js.map +1 -1
- package/lib/metrics/metricsDatabaseClient.d.ts +2 -0
- package/lib/metrics/metricsDatabaseClient.d.ts.map +1 -1
- package/lib/metrics/metricsDatabaseClient.js +1 -0
- package/lib/metrics/metricsDatabaseClient.js.map +1 -1
- package/lib/metrics/metricsQueueRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsQueueRedisClient.js +1 -0
- package/lib/metrics/metricsQueueRedisClient.js.map +1 -1
- package/lib/metrics/metricsRedisClient.d.ts +2 -0
- package/lib/metrics/metricsRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsRedisClient.js +1 -0
- package/lib/metrics/metricsRedisClient.js.map +1 -1
- package/package.json +1 -1
- package/src/metrics/baseMetricsClient.js +28 -2
- package/src/metrics/metricsClient.js +1 -0
- package/src/metrics/metricsDatabaseClient.js +1 -0
- package/src/metrics/metricsQueueRedisClient.js +1 -0
- package/src/metrics/metricsRedisClient.js +1 -0
|
@@ -15,6 +15,7 @@ export class BaseMetricsClient {
|
|
|
15
15
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
16
16
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
17
17
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
18
|
+
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
18
19
|
*/
|
|
19
20
|
constructor(config?: {
|
|
20
21
|
appName?: string | undefined;
|
|
@@ -27,6 +28,7 @@ export class BaseMetricsClient {
|
|
|
27
28
|
intervalSec?: number | undefined;
|
|
28
29
|
removeOldMetrics?: boolean | undefined;
|
|
29
30
|
startupValidation?: Function | undefined;
|
|
31
|
+
disablePushgateway?: boolean | undefined;
|
|
30
32
|
});
|
|
31
33
|
appName: string;
|
|
32
34
|
dynoId: string;
|
|
@@ -37,6 +39,7 @@ export class BaseMetricsClient {
|
|
|
37
39
|
authToken: string;
|
|
38
40
|
intervalSec: number;
|
|
39
41
|
startupValidation: Function | undefined;
|
|
42
|
+
disablePushgateway: boolean;
|
|
40
43
|
prefixLogs: string;
|
|
41
44
|
_registry: client.Registry<"text/plain; version=0.0.4; charset=utf-8">;
|
|
42
45
|
defaultLabels: {
|
|
@@ -167,6 +170,8 @@ export class BaseMetricsClient {
|
|
|
167
170
|
get metricsEnabled(): boolean;
|
|
168
171
|
get metricsLogValues(): boolean;
|
|
169
172
|
get registry(): client.Registry<"text/plain; version=0.0.4; charset=utf-8">;
|
|
173
|
+
getMetricsAsString(): Promise<string>;
|
|
174
|
+
metricsMiddleware(): (req: any, res: any) => Promise<void>;
|
|
170
175
|
}
|
|
171
176
|
import client = require("prom-client");
|
|
172
177
|
//# sourceMappingURL=baseMetricsClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseMetricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/baseMetricsClient.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"baseMetricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/baseMetricsClient.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH;IACE;;;;;;;;;;;;;OAaG;IACH;QAZ2B,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QACf,iBAAiB;QAClB,kBAAkB;OAqD7C;IAlDC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,iBAAuE;IACvE,mBAC+D;IAC/D,uBACoE;IACpE,kBAC0E;IAC1E,oBAGI;IACJ,wCAAiD;IACjD,4BAEoD;IAEpD,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;IAMzB;;;;;;;;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;;OAEG;IACH,6BAKC;IAED;;OAEG;IACH,kCAiCC;IAED,sEAuBC;IAED,iCAEC;IAED;;;;;;;;;OASG;IACH,iFAEC;IAED;;;OAGG;IACH,eAFa,QAAQ,IAAI,CAAC,CAOzB;IAED;;;;;;;;;OASG;IACH,yBA0FC;IAED;;;;;;;;;OASG;IACH;;;;;;sBAFa,QAAQ,IAAI,CAAC,CAUzB;IAED;;;;;;;OAOG;IACH;;;sBAFa,QAAQ,IAAI,CAAC,CAezB;IAED;;;;;;OAMG;IACH,6BAHW,MAAM,EAAE,KACN,MAAM,EAAE,CAIpB;IAED;;;;MAEC;IAED,gCAGC;IAID,8BAEC;IAED,gCAEC;IAED,4EAEC;IAED,sCAEC;IAED,2DAWC;CACF"}
|
|
@@ -20,6 +20,7 @@ class BaseMetricsClient {
|
|
|
20
20
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
21
21
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
22
22
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
23
|
+
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
23
24
|
*/
|
|
24
25
|
constructor(config = {}) {
|
|
25
26
|
this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app';
|
|
@@ -31,6 +32,7 @@ class BaseMetricsClient {
|
|
|
31
32
|
this.authToken = config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || '';
|
|
32
33
|
this.intervalSec = config.intervalSec || parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) || 15;
|
|
33
34
|
this.startupValidation = config.startupValidation;
|
|
35
|
+
this.disablePushgateway = config.disablePushgateway ?? process.env.METRICS_DISABLE_PUSHGATEWAY === 'true';
|
|
34
36
|
this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`;
|
|
35
37
|
this._registry = new client.Registry();
|
|
36
38
|
client.collectDefaultMetrics({
|
|
@@ -143,7 +145,7 @@ class BaseMetricsClient {
|
|
|
143
145
|
for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {
|
|
144
146
|
try {
|
|
145
147
|
if (!updateFn) {
|
|
146
|
-
|
|
148
|
+
continue;
|
|
147
149
|
}
|
|
148
150
|
const result = updateFn();
|
|
149
151
|
const val = result instanceof Promise ? await result : result;
|
|
@@ -152,7 +154,9 @@ class BaseMetricsClient {
|
|
|
152
154
|
console.error(`${this.prefixLogs} Failed to update gauge ${name}:`, err);
|
|
153
155
|
}
|
|
154
156
|
}
|
|
155
|
-
|
|
157
|
+
if (!this.disablePushgateway) {
|
|
158
|
+
await this.gatewayPush();
|
|
159
|
+
}
|
|
156
160
|
// this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)
|
|
157
161
|
|
|
158
162
|
if (this.logValues) {
|
|
@@ -310,6 +314,9 @@ class BaseMetricsClient {
|
|
|
310
314
|
* @returns {Promise<void>}
|
|
311
315
|
*/
|
|
312
316
|
gatewayPush = async (params = {}) => {
|
|
317
|
+
if (this.disablePushgateway) {
|
|
318
|
+
return Promise.resolve();
|
|
319
|
+
}
|
|
313
320
|
const groupings = {
|
|
314
321
|
process_type: this.processType,
|
|
315
322
|
instance: this.dynoId,
|
|
@@ -350,6 +357,21 @@ class BaseMetricsClient {
|
|
|
350
357
|
get registry() {
|
|
351
358
|
return this._registry;
|
|
352
359
|
}
|
|
360
|
+
async getMetricsAsString() {
|
|
361
|
+
return this._registry.metrics();
|
|
362
|
+
}
|
|
363
|
+
metricsMiddleware() {
|
|
364
|
+
return async (req, res) => {
|
|
365
|
+
try {
|
|
366
|
+
const metrics = await this.getMetricsAsString();
|
|
367
|
+
res.set('Content-Type', client.register.contentType);
|
|
368
|
+
res.end(metrics);
|
|
369
|
+
} catch (err) {
|
|
370
|
+
console.error(`${this.prefixLogs} Failed to get metrics:`, err);
|
|
371
|
+
res.status(500).end('Failed to collect metrics');
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
353
375
|
}
|
|
354
376
|
module.exports = {
|
|
355
377
|
BaseMetricsClient
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseMetricsClient.js","names":["client","require","https","BaseMetricsClient","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","_clearOldWorkers","removeOldMetrics","_setCleanupHandlers","createGauge","name","help","updateFn","labelNames","Object","keys","g","Gauge","registers","createCounter","c","Counter","data","value","inc","clearAllCounters","metricsLogValues","console","log","values","forEach","counter","reset","_pushMetrics","entries","result","val","Promise","undefined","set","err","error","gatewayPush","metrics","getMetricsAsJSON","JSON","stringify","_startPush","interval","customPushMetics","warn","setInterval","pushMetrics","catch","startPush","cleanup","gatewayDelete","exit","url","res","fetch","Accept","ok","status","text","metricRegex","labelRegex","uniqueLabelSets","Set","match","exec","rawLabels","lr","labels","job","add","size","oldLabelSets","map","s","parse","filter","instance","length","jobName","groupings","params","delete","push","withDefaultLabels","getDefaultLabels","on","metricsEnabled","registry","module","exports"],"sources":["../../src/metrics/baseMetricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst https = require('https')\n\n/**\n * BaseMetricsClient provides common functionality for all metrics clients.\n * Handles registry setup, pushgateway, default labels, and common operations.\n */\nclass BaseMetricsClient {\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 {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\n this._clearOldWorkers(config.removeOldMetrics)\n this._setCleanupHandlers()\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 * Clear all collected counters\n */\n clearAllCounters = () => {\n if (this.metricsLogValues) {\n console.log('Counters to clear: ', Object.keys(this.counters))\n }\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 // this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)\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 pushMetrics = async () => {\n return this._pushMetrics()\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 metricRegex = /([a-zA-Z_:][a-zA-Z0-9_:]*)\\{([^}]*)\\}/gm\n const labelRegex = /(\\w+)=\"([^\"]*)\"/g\n\n const uniqueLabelSets = new Set()\n\n let match\n // eslint-disable-next-line no-cond-assign\n while ((match = metricRegex.exec(text)) !== null) {\n const rawLabels = match[2]\n let lr\n const labels = {}\n\n // eslint-disable-next-line no-cond-assign\n while ((lr = labelRegex.exec(rawLabels)) !== null) {\n // eslint-disable-next-line prefer-destructuring\n labels[lr[1]] = lr[2]\n }\n\n if (\n labels.job === this.appName &&\n labels.process_type === this.processType\n ) {\n uniqueLabelSets.add(JSON.stringify(labels))\n }\n }\n\n if (uniqueLabelSets.size === 0) {\n console.log(\n `${this.prefixLogs} No metrics found for job ${this.appName}`\n )\n return\n }\n\n const oldLabelSets = [...uniqueLabelSets]\n .map(s => JSON.parse(s))\n .filter(\n labels =>\n labels.instance &&\n labels.instance !== this.dynoId &&\n labels.process_type === this.processType\n )\n\n if (oldLabelSets.length === 0) {\n console.log(`${this.prefixLogs} No old dynos to delete.`)\n return\n }\n\n for (const labels of oldLabelSets) {\n try {\n await this.gatewayDelete({ jobName: this.appName, groupings: labels })\n console.log(\n `${this.prefixLogs} Deleted metrics for dyno: ${\n labels.instance\n }, labels: ${Object.keys(labels)} `\n )\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to delete metrics for ${labels.instance}:`,\n err\n )\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: params.groupings || {\n process_type: this.processType,\n 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 = { BaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"baseMetricsClient.js","names":["client","require","https","BaseMetricsClient","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","disablePushgateway","METRICS_DISABLE_PUSHGATEWAY","prefixLogs","_registry","Registry","collectDefaultMetrics","register","defaultLabels","app","dyno_id","process_type","gateway","Pushgateway","headers","Authorization","agent","Agent","keepAlive","gauges","counters","countersFunctions","gaugeUpdaters","_clearOldWorkers","removeOldMetrics","_setCleanupHandlers","createGauge","name","help","updateFn","labelNames","Object","keys","g","Gauge","registers","createCounter","c","Counter","data","value","inc","clearAllCounters","metricsLogValues","console","log","values","forEach","counter","reset","_pushMetrics","entries","result","val","Promise","undefined","set","err","error","gatewayPush","metrics","getMetricsAsJSON","JSON","stringify","_startPush","interval","customPushMetics","warn","setInterval","pushMetrics","catch","startPush","cleanup","gatewayDelete","exit","url","res","fetch","Accept","ok","status","text","metricRegex","labelRegex","uniqueLabelSets","Set","match","exec","rawLabels","lr","labels","job","add","size","oldLabelSets","map","s","parse","filter","instance","length","jobName","groupings","params","delete","resolve","push","withDefaultLabels","getDefaultLabels","on","metricsEnabled","registry","getMetricsAsString","metricsMiddleware","req","contentType","end","module","exports"],"sources":["../../src/metrics/baseMetricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst https = require('https')\n\n/**\n * BaseMetricsClient provides common functionality for all metrics clients.\n * Handles registry setup, pushgateway, default labels, and common operations.\n */\nclass BaseMetricsClient {\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 {function} [config.startupValidation] Add to validate on start push.\n * @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)\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 this.disablePushgateway =\n config.disablePushgateway ??\n process.env.METRICS_DISABLE_PUSHGATEWAY === 'true'\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\n this._clearOldWorkers(config.removeOldMetrics)\n this._setCleanupHandlers()\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 * Clear all collected counters\n */\n clearAllCounters = () => {\n if (this.metricsLogValues) {\n console.log('Counters to clear: ', Object.keys(this.counters))\n }\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 continue\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 if (!this.disablePushgateway) {\n await this.gatewayPush()\n }\n // this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)\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 pushMetrics = async () => {\n return this._pushMetrics()\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 metricRegex = /([a-zA-Z_:][a-zA-Z0-9_:]*)\\{([^}]*)\\}/gm\n const labelRegex = /(\\w+)=\"([^\"]*)\"/g\n\n const uniqueLabelSets = new Set()\n\n let match\n // eslint-disable-next-line no-cond-assign\n while ((match = metricRegex.exec(text)) !== null) {\n const rawLabels = match[2]\n let lr\n const labels = {}\n\n // eslint-disable-next-line no-cond-assign\n while ((lr = labelRegex.exec(rawLabels)) !== null) {\n // eslint-disable-next-line prefer-destructuring\n labels[lr[1]] = lr[2]\n }\n\n if (\n labels.job === this.appName &&\n labels.process_type === this.processType\n ) {\n uniqueLabelSets.add(JSON.stringify(labels))\n }\n }\n\n if (uniqueLabelSets.size === 0) {\n console.log(\n `${this.prefixLogs} No metrics found for job ${this.appName}`\n )\n return\n }\n\n const oldLabelSets = [...uniqueLabelSets]\n .map(s => JSON.parse(s))\n .filter(\n labels =>\n labels.instance &&\n labels.instance !== this.dynoId &&\n labels.process_type === this.processType\n )\n\n if (oldLabelSets.length === 0) {\n console.log(`${this.prefixLogs} No old dynos to delete.`)\n return\n }\n\n for (const labels of oldLabelSets) {\n try {\n await this.gatewayDelete({ jobName: this.appName, groupings: labels })\n console.log(\n `${this.prefixLogs} Deleted metrics for dyno: ${\n labels.instance\n }, labels: ${Object.keys(labels)} `\n )\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to delete metrics for ${labels.instance}:`,\n err\n )\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: params.groupings || {\n process_type: this.processType,\n 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 if (this.disablePushgateway) {\n return Promise.resolve()\n }\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 async getMetricsAsString() {\n return this._registry.metrics()\n }\n\n metricsMiddleware() {\n return async (req, res) => {\n try {\n const metrics = await this.getMetricsAsString()\n res.set('Content-Type', client.register.contentType)\n res.end(metrics)\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to get metrics:`, err)\n res.status(500).end('Failed to collect metrics')\n }\n }\n }\n}\n\nmodule.exports = { BaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsClient.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;
|
|
1
|
+
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsClient.js"],"names":[],"mappings":"AAIA;;;;GAIG;AACH;IAkBI,yBAAyB;IACzB,uBAAgC;IAKlC;;;OAGG;IACH,4BA4DC;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;;;;;;;;;;OAUG;IACH;QAP0B,MAAM,EAArB,MAAM;QACS,KAAK,EAApB,MAAM;QACS,WAAW,EAA1B,MAAM;QACU,KAAK;QACL,UAAU;QACX,QAAQ,EAAvB,MAAM;aA2BhB;IAED;;;OAGG;IACH,oEA+BC;CACF"}
|
|
@@ -24,6 +24,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
24
24
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
25
25
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
26
26
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
27
|
+
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
27
28
|
*/
|
|
28
29
|
constructor(config = {}) {
|
|
29
30
|
super(config);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.js","names":["fs","require","os","BaseMetricsClient","MetricsClient","constructor","config","_lastUsageMicros","_lastCheckTime","Date","now","_initDefaultMetrics","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","process","uptime","createCounter","labelNames","withDefaultLabels","stat","readFileSync","match","currentUsage","parseInt","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","cpus","length","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","trackHttpRequest","method","route","status_code","appId","databaseId","duration","countersFunctions","app_requests_total","app_requests_total_duration","trackHttpRequestMiddleware","req","res","next","enabled","on","params","body","query","datasourceId","statusCode","module","exports"],"sources":["../../src/metrics/metricsClient.js"],"sourcesContent":["const fs = require('fs')\nconst os = require('os')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n * Supports gauges, counters, default metrics, and custom metrics.\n * Extends BaseMetricsClient for common functionality.\n */\nclass MetricsClient extends BaseMetricsClient {\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 {function} [config.startupValidation] Add to validate on start push.\n */\n constructor(config = {}) {\n super(config)\n\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._initDefaultMetrics()\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_requests_total',\n help: 'How long the process has been running',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'appId',\n 'databaseId',\n 'status_code',\n ]),\n })\n\n this.createCounter({\n name: 'app_requests_total_duration',\n help: 'How long the process has been running',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'appId',\n 'databaseId',\n 'status_code',\n ]),\n })\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 * Increment the HTTP requests counter with detailed request information.\n *\n * @param {Object} params - The parameters for the request counter.\n * @param {string} params.method - HTTP method (GET, POST, etc.).\n * @param {string} params.route - The full requested URL or route.\n * @param {number} params.status_code - HTTP response status code.\n * @param {string} [params.appId=''] - Optional application identifier.\n * @param {string} [params.databaseId=''] - Optional database identifier.\n * @param {number} params.duration - Request duration in milliseconds.\n */\n trackHttpRequest({\n method,\n route,\n status_code,\n appId = '',\n databaseId = '',\n duration,\n }) {\n this.countersFunctions?.app_requests_total({\n method,\n route,\n status_code,\n appId,\n databaseId,\n })\n this.countersFunctions?.app_requests_total_duration(\n {\n method,\n route,\n status_code,\n appId,\n databaseId,\n },\n duration\n )\n }\n\n /**\n * Express middleware to track HTTP requests.\n * Track the `app_requests_total` and `app_requests_total_duration` metric.\n */\n trackHttpRequestMiddleware = (req, res, next) => {\n if (!this.enabled || req.method === 'OPTIONS') {\n next()\n return\n }\n\n const start = Date.now()\n res.on('finish', () => {\n const route = req.route?.path || req.path || '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\n this.trackHttpRequest({\n method: req.method,\n route,\n status_code: res.statusCode,\n appId,\n databaseId,\n duration: Date.now() - start,\n })\n })\n\n next()\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsClient.js","names":["fs","require","os","BaseMetricsClient","MetricsClient","constructor","config","_lastUsageMicros","_lastCheckTime","Date","now","_initDefaultMetrics","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","process","uptime","createCounter","labelNames","withDefaultLabels","stat","readFileSync","match","currentUsage","parseInt","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","cpus","length","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","trackHttpRequest","method","route","status_code","appId","databaseId","duration","countersFunctions","app_requests_total","app_requests_total_duration","trackHttpRequestMiddleware","req","res","next","enabled","on","params","body","query","datasourceId","statusCode","module","exports"],"sources":["../../src/metrics/metricsClient.js"],"sourcesContent":["const fs = require('fs')\nconst os = require('os')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n * Supports gauges, counters, default metrics, and custom metrics.\n * Extends BaseMetricsClient for common functionality.\n */\nclass MetricsClient extends BaseMetricsClient {\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 {function} [config.startupValidation] Add to validate on start push.\n * @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)\n */\n constructor(config = {}) {\n super(config)\n\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._initDefaultMetrics()\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_requests_total',\n help: 'How long the process has been running',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'appId',\n 'databaseId',\n 'status_code',\n ]),\n })\n\n this.createCounter({\n name: 'app_requests_total_duration',\n help: 'How long the process has been running',\n labelNames: this.withDefaultLabels([\n 'method',\n 'route',\n 'appId',\n 'databaseId',\n 'status_code',\n ]),\n })\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 * Increment the HTTP requests counter with detailed request information.\n *\n * @param {Object} params - The parameters for the request counter.\n * @param {string} params.method - HTTP method (GET, POST, etc.).\n * @param {string} params.route - The full requested URL or route.\n * @param {number} params.status_code - HTTP response status code.\n * @param {string} [params.appId=''] - Optional application identifier.\n * @param {string} [params.databaseId=''] - Optional database identifier.\n * @param {number} params.duration - Request duration in milliseconds.\n */\n trackHttpRequest({\n method,\n route,\n status_code,\n appId = '',\n databaseId = '',\n duration,\n }) {\n this.countersFunctions?.app_requests_total({\n method,\n route,\n status_code,\n appId,\n databaseId,\n })\n this.countersFunctions?.app_requests_total_duration(\n {\n method,\n route,\n status_code,\n appId,\n databaseId,\n },\n duration\n )\n }\n\n /**\n * Express middleware to track HTTP requests.\n * Track the `app_requests_total` and `app_requests_total_duration` metric.\n */\n trackHttpRequestMiddleware = (req, res, next) => {\n if (!this.enabled || req.method === 'OPTIONS') {\n next()\n return\n }\n\n const start = Date.now()\n res.on('finish', () => {\n const route = req.route?.path || req.path || '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\n this.trackHttpRequest({\n method: req.method,\n route,\n status_code: res.statusCode,\n appId,\n databaseId,\n duration: Date.now() - start,\n })\n })\n\n next()\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -20,6 +20,7 @@ export class DatabaseMetricsClient extends BaseMetricsClient {
|
|
|
20
20
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics
|
|
21
21
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service
|
|
22
22
|
* @param {function} [options.startupValidation] - Function to validate startup
|
|
23
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
23
24
|
*/
|
|
24
25
|
constructor({ databaseUrl, databaseName, additional_database_urls, ...metricsConfig }?: {
|
|
25
26
|
databaseUrl: string;
|
|
@@ -37,6 +38,7 @@ export class DatabaseMetricsClient extends BaseMetricsClient {
|
|
|
37
38
|
intervalSec?: number | undefined;
|
|
38
39
|
removeOldMetrics?: boolean | undefined;
|
|
39
40
|
startupValidation?: Function | undefined;
|
|
41
|
+
disablePushgateway?: boolean | undefined;
|
|
40
42
|
});
|
|
41
43
|
databasePools: any[];
|
|
42
44
|
/** Gauge for Database connections */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsDatabaseClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsDatabaseClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"metricsDatabaseClient.d.ts","sourceRoot":"","sources":["../../src/metrics/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;QACf,iBAAiB;QAClB,kBAAkB;OAkF9C;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,CAqBzB;IAED;;;OAGG;IACH,sDAMC;CAwBF"}
|
|
@@ -29,6 +29,7 @@ class DatabaseMetricsClient extends BaseMetricsClient {
|
|
|
29
29
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics
|
|
30
30
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service
|
|
31
31
|
* @param {function} [options.startupValidation] - Function to validate startup
|
|
32
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
32
33
|
*/
|
|
33
34
|
constructor({
|
|
34
35
|
databaseUrl,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsDatabaseClient.js","names":["Pool","require","BaseMetricsClient","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","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","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","exit","on","module","exports"],"sources":["../../src/metrics/metricsDatabaseClient.js"],"sourcesContent":["const { Pool } = require('pg')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\n\n/**\n * DatabaseMetricsClient collects Postgres connection metrics\n * and pushes them to Prometheus Pushgateway.\n *\n * @extends BaseMetricsClient\n */\nclass DatabaseMetricsClient extends BaseMetricsClient {\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 BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service\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 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 this.clearAllCounters()\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","BaseMetricsClient","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","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","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","exit","on","module","exports"],"sources":["../../src/metrics/metricsDatabaseClient.js"],"sourcesContent":["const { Pool } = require('pg')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\n\n/**\n * DatabaseMetricsClient collects Postgres connection metrics\n * and pushes them to Prometheus Pushgateway.\n *\n * @extends BaseMetricsClient\n */\nclass DatabaseMetricsClient extends BaseMetricsClient {\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 BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service\n * @param {function} [options.startupValidation] - Function to validate startup\n * @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)\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 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 this.clearAllCounters()\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":"metricsQueueRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsQueueRedisClient.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH;
|
|
1
|
+
{"version":3,"file":"metricsQueueRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsQueueRedisClient.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH;IAgEI,wCAAsD;IACtD,iCAA0C;IAE1C,4DAA4D;IAC5D,0BAA2B;IAE3B,qCAAqC;IACrC,oDAIE;IAKJ;;;;;;;;OAQG;IACH,kCAFa,MAAM,GAAC,GAAG,CAStB;IAED;;;;OAIG;IACH,uCAHW,MAAM,KACJ,QAAQ,IAAI,CAAC,CAkDzB;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAuCzB;CAoCF"}
|
|
@@ -28,6 +28,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
28
28
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
29
29
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
30
30
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
31
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
31
32
|
*/
|
|
32
33
|
constructor({
|
|
33
34
|
redisClient,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsQueueRedisClient.js","names":["Queue","require","RedisMetricsClient","IOREDIS","QueueRedisMetricsClient","constructor","redisClient","metricsConfig","getConfiguredQueueNames","process","env","METRICS_APP_REDIS_BQ","Error","allQueues","split","map","q","trim","filter","Boolean","length","Set","startupValidation","queueNames","console","info","error","message","queueCache","Map","queueJobsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","getConfigForDifferentRedis","redisClientType","host","port","db","password","options","collectSingleQueueMetrics","queueName","has","set","redis","isWorker","getEvents","sendEvents","queue","get","health","checkHealth","labels","getDefaultLabels","queue_name","status","waiting","active","succeeded","failed","delayed","warn","collectQueueMetrics","collectRedisMetrics","Promise","allSettled","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","intervalSec","_startPush","catch","err","on","cleanup","close","exit","module","exports"],"sources":["../../src/metrics/metricsQueueRedisClient.js"],"sourcesContent":["const Queue = require('bee-queue')\nconst { RedisMetricsClient } = require('./metricsRedisClient')\nconst { IOREDIS } = require('../redisUtils')\n\n/**\n * QueueRedisMetricsClient extends RedisMetricsClient to collect\n * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends RedisMetricsClient\n */\nclass QueueRedisMetricsClient extends RedisMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\n */\n constructor({ redisClient, metricsConfig = {} } = {}) {\n const getConfiguredQueueNames = () => {\n if (!process.env.METRICS_APP_REDIS_BQ) {\n throw new Error(\n 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'\n )\n }\n\n const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')\n .map(q => q.trim())\n .filter(Boolean)\n\n if (allQueues.length === 0) {\n throw new Error(\n 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +\n 'Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"'\n )\n }\n\n return [...new Set(allQueues)]\n }\n\n const startupValidation = () => {\n try {\n const queueNames = getConfiguredQueueNames()\n console.info(\n `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`\n )\n return true\n } catch (error) {\n console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)\n console.error(\n `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n console.error(\n `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC=\"10\"`\n )\n console.error(`[queue-metrics] Skipping queue metrics collection`)\n return false\n }\n }\n\n super({\n ...metricsConfig,\n redisClient,\n startupValidation,\n })\n\n this.getConfiguredQueueNames = getConfiguredQueueNames\n this.startupValidation = startupValidation\n\n /** Cache for queue objects to avoid multiple connections */\n this.queueCache = new Map()\n\n /** Gauge for queue jobs by status */\n this.queueJobsGauge = this.createGauge({\n name: 'app_queue_jobs_count',\n help: 'Number of app jobs in the queue by status',\n labelNames: this.withDefaultLabels(['queue_name', 'status']),\n })\n\n this._setCleanupHandlers()\n }\n\n /**\n * Get the correct Redis configuration for a queue depending on the client type\n *\n * For ioredis, returns { host, port, db, password } because BeeQueue\n * cannot accept the full client instance.\n * For other Redis clients (v3/v4), returns the client instance directly.\n *\n * @returns {object|any} Redis config object for BeeQueue or Redis client instance\n */\n getConfigForDifferentRedis = () => {\n if (this.redisClientType === IOREDIS) {\n const { host, port, db, password } = this.redisClient.options\n return { host, port, db, password }\n }\n\n return this.redisClient\n }\n\n /**\n * Collect metrics for a single Bee Queue and set gauges\n * @param {string} queueName - Name of the queue\n * @returns {Promise<void>}\n */\n collectSingleQueueMetrics = async queueName => {\n try {\n if (!this.queueCache.has(queueName)) {\n this.queueCache.set(\n queueName,\n new Queue(queueName, {\n redis: this.getConfigForDifferentRedis(),\n isWorker: false,\n getEvents: false,\n sendEvents: false,\n })\n )\n }\n\n const queue = this.queueCache.get(queueName)\n const health = await queue.checkHealth()\n\n const labels = {\n ...this.getDefaultLabels(),\n queue_name: queueName,\n }\n\n this.queueJobsGauge.set(\n { ...labels, status: 'waiting' },\n health.waiting || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'active' },\n health.active || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'succeeded' },\n health.succeeded || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'failed' },\n health.failed || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'delayed' },\n health.delayed || 0\n )\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all queues and Redis, then push to Pushgateway\n * @returns {Promise<void>}\n */\n collectQueueMetrics = async () => {\n try {\n const queueNames = this.getConfiguredQueueNames()\n\n await this.collectRedisMetrics()\n await Promise.allSettled(\n queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))\n )\n\n await this.gatewayPush()\n this.clearAllCounters()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n if (\n error.message?.includes('No queues configured') ||\n error.message?.includes('METRICS_APP_REDIS_BQ')\n ) {\n console.error(\n `[queue-metrics] ❌ Configuration error: ${error.message}`\n )\n console.error(\n `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n } else {\n console.error(\n `[queue-metrics] Failed to collect queue metrics: ${error.message}`\n )\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.collectQueueMetrics().catch(err => {\n console.error(\n `[queue-metrics] Failed to collect queue & Redis metrics:`,\n err\n )\n })\n })\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n /**\n * Cleanup queues and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n for (const [queueName, queue] of this.queueCache) {\n try {\n await queue.close()\n } catch (err) {\n console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)\n }\n }\n process.exit(0)\n }\n}\n\nmodule.exports = { QueueRedisMetricsClient }\n"],"mappings":";;AAAA,MAAMA,KAAK,GAAGC,OAAO,CAAC,WAAW,CAAC;AAClC,MAAM;EAAEC;AAAmB,CAAC,GAAGD,OAAO,CAAC,sBAAsB,CAAC;AAC9D,MAAM;EAAEE;AAAQ,CAAC,GAAGF,OAAO,CAAC,eAAe,CAAC;;AAE5C;AACA;AACA;AACA;AACA;AACA;AACA,MAAMG,uBAAuB,SAASF,kBAAkB,CAAC;EACvD;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEG,WAAWA,CAAC;IAAEC,WAAW;IAAEC,aAAa,GAAG,CAAC;EAAE,CAAC,GAAG,CAAC,CAAC,EAAE;IACpD,MAAMC,uBAAuB,GAAGA,CAAA,KAAM;MACpC,IAAI,CAACC,OAAO,CAACC,GAAG,CAACC,oBAAoB,EAAE;QACrC,MAAM,IAAIC,KAAK,CACb,gGACF,CAAC;MACH;MAEA,MAAMC,SAAS,GAAGJ,OAAO,CAACC,GAAG,CAACC,oBAAoB,CAACG,KAAK,CAAC,GAAG,CAAC,CAC1DC,GAAG,CAACC,CAAC,IAAIA,CAAC,CAACC,IAAI,CAAC,CAAC,CAAC,CAClBC,MAAM,CAACC,OAAO,CAAC;MAElB,IAAIN,SAAS,CAACO,MAAM,KAAK,CAAC,EAAE;QAC1B,MAAM,IAAIR,KAAK,CACb,6DAA6D,GAC3D,gEACJ,CAAC;MACH;MAEA,OAAO,CAAC,GAAG,IAAIS,GAAG,CAACR,SAAS,CAAC,CAAC;IAChC,CAAC;IAED,MAAMS,iBAAiB,GAAGA,CAAA,KAAM;MAC9B,IAAI;QACF,MAAMC,UAAU,GAAGf,uBAAuB,CAAC,CAAC;QAC5CgB,OAAO,CAACC,IAAI,CACV,iEAAiEF,UAAU,CAACH,MAAM,SACpF,CAAC;QACD,OAAO,IAAI;MACb,CAAC,CAAC,OAAOM,KAAK,EAAE;QACdF,OAAO,CAACE,KAAK,CAAC,mCAAmCA,KAAK,CAACC,OAAO,EAAE,CAAC;QACjEH,OAAO,CAACE,KAAK,CACX,mFACF,CAAC;QACDF,OAAO,CAACE,KAAK,CACX,8DACF,CAAC;QACDF,OAAO,CAACE,KAAK,CAAC,mDAAmD,CAAC;QAClE,OAAO,KAAK;MACd;IACF,CAAC;IAED,KAAK,CAAC;MACJ,GAAGnB,aAAa;MAChBD,WAAW;MACXgB;IACF,CAAC,CAAC;IAEF,IAAI,CAACd,uBAAuB,GAAGA,uBAAuB;IACtD,IAAI,CAACc,iBAAiB,GAAGA,iBAAiB;;IAE1C;IACA,IAAI,CAACM,UAAU,GAAG,IAAIC,GAAG,CAAC,CAAC;;IAE3B;IACA,IAAI,CAACC,cAAc,GAAG,IAAI,CAACC,WAAW,CAAC;MACrCC,IAAI,EAAE,sBAAsB;MAC5BC,IAAI,EAAE,2CAA2C;MACjDC,UAAU,EAAE,IAAI,CAACC,iBAAiB,CAAC,CAAC,YAAY,EAAE,QAAQ,CAAC;IAC7D,CAAC,CAAC;IAEF,IAAI,CAACC,mBAAmB,CAAC,CAAC;EAC5B;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEC,0BAA0B,GAAGA,CAAA,KAAM;IACjC,IAAI,IAAI,CAACC,eAAe,KAAKnC,OAAO,EAAE;MACpC,MAAM;QAAEoC,IAAI;QAAEC,IAAI;QAAEC,EAAE;QAAEC;MAAS,CAAC,GAAG,IAAI,CAACpC,WAAW,CAACqC,OAAO;MAC7D,OAAO;QAAEJ,IAAI;QAAEC,IAAI;QAAEC,EAAE;QAAEC;MAAS,CAAC;IACrC;IAEA,OAAO,IAAI,CAACpC,WAAW;EACzB,CAAC;;EAED;AACF;AACA;AACA;AACA;EACEsC,yBAAyB,GAAG,MAAMC,SAAS,IAAI;IAC7C,IAAI;MACF,IAAI,CAAC,IAAI,CAACjB,UAAU,CAACkB,GAAG,CAACD,SAAS,CAAC,EAAE;QACnC,IAAI,CAACjB,UAAU,CAACmB,GAAG,CACjBF,SAAS,EACT,IAAI7C,KAAK,CAAC6C,SAAS,EAAE;UACnBG,KAAK,EAAE,IAAI,CAACX,0BAA0B,CAAC,CAAC;UACxCY,QAAQ,EAAE,KAAK;UACfC,SAAS,EAAE,KAAK;UAChBC,UAAU,EAAE;QACd,CAAC,CACH,CAAC;MACH;MAEA,MAAMC,KAAK,GAAG,IAAI,CAACxB,UAAU,CAACyB,GAAG,CAACR,SAAS,CAAC;MAC5C,MAAMS,MAAM,GAAG,MAAMF,KAAK,CAACG,WAAW,CAAC,CAAC;MAExC,MAAMC,MAAM,GAAG;QACb,GAAG,IAAI,CAACC,gBAAgB,CAAC,CAAC;QAC1BC,UAAU,EAAEb;MACd,CAAC;MAED,IAAI,CAACf,cAAc,CAACiB,GAAG,CACrB;QAAE,GAAGS,MAAM;QAAEG,MAAM,EAAE;MAAU,CAAC,EAChCL,MAAM,CAACM,OAAO,IAAI,CACpB,CAAC;MACD,IAAI,CAAC9B,cAAc,CAACiB,GAAG,CACrB;QAAE,GAAGS,MAAM;QAAEG,MAAM,EAAE;MAAS,CAAC,EAC/BL,MAAM,CAACO,MAAM,IAAI,CACnB,CAAC;MACD,IAAI,CAAC/B,cAAc,CAACiB,GAAG,CACrB;QAAE,GAAGS,MAAM;QAAEG,MAAM,EAAE;MAAY,CAAC,EAClCL,MAAM,CAACQ,SAAS,IAAI,CACtB,CAAC;MACD,IAAI,CAAChC,cAAc,CAACiB,GAAG,CACrB;QAAE,GAAGS,MAAM;QAAEG,MAAM,EAAE;MAAS,CAAC,EAC/BL,MAAM,CAACS,MAAM,IAAI,CACnB,CAAC;MACD,IAAI,CAACjC,cAAc,CAACiB,GAAG,CACrB;QAAE,GAAGS,MAAM;QAAEG,MAAM,EAAE;MAAU,CAAC,EAChCL,MAAM,CAACU,OAAO,IAAI,CACpB,CAAC;IACH,CAAC,CAAC,OAAOtC,KAAK,EAAE;MACdF,OAAO,CAACyC,IAAI,CACV,uDAAuDpB,SAAS,GAAG,EACnEnB,KAAK,CAACC,OACR,CAAC;IACH;EACF,CAAC;;EAED;AACF;AACA;AACA;EACEuC,mBAAmB,GAAG,MAAAA,CAAA,KAAY;IAChC,IAAI;MACF,MAAM3C,UAAU,GAAG,IAAI,CAACf,uBAAuB,CAAC,CAAC;MAEjD,MAAM,IAAI,CAAC2D,mBAAmB,CAAC,CAAC;MAChC,MAAMC,OAAO,CAACC,UAAU,CACtB9C,UAAU,CAACR,GAAG,CAAC8B,SAAS,IAAI,IAAI,CAACD,yBAAyB,CAACC,SAAS,CAAC,CACvE,CAAC;MAED,MAAM,IAAI,CAACyB,WAAW,CAAC,CAAC;MACxB,IAAI,CAACC,gBAAgB,CAAC,CAAC;MAEvB,IAAI,IAAI,CAACC,gBAAgB,EAAE;QACzB,MAAMC,aAAa,GAAG,MAAM,IAAI,CAACC,QAAQ,CAACC,gBAAgB,CAAC,CAAC;QAC5DnD,OAAO,CAACC,IAAI,CACV,yCAAyCF,UAAU,CAACH,MAAM,UAAU,EACpEwD,IAAI,CAACC,SAAS,CAACJ,aAAa,EAAE,IAAI,EAAE,CAAC,CACvC,CAAC;MACH;IACF,CAAC,CAAC,OAAO/C,KAAK,EAAE;MACd,IACEA,KAAK,CAACC,OAAO,EAAEmD,QAAQ,CAAC,sBAAsB,CAAC,IAC/CpD,KAAK,CAACC,OAAO,EAAEmD,QAAQ,CAAC,sBAAsB,CAAC,EAC/C;QACAtD,OAAO,CAACE,KAAK,CACX,0CAA0CA,KAAK,CAACC,OAAO,EACzD,CAAC;QACDH,OAAO,CAACE,KAAK,CACX,0FACF,CAAC;MACH,CAAC,MAAM;QACLF,OAAO,CAACE,KAAK,CACX,oDAAoDA,KAAK,CAACC,OAAO,EACnE,CAAC;MACH;MACA,MAAMD,KAAK;IACb;EACF,CAAC;;EAED;AACF;AACA;AACA;EACEqD,SAAS,GAAGA,CAACC,WAAW,GAAG,IAAI,CAACA,WAAW,KAAK;IAC9C,IAAI,CAACC,UAAU,CAACD,WAAW,EAAE,MAAM;MACjC,IAAI,CAACd,mBAAmB,CAAC,CAAC,CAACgB,KAAK,CAACC,GAAG,IAAI;QACtC3D,OAAO,CAACE,KAAK,CACX,0DAA0D,EAC1DyD,GACF,CAAC;MACH,CAAC,CAAC;IACJ,CAAC,CAAC;EACJ,CAAC;EAED/C,mBAAmB,GAAGA,CAAA,KAAM;IAC1B3B,OAAO,CAAC2E,EAAE,CAAC,QAAQ,EAAE,IAAI,CAACC,OAAO,CAAC;IAClC5E,OAAO,CAAC2E,EAAE,CAAC,SAAS,EAAE,IAAI,CAACC,OAAO,CAAC;EACrC,CAAC;;EAED;AACF;AACA;AACA;EACEA,OAAO,GAAG,MAAAA,CAAA,KAAY;IACpB,KAAK,MAAM,CAACxC,SAAS,EAAEO,KAAK,CAAC,IAAI,IAAI,CAACxB,UAAU,EAAE;MAChD,IAAI;QACF,MAAMwB,KAAK,CAACkC,KAAK,CAAC,CAAC;MACrB,CAAC,CAAC,OAAOH,GAAG,EAAE;QACZ3D,OAAO,CAACE,KAAK,CAAC,uCAAuCmB,SAAS,GAAG,EAAEsC,GAAG,CAAC;MACzE;IACF;IACA1E,OAAO,CAAC8E,IAAI,CAAC,CAAC,CAAC;EACjB,CAAC;AACH;AAEAC,MAAM,CAACC,OAAO,GAAG;EAAErF;AAAwB,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsQueueRedisClient.js","names":["Queue","require","RedisMetricsClient","IOREDIS","QueueRedisMetricsClient","constructor","redisClient","metricsConfig","getConfiguredQueueNames","process","env","METRICS_APP_REDIS_BQ","Error","allQueues","split","map","q","trim","filter","Boolean","length","Set","startupValidation","queueNames","console","info","error","message","queueCache","Map","queueJobsGauge","createGauge","name","help","labelNames","withDefaultLabels","_setCleanupHandlers","getConfigForDifferentRedis","redisClientType","host","port","db","password","options","collectSingleQueueMetrics","queueName","has","set","redis","isWorker","getEvents","sendEvents","queue","get","health","checkHealth","labels","getDefaultLabels","queue_name","status","waiting","active","succeeded","failed","delayed","warn","collectQueueMetrics","collectRedisMetrics","Promise","allSettled","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","intervalSec","_startPush","catch","err","on","cleanup","close","exit","module","exports"],"sources":["../../src/metrics/metricsQueueRedisClient.js"],"sourcesContent":["const Queue = require('bee-queue')\nconst { RedisMetricsClient } = require('./metricsRedisClient')\nconst { IOREDIS } = require('../redisUtils')\n\n/**\n * QueueRedisMetricsClient extends RedisMetricsClient to collect\n * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends RedisMetricsClient\n */\nclass QueueRedisMetricsClient extends RedisMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\n * @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)\n */\n constructor({ redisClient, metricsConfig = {} } = {}) {\n const getConfiguredQueueNames = () => {\n if (!process.env.METRICS_APP_REDIS_BQ) {\n throw new Error(\n 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'\n )\n }\n\n const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')\n .map(q => q.trim())\n .filter(Boolean)\n\n if (allQueues.length === 0) {\n throw new Error(\n 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +\n 'Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"'\n )\n }\n\n return [...new Set(allQueues)]\n }\n\n const startupValidation = () => {\n try {\n const queueNames = getConfiguredQueueNames()\n console.info(\n `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`\n )\n return true\n } catch (error) {\n console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)\n console.error(\n `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n console.error(\n `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC=\"10\"`\n )\n console.error(`[queue-metrics] Skipping queue metrics collection`)\n return false\n }\n }\n\n super({\n ...metricsConfig,\n redisClient,\n startupValidation,\n })\n\n this.getConfiguredQueueNames = getConfiguredQueueNames\n this.startupValidation = startupValidation\n\n /** Cache for queue objects to avoid multiple connections */\n this.queueCache = new Map()\n\n /** Gauge for queue jobs by status */\n this.queueJobsGauge = this.createGauge({\n name: 'app_queue_jobs_count',\n help: 'Number of app jobs in the queue by status',\n labelNames: this.withDefaultLabels(['queue_name', 'status']),\n })\n\n this._setCleanupHandlers()\n }\n\n /**\n * Get the correct Redis configuration for a queue depending on the client type\n *\n * For ioredis, returns { host, port, db, password } because BeeQueue\n * cannot accept the full client instance.\n * For other Redis clients (v3/v4), returns the client instance directly.\n *\n * @returns {object|any} Redis config object for BeeQueue or Redis client instance\n */\n getConfigForDifferentRedis = () => {\n if (this.redisClientType === IOREDIS) {\n const { host, port, db, password } = this.redisClient.options\n return { host, port, db, password }\n }\n\n return this.redisClient\n }\n\n /**\n * Collect metrics for a single Bee Queue and set gauges\n * @param {string} queueName - Name of the queue\n * @returns {Promise<void>}\n */\n collectSingleQueueMetrics = async queueName => {\n try {\n if (!this.queueCache.has(queueName)) {\n this.queueCache.set(\n queueName,\n new Queue(queueName, {\n redis: this.getConfigForDifferentRedis(),\n isWorker: false,\n getEvents: false,\n sendEvents: false,\n })\n )\n }\n\n const queue = this.queueCache.get(queueName)\n const health = await queue.checkHealth()\n\n const labels = {\n ...this.getDefaultLabels(),\n queue_name: queueName,\n }\n\n this.queueJobsGauge.set(\n { ...labels, status: 'waiting' },\n health.waiting || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'active' },\n health.active || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'succeeded' },\n health.succeeded || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'failed' },\n health.failed || 0\n )\n this.queueJobsGauge.set(\n { ...labels, status: 'delayed' },\n health.delayed || 0\n )\n } catch (error) {\n console.warn(\n `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all queues and Redis, then push to Pushgateway\n * @returns {Promise<void>}\n */\n collectQueueMetrics = async () => {\n try {\n const queueNames = this.getConfiguredQueueNames()\n\n await this.collectRedisMetrics()\n await Promise.allSettled(\n queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))\n )\n\n await this.gatewayPush()\n this.clearAllCounters()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n if (\n error.message?.includes('No queues configured') ||\n error.message?.includes('METRICS_APP_REDIS_BQ')\n ) {\n console.error(\n `[queue-metrics] ❌ Configuration error: ${error.message}`\n )\n console.error(\n `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ=\"adalo-compile,adalo-migrations\"`\n )\n } else {\n console.error(\n `[queue-metrics] Failed to collect queue metrics: ${error.message}`\n )\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.collectQueueMetrics().catch(err => {\n console.error(\n `[queue-metrics] Failed to collect queue & Redis metrics:`,\n err\n )\n })\n })\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n /**\n * Cleanup queues and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n for (const [queueName, queue] of this.queueCache) {\n try {\n await queue.close()\n } catch (err) {\n console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)\n }\n }\n process.exit(0)\n }\n}\n\nmodule.exports = { QueueRedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -18,6 +18,7 @@ export class RedisMetricsClient extends BaseMetricsClient {
|
|
|
18
18
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
19
19
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
20
20
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
21
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
21
22
|
*/
|
|
22
23
|
constructor({ redisClient, ...metricsConfig }?: {
|
|
23
24
|
redisClient: any;
|
|
@@ -31,6 +32,7 @@ export class RedisMetricsClient extends BaseMetricsClient {
|
|
|
31
32
|
intervalSec?: number | undefined;
|
|
32
33
|
removeOldMetrics?: boolean | undefined;
|
|
33
34
|
startupValidation?: Function | undefined;
|
|
35
|
+
disablePushgateway?: boolean | undefined;
|
|
34
36
|
});
|
|
35
37
|
/** Redis client used for metrics */
|
|
36
38
|
redisClient: any;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsRedisClient.js"],"names":[],"mappings":"AAWA;;;;;GAKG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../../src/metrics/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;QACf,iBAAiB;QAClB,kBAAkB;OA8C9C;IAhCC,oCAAoC;IACpC,iBAA8B;IAC9B,wBAAsD;IAEtD,2CAA2C;IAC3C,2DAIE;IAEF,iEAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ,wCAgCC;IAED,6CAuBC;IAED,gDAeC;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAsFzB;IAED;;;OAGG;IACH,wBAFa,QAAQ,IAAI,CAAC,CAqBzB;IAED;;;OAGG;IACH,sDAMC;CA4BF"}
|
|
@@ -32,6 +32,7 @@ class RedisMetricsClient extends BaseMetricsClient {
|
|
|
32
32
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
33
33
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
34
34
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
35
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
35
36
|
*/
|
|
36
37
|
constructor({
|
|
37
38
|
redisClient,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsRedisClient.js","names":["BaseMetricsClient","require","getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","redisConnectionStableFields","redisConnectionFields","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","processType","redisClientType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisConnectionsMemoryGauge","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","logValues","console","log","length","grouped","conn","flags","totMem","cmd","key","JSON","stringify","count","memory","Object","values","valueLabels","set","parseRedisInfo","infoStr","fromEntries","startsWith","stats","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","error","warn","pushRedisMetrics","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../../src/metrics/metricsRedisClient.js"],"sourcesContent":["const { BaseMetricsClient } = require('./baseMetricsClient')\nconst {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('../redisUtils')\n\nconst redisConnectionStableFields = ['name', 'flags', 'cmd']\nconst redisConnectionFields = ['name', 'flags', 'tot-mem', 'cmd']\n\n/**\n * RedisMetricsClient extends BaseMetricsClient to collect\n * Redis metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends BaseMetricsClient\n */\nclass RedisMetricsClient extends BaseMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\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 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 /** Counter for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections_count',\n help: 'Redis client connections',\n labelNames: this.withDefaultLabels(redisConnectionStableFields),\n })\n\n this.redisConnectionsMemoryGauge = this.createGauge({\n name: 'app_redis_connections_memory_usage_count',\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 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\n if (this.logValues) {\n console.log('Redis connections: ', connectionsInfoStr)\n console.log('Redis connections count: ', connections.length)\n }\n\n const grouped = {}\n connections.forEach(conn => {\n const { name, flags, 'tot-mem': totMem, cmd } = conn\n\n // build grouping key (includes default gauge labels later)\n const key = JSON.stringify({ name, flags, cmd })\n\n if (!grouped[key]) {\n grouped[key] = {\n labels: { name, flags, cmd },\n count: 0,\n memory: 0,\n }\n }\n\n grouped[key].count += 1\n grouped[key].memory += parseInt(totMem, 10)\n })\n\n Object.values(grouped).forEach(\n ({ labels: valueLabels, count, memory }) => {\n this.redisConnectionsGauge.set({ ...labels, ...valueLabels }, count)\n this.redisConnectionsMemoryGauge.set(\n { ...labels, ...valueLabels },\n memory\n )\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 this.clearAllCounters()\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":["BaseMetricsClient","require","getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","redisConnectionStableFields","redisConnectionFields","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","processType","redisClientType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisConnectionsMemoryGauge","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","logValues","console","log","length","grouped","conn","flags","totMem","cmd","key","JSON","stringify","count","memory","Object","values","valueLabels","set","parseRedisInfo","infoStr","fromEntries","startsWith","stats","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","error","warn","pushRedisMetrics","gatewayPush","clearAllCounters","metricsLogValues","metricObjects","registry","getMetricsAsJSON","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../../src/metrics/metricsRedisClient.js"],"sourcesContent":["const { BaseMetricsClient } = require('./baseMetricsClient')\nconst {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('../redisUtils')\n\nconst redisConnectionStableFields = ['name', 'flags', 'cmd']\nconst redisConnectionFields = ['name', 'flags', 'tot-mem', 'cmd']\n\n/**\n * RedisMetricsClient extends BaseMetricsClient to collect\n * Redis metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends BaseMetricsClient\n */\nclass RedisMetricsClient extends BaseMetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from BaseMetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)\n * @param {string} [options.processType] - Process type (from BaseMetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)\n * @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)\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 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 /** Counter for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections_count',\n help: 'Redis client connections',\n labelNames: this.withDefaultLabels(redisConnectionStableFields),\n })\n\n this.redisConnectionsMemoryGauge = this.createGauge({\n name: 'app_redis_connections_memory_usage_count',\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 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\n if (this.logValues) {\n console.log('Redis connections: ', connectionsInfoStr)\n console.log('Redis connections count: ', connections.length)\n }\n\n const grouped = {}\n connections.forEach(conn => {\n const { name, flags, 'tot-mem': totMem, cmd } = conn\n\n // build grouping key (includes default gauge labels later)\n const key = JSON.stringify({ name, flags, cmd })\n\n if (!grouped[key]) {\n grouped[key] = {\n labels: { name, flags, cmd },\n count: 0,\n memory: 0,\n }\n }\n\n grouped[key].count += 1\n grouped[key].memory += parseInt(totMem, 10)\n })\n\n Object.values(grouped).forEach(\n ({ labels: valueLabels, count, memory }) => {\n this.redisConnectionsGauge.set({ ...labels, ...valueLabels }, count)\n this.redisConnectionsMemoryGauge.set(\n { ...labels, ...valueLabels },\n memory\n )\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 this.clearAllCounters()\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
|
@@ -18,6 +18,7 @@ class BaseMetricsClient {
|
|
|
18
18
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
19
19
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
20
20
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
21
|
+
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
21
22
|
*/
|
|
22
23
|
constructor(config = {}) {
|
|
23
24
|
this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app'
|
|
@@ -38,6 +39,9 @@ class BaseMetricsClient {
|
|
|
38
39
|
parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||
|
|
39
40
|
15
|
|
40
41
|
this.startupValidation = config.startupValidation
|
|
42
|
+
this.disablePushgateway =
|
|
43
|
+
config.disablePushgateway ??
|
|
44
|
+
process.env.METRICS_DISABLE_PUSHGATEWAY === 'true'
|
|
41
45
|
|
|
42
46
|
this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`
|
|
43
47
|
|
|
@@ -152,7 +156,7 @@ class BaseMetricsClient {
|
|
|
152
156
|
for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {
|
|
153
157
|
try {
|
|
154
158
|
if (!updateFn) {
|
|
155
|
-
|
|
159
|
+
continue
|
|
156
160
|
}
|
|
157
161
|
const result = updateFn()
|
|
158
162
|
const val = result instanceof Promise ? await result : result
|
|
@@ -165,7 +169,9 @@ class BaseMetricsClient {
|
|
|
165
169
|
}
|
|
166
170
|
}
|
|
167
171
|
|
|
168
|
-
|
|
172
|
+
if (!this.disablePushgateway) {
|
|
173
|
+
await this.gatewayPush()
|
|
174
|
+
}
|
|
169
175
|
// this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)
|
|
170
176
|
|
|
171
177
|
if (this.logValues) {
|
|
@@ -365,6 +371,9 @@ class BaseMetricsClient {
|
|
|
365
371
|
* @returns {Promise<void>}
|
|
366
372
|
*/
|
|
367
373
|
gatewayPush = async (params = {}) => {
|
|
374
|
+
if (this.disablePushgateway) {
|
|
375
|
+
return Promise.resolve()
|
|
376
|
+
}
|
|
368
377
|
const groupings = {
|
|
369
378
|
process_type: this.processType,
|
|
370
379
|
instance: this.dynoId,
|
|
@@ -409,6 +418,23 @@ class BaseMetricsClient {
|
|
|
409
418
|
get registry() {
|
|
410
419
|
return this._registry
|
|
411
420
|
}
|
|
421
|
+
|
|
422
|
+
async getMetricsAsString() {
|
|
423
|
+
return this._registry.metrics()
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
metricsMiddleware() {
|
|
427
|
+
return async (req, res) => {
|
|
428
|
+
try {
|
|
429
|
+
const metrics = await this.getMetricsAsString()
|
|
430
|
+
res.set('Content-Type', client.register.contentType)
|
|
431
|
+
res.end(metrics)
|
|
432
|
+
} catch (err) {
|
|
433
|
+
console.error(`${this.prefixLogs} Failed to get metrics:`, err)
|
|
434
|
+
res.status(500).end('Failed to collect metrics')
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
412
438
|
}
|
|
413
439
|
|
|
414
440
|
module.exports = { BaseMetricsClient }
|
|
@@ -20,6 +20,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
20
20
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
21
21
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
22
22
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
23
|
+
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
23
24
|
*/
|
|
24
25
|
constructor(config = {}) {
|
|
25
26
|
super(config)
|
|
@@ -23,6 +23,7 @@ class DatabaseMetricsClient extends BaseMetricsClient {
|
|
|
23
23
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics
|
|
24
24
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service
|
|
25
25
|
* @param {function} [options.startupValidation] - Function to validate startup
|
|
26
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
26
27
|
*/
|
|
27
28
|
constructor({
|
|
28
29
|
databaseUrl,
|
|
@@ -22,6 +22,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
22
22
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
23
23
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
24
24
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
25
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
25
26
|
*/
|
|
26
27
|
constructor({ redisClient, metricsConfig = {} } = {}) {
|
|
27
28
|
const getConfiguredQueueNames = () => {
|
|
@@ -29,6 +29,7 @@ class RedisMetricsClient extends BaseMetricsClient {
|
|
|
29
29
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
30
30
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
31
31
|
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
32
|
+
* @param {boolean} [options.disablePushgateway] - Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
32
33
|
*/
|
|
33
34
|
constructor({ redisClient, ...metricsConfig } = {}) {
|
|
34
35
|
const intervalSec =
|