@adalo/metrics 0.1.55 → 0.1.57

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/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './metricsClient';
2
2
  export * from './metricsRedisClient';
3
+ export * from './metricsQueueRedisClient';
3
4
  export * from './redisUtils';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,cAAc,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,cAAc,CAAA"}
package/lib/index.js CHANGED
@@ -25,6 +25,17 @@ Object.keys(_metricsRedisClient).forEach(function (key) {
25
25
  }
26
26
  });
27
27
  });
28
+ var _metricsQueueRedisClient = require("./metricsQueueRedisClient");
29
+ Object.keys(_metricsQueueRedisClient).forEach(function (key) {
30
+ if (key === "default" || key === "__esModule") return;
31
+ if (key in exports && exports[key] === _metricsQueueRedisClient[key]) return;
32
+ Object.defineProperty(exports, key, {
33
+ enumerable: true,
34
+ get: function () {
35
+ return _metricsQueueRedisClient[key];
36
+ }
37
+ });
38
+ });
28
39
  var _redisUtils = require("./redisUtils");
29
40
  Object.keys(_redisUtils).forEach(function (key) {
30
41
  if (key === "default" || key === "__esModule") return;
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_metricsClient","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_metricsRedisClient","_redisUtils"],"sources":["../src/index.ts"],"sourcesContent":["export * from './metricsClient'\nexport * from './metricsRedisClient'\nexport * from './redisUtils'\n"],"mappings":";;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,cAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,cAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,cAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,mBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,mBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,mBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,mBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,WAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,WAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,WAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,WAAA,CAAAN,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["_metricsClient","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_metricsRedisClient","_metricsQueueRedisClient","_redisUtils"],"sources":["../src/index.ts"],"sourcesContent":["export * from './metricsClient'\nexport * from './metricsRedisClient'\nexport * from './metricsQueueRedisClient'\nexport * from './redisUtils'\n"],"mappings":";;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,cAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,cAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,cAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,mBAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,mBAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,mBAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,mBAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,wBAAA,GAAAV,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAQ,wBAAA,EAAAP,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAM,wBAAA,CAAAN,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAE,wBAAA,CAAAN,GAAA;IAAA;EAAA;AAAA;AACA,IAAAO,WAAA,GAAAX,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAS,WAAA,EAAAR,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAO,WAAA,CAAAP,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,WAAA,CAAAP,GAAA;IAAA;EAAA;AAAA","ignoreList":[]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * QueueRedisMetricsClient extends MetricsClient to collect
3
+ * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
4
+ *
5
+ * @extends RedisMetricsClient
6
+ */
7
+ export class QueueRedisMetricsClient extends RedisMetricsClient {
8
+ getConfiguredQueueNames: () => string[];
9
+ startupValidation: () => boolean;
10
+ /** Cache for queue objects to avoid multiple connections */
11
+ queueCache: Map<any, any>;
12
+ /** Gauge for queue jobs by status */
13
+ queueJobsGauge: import("prom-client").Gauge<string>;
14
+ /**
15
+ * Collect metrics for a single Bee Queue and set gauges
16
+ * @param {string} queueName - Name of the queue
17
+ * @returns {Promise<void>}
18
+ */
19
+ collectSingleQueueMetrics: (queueName: string) => Promise<void>;
20
+ /**
21
+ * Collect metrics for all queues and Redis, then push to Pushgateway
22
+ * @returns {Promise<void>}
23
+ */
24
+ collectQueueMetrics: () => Promise<void>;
25
+ }
26
+ import { RedisMetricsClient } from "./metricsRedisClient";
27
+ //# sourceMappingURL=metricsQueueRedisClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsQueueRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsQueueRedisClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IAgEI,wCAAsD;IACtD,iCAA0C;IAE1C,4DAA4D;IAC5D,0BAA2B;IAE3B,qCAAqC;IACrC,oDAIE;IAKJ;;;;OAIG;IACH,uCAHW,MAAM,KACJ,QAAQ,IAAI,CAAC,CAkDzB;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAsCzB;CAmCF"}
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+
3
+ const Queue = require('bee-queue');
4
+ const {
5
+ RedisMetricsClient
6
+ } = require('.');
7
+
8
+ /**
9
+ * QueueRedisMetricsClient extends MetricsClient to collect
10
+ * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
11
+ *
12
+ * @extends RedisMetricsClient
13
+ */
14
+ class QueueRedisMetricsClient extends RedisMetricsClient {
15
+ /**
16
+ * @param {Object} options
17
+ * @param {any} options.redisClient - Redis client instance (required)
18
+ * @param {string} [options.appName] - Application name (from MetricsClient)
19
+ * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
20
+ * @param {string} [options.processType] - Process type (from MetricsClient)
21
+ * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)
22
+ * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)
23
+ * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)
24
+ * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)
25
+ * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)
26
+ * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)
27
+ * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)
28
+ * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
29
+ */
30
+ constructor({
31
+ redisClient,
32
+ metricsConfig = {}
33
+ } = {}) {
34
+ const getConfiguredQueueNames = () => {
35
+ if (!process.env.METRICS_APP_REDIS_BQ) {
36
+ throw new Error('No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names');
37
+ }
38
+ const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',').map(q => q.trim()).filter(Boolean);
39
+ if (allQueues.length === 0) {
40
+ throw new Error('METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' + 'Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"');
41
+ }
42
+ return [...new Set(allQueues)];
43
+ };
44
+ const startupValidation = () => {
45
+ try {
46
+ const queueNames = getConfiguredQueueNames();
47
+ console.info(`[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`);
48
+ return true;
49
+ } catch (error) {
50
+ console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`);
51
+ console.error(`[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`);
52
+ console.error(`[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC="10"`);
53
+ console.error(`[queue-metrics] Skipping queue metrics collection`);
54
+ return false;
55
+ }
56
+ };
57
+ super({
58
+ ...metricsConfig,
59
+ redisClient,
60
+ startupValidation
61
+ });
62
+ this.getConfiguredQueueNames = getConfiguredQueueNames;
63
+ this.startupValidation = startupValidation;
64
+
65
+ /** Cache for queue objects to avoid multiple connections */
66
+ this.queueCache = new Map();
67
+
68
+ /** Gauge for queue jobs by status */
69
+ this.queueJobsGauge = this.createGauge({
70
+ name: 'app_queue_jobs_count',
71
+ help: 'Number of app jobs in the queue by status',
72
+ labelNames: this.withDefaultLabels(['queue_name', 'status'])
73
+ });
74
+ this._setCleanupHandlers();
75
+ }
76
+
77
+ /**
78
+ * Collect metrics for a single Bee Queue and set gauges
79
+ * @param {string} queueName - Name of the queue
80
+ * @returns {Promise<void>}
81
+ */
82
+ collectSingleQueueMetrics = async queueName => {
83
+ try {
84
+ if (!this.queueCache.has(queueName)) {
85
+ this.queueCache.set(queueName, new Queue(queueName, {
86
+ redis: this.redisClient,
87
+ isWorker: false,
88
+ getEvents: false,
89
+ sendEvents: false
90
+ }));
91
+ }
92
+ const queue = this.queueCache.get(queueName);
93
+ const health = await queue.checkHealth();
94
+ const labels = {
95
+ ...this.getDefaultLabels(),
96
+ queue_name: queueName
97
+ };
98
+ this.queueJobsGauge.set({
99
+ ...labels,
100
+ status: 'waiting'
101
+ }, health.waiting || 0);
102
+ this.queueJobsGauge.set({
103
+ ...labels,
104
+ status: 'active'
105
+ }, health.active || 0);
106
+ this.queueJobsGauge.set({
107
+ ...labels,
108
+ status: 'succeeded'
109
+ }, health.succeeded || 0);
110
+ this.queueJobsGauge.set({
111
+ ...labels,
112
+ status: 'failed'
113
+ }, health.failed || 0);
114
+ this.queueJobsGauge.set({
115
+ ...labels,
116
+ status: 'delayed'
117
+ }, health.delayed || 0);
118
+ } catch (error) {
119
+ console.warn(`[queue-metrics] Failed to collect metrics for queue ${queueName}:`, error.message);
120
+ }
121
+ };
122
+
123
+ /**
124
+ * Collect metrics for all queues and Redis, then push to Pushgateway
125
+ * @returns {Promise<void>}
126
+ */
127
+ collectQueueMetrics = async () => {
128
+ try {
129
+ const queueNames = this.getConfiguredQueueNames();
130
+ await this.collectRedisMetrics();
131
+ await Promise.allSettled(queueNames.map(queueName => this.collectSingleQueueMetrics(queueName)));
132
+ await this.gatewayPush();
133
+ if (this.metricsLogValues) {
134
+ const metricObjects = await this.registry.getMetricsAsJSON();
135
+ console.info(`[queue-metrics] Collected metrics for ${queueNames.length} queues:`, JSON.stringify(metricObjects, null, 2));
136
+ }
137
+ } catch (error) {
138
+ if (error.message?.includes('No queues configured') || error.message?.includes('METRICS_APP_REDIS_BQ')) {
139
+ console.error(`[queue-metrics] ❌ Configuration error: ${error.message}`);
140
+ console.error(`[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`);
141
+ } else {
142
+ console.error(`[queue-metrics] Failed to collect queue metrics: ${error.message}`);
143
+ }
144
+ throw error;
145
+ }
146
+ };
147
+
148
+ /**
149
+ * Start periodic collection.
150
+ * @param {number} [intervalSec=this.intervalSec] - Interval in seconds
151
+ */
152
+ startPush = (intervalSec = this.intervalSec) => {
153
+ this._startPush(intervalSec, () => {
154
+ this.collectQueueMetrics().catch(err => {
155
+ console.error(`[queue-metrics] Failed to collect queue & Redis metrics:`, err);
156
+ });
157
+ });
158
+ };
159
+ _setCleanupHandlers = () => {
160
+ process.on('SIGINT', this.cleanup);
161
+ process.on('SIGTERM', this.cleanup);
162
+ };
163
+
164
+ /**
165
+ * Cleanup queues and Redis client
166
+ */
167
+ cleanup = async () => {
168
+ for (const [queueName, queue] of this.queueCache) {
169
+ try {
170
+ await queue.close();
171
+ } catch (err) {
172
+ console.error(`[queue-metrics] Error closing queue ${queueName}:`, err);
173
+ }
174
+ }
175
+ process.exit(0);
176
+ };
177
+ }
178
+ module.exports = {
179
+ QueueRedisMetricsClient
180
+ };
181
+ //# sourceMappingURL=metricsQueueRedisClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsQueueRedisClient.js","names":["Queue","require","RedisMetricsClient","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","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","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","intervalSec","_startPush","catch","err","on","cleanup","close","exit","module","exports"],"sources":["../src/metricsQueueRedisClient.js"],"sourcesContent":["const Queue = require('bee-queue')\nconst { RedisMetricsClient } = require('.')\n\n/**\n * QueueRedisMetricsClient extends MetricsClient 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 MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)\n */\n constructor({ redisClient, metricsConfig = {} } = {}) {\n const 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 * 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.redisClient,\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\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 Redis client\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":[]}
@@ -1,27 +1,41 @@
1
1
  /**
2
2
  * RedisMetricsClient extends MetricsClient to collect
3
- * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
3
+ * Redis metrics periodically and push them to Prometheus Pushgateway.
4
4
  *
5
5
  * @extends MetricsClient
6
6
  */
7
7
  export class RedisMetricsClient extends MetricsClient {
8
8
  /**
9
- * @param {Object} options - Metrics client options + Redis client
9
+ * @param {Object} options
10
10
  * @param {any} options.redisClient - Redis client instance (required)
11
- * @param {Object} [options.metricsConfig] - MetricsClient configuration overrides
11
+ * @param {string} [options.appName] - Application name (from MetricsClient)
12
+ * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
13
+ * @param {string} [options.processType] - Process type (from MetricsClient)
14
+ * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)
15
+ * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)
16
+ * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)
17
+ * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)
18
+ * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)
19
+ * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)
20
+ * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)
21
+ * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
12
22
  */
13
- constructor({ redisClient, metricsConfig }?: {
23
+ constructor({ redisClient, ...metricsConfig }?: {
14
24
  redisClient: any;
15
- metricsConfig?: Object | undefined;
25
+ appName?: string | undefined;
26
+ dynoId?: string | undefined;
27
+ processType?: string | undefined;
28
+ enabled?: boolean | undefined;
29
+ logValues?: boolean | undefined;
30
+ pushgatewayUrl?: string | undefined;
31
+ pushgatewaySecret?: string | undefined;
32
+ intervalSec?: number | undefined;
33
+ removeOldMetrics?: boolean | undefined;
34
+ scripDefaultMetrics?: boolean | undefined;
35
+ startupValidation?: Function | undefined;
16
36
  });
17
- getConfiguredQueueNames: () => string[];
18
- startupValidation: () => boolean;
19
- /** Redis client used for queue & Redis metrics */
37
+ /** Redis client used for metrics */
20
38
  redisClient: any;
21
- /** Cache for queue objects to avoid multiple connections */
22
- queueCache: Map<any, any>;
23
- /** Gauge for queue jobs by status */
24
- queueJobsGauge: import("prom-client").Gauge<string>;
25
39
  /** Gauge for Redis client connections */
26
40
  redisConnectionsGauge: import("prom-client").Gauge<string>;
27
41
  /** Gauge for Redis memory usage */
@@ -34,16 +48,10 @@ export class RedisMetricsClient extends MetricsClient {
34
48
  */
35
49
  collectRedisMetrics: () => Promise<void>;
36
50
  /**
37
- * Collect metrics for a single Bee Queue and set gauges
38
- * @param {string} queueName - Name of the queue
51
+ * Collect metrics for all Redis and push to Prometheus Pushgateway
39
52
  * @returns {Promise<void>}
40
53
  */
41
- collectSingleQueueMetrics: (queueName: string) => Promise<void>;
42
- /**
43
- * Collect metrics for all queues and Redis, then push to Pushgateway
44
- * @returns {Promise<void>}
45
- */
46
- collectQueueMetrics: () => Promise<void>;
54
+ pushRedisMetrics: () => Promise<void>;
47
55
  /**
48
56
  * Start periodic collection.
49
57
  * @param {number} [intervalSec=this.intervalSec] - Interval in seconds
@@ -1 +1 @@
1
- {"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH;IACE;;;;OAIG;IACH;QAHwB,WAAW,EAAxB,GAAG;QACc,aAAa;OA+FxC;IAtCC,wCAAsD;IACtD,iCAA0C;IAE1C,kDAAkD;IAClD,iBAA8B;IAE9B,4DAA4D;IAC5D,0BAA2B;IAE3B,qCAAqC;IACrC,oDAIE;IAEF,yCAAyC;IACzC,2DAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAiEzB;IAED;;;;OAIG;IACH,uCAHW,MAAM,KACJ,QAAQ,IAAI,CAAC,CAkDzB;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAsCzB;IAED;;;OAGG;IACH,sDASC;CAuBF"}
1
+ {"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH;QAbwB,WAAW,EAAxB,GAAG;QACc,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAwC9C;IAzBC,oCAAoC;IACpC,iBAA8B;IAE9B,yCAAyC;IACzC,2DAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAiEzB;IAED;;;OAGG;IACH,wBAFa,QAAQ,IAAI,CAAC,CAoBzB;IAED;;;OAGG;IACH,sDAMC;CAkBF"}
@@ -1,73 +1,46 @@
1
1
  "use strict";
2
2
 
3
- const Queue = require('bee-queue');
4
3
  const {
5
4
  MetricsClient
6
5
  } = require('.');
7
6
 
8
7
  /**
9
8
  * RedisMetricsClient extends MetricsClient to collect
10
- * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
9
+ * Redis metrics periodically and push them to Prometheus Pushgateway.
11
10
  *
12
11
  * @extends MetricsClient
13
12
  */
14
13
  class RedisMetricsClient extends MetricsClient {
15
14
  /**
16
- * @param {Object} options - Metrics client options + Redis client
15
+ * @param {Object} options
17
16
  * @param {any} options.redisClient - Redis client instance (required)
18
- * @param {Object} [options.metricsConfig] - MetricsClient configuration overrides
17
+ * @param {string} [options.appName] - Application name (from MetricsClient)
18
+ * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
19
+ * @param {string} [options.processType] - Process type (from MetricsClient)
20
+ * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)
21
+ * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)
22
+ * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)
23
+ * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)
24
+ * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)
25
+ * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)
26
+ * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)
27
+ * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
19
28
  */
20
29
  constructor({
21
30
  redisClient,
22
- metricsConfig = {}
31
+ ...metricsConfig
23
32
  } = {}) {
24
- const METRICS_QUEUE_INTERVAL_SEC = metricsConfig.intervalSec || parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) || 5;
25
- const getConfiguredQueueNames = () => {
26
- if (!process.env.METRICS_APP_REDIS_BQ) {
27
- throw new Error('No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names');
28
- }
29
- const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',').map(q => q.trim()).filter(Boolean);
30
- if (allQueues.length === 0) {
31
- throw new Error('METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' + 'Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"');
32
- }
33
- return [...new Set(allQueues)];
34
- };
35
- const startupValidation = () => {
36
- try {
37
- const queueNames = getConfiguredQueueNames();
38
- console.info(`[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`);
39
- return true;
40
- } catch (error) {
41
- console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`);
42
- console.error(`[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`);
43
- console.error(`[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC="10"`);
44
- console.error(`[queue-metrics] Skipping queue metrics collection`);
45
- return false;
46
- }
47
- };
33
+ const intervalSec = metricsConfig.intervalSec || parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) || 5;
48
34
  super({
49
35
  ...metricsConfig,
50
36
  scripDefaultMetrics: true,
51
- processType: metricsConfig.processType || 'queue-metrics',
52
- intervalSec: METRICS_QUEUE_INTERVAL_SEC,
53
- startupValidation
37
+ processType: metricsConfig.processType || 'redis-metrics',
38
+ intervalSec
54
39
  });
55
- this.getConfiguredQueueNames = getConfiguredQueueNames;
56
- this.startupValidation = startupValidation;
57
40
 
58
- /** Redis client used for queue & Redis metrics */
41
+ /** Redis client used for metrics */
59
42
  this.redisClient = redisClient;
60
43
 
61
- /** Cache for queue objects to avoid multiple connections */
62
- this.queueCache = new Map();
63
-
64
- /** Gauge for queue jobs by status */
65
- this.queueJobsGauge = this.createGauge({
66
- name: 'app_queue_jobs_count',
67
- help: 'Number of app jobs in the queue by status',
68
- labelNames: this.withDefaultLabels(['queue_name', 'status'])
69
- });
70
-
71
44
  /** Gauge for Redis client connections */
72
45
  this.redisConnectionsGauge = this.createGauge({
73
46
  name: 'app_redis_connections_count',
@@ -138,72 +111,19 @@ class RedisMetricsClient extends MetricsClient {
138
111
  };
139
112
 
140
113
  /**
141
- * Collect metrics for a single Bee Queue and set gauges
142
- * @param {string} queueName - Name of the queue
114
+ * Collect metrics for all Redis and push to Prometheus Pushgateway
143
115
  * @returns {Promise<void>}
144
116
  */
145
- collectSingleQueueMetrics = async queueName => {
117
+ pushRedisMetrics = async () => {
146
118
  try {
147
- if (!this.queueCache.has(queueName)) {
148
- this.queueCache.set(queueName, new Queue(queueName, {
149
- redis: this.redisClient,
150
- isWorker: false,
151
- getEvents: false,
152
- sendEvents: false
153
- }));
154
- }
155
- const queue = this.queueCache.get(queueName);
156
- const health = await queue.checkHealth();
157
- const labels = {
158
- ...this.getDefaultLabels(),
159
- queue_name: queueName
160
- };
161
- this.queueJobsGauge.set({
162
- ...labels,
163
- status: 'waiting'
164
- }, health.waiting || 0);
165
- this.queueJobsGauge.set({
166
- ...labels,
167
- status: 'active'
168
- }, health.active || 0);
169
- this.queueJobsGauge.set({
170
- ...labels,
171
- status: 'succeeded'
172
- }, health.succeeded || 0);
173
- this.queueJobsGauge.set({
174
- ...labels,
175
- status: 'failed'
176
- }, health.failed || 0);
177
- this.queueJobsGauge.set({
178
- ...labels,
179
- status: 'delayed'
180
- }, health.delayed || 0);
181
- } catch (error) {
182
- console.warn(`[queue-metrics] Failed to collect metrics for queue ${queueName}:`, error.message);
183
- }
184
- };
185
-
186
- /**
187
- * Collect metrics for all queues and Redis, then push to Pushgateway
188
- * @returns {Promise<void>}
189
- */
190
- collectQueueMetrics = async () => {
191
- try {
192
- const queueNames = this.getConfiguredQueueNames();
193
119
  await this.collectRedisMetrics();
194
- await Promise.allSettled(queueNames.map(queueName => this.collectSingleQueueMetrics(queueName)));
195
120
  await this.gatewayPush();
196
121
  if (this.metricsLogValues) {
197
122
  const metricObjects = await this.registry.getMetricsAsJSON();
198
- console.info(`[queue-metrics] Collected metrics for ${queueNames.length} queues:`, JSON.stringify(metricObjects, null, 2));
123
+ console.info(`[redis-metrics] Collected metrics for Redis`, JSON.stringify(metricObjects, null, 2));
199
124
  }
200
125
  } catch (error) {
201
- if (error.message?.includes('No queues configured') || error.message?.includes('METRICS_APP_REDIS_BQ')) {
202
- console.error(`[queue-metrics] ❌ Configuration error: ${error.message}`);
203
- console.error(`[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`);
204
- } else {
205
- console.error(`[queue-metrics] Failed to collect queue metrics: ${error.message}`);
206
- }
126
+ console.error(`[redis-metrics] Failed to collect Redis metrics: ${error.message}`);
207
127
  throw error;
208
128
  }
209
129
  };
@@ -214,32 +134,27 @@ class RedisMetricsClient extends MetricsClient {
214
134
  */
215
135
  startPush = (intervalSec = this.intervalSec) => {
216
136
  this._startPush(intervalSec, () => {
217
- this.collectQueueMetrics().catch(err => {
218
- console.error(`[queue-metrics] Failed to collect queue & Redis metrics:`, err);
137
+ this.pushRedisMetrics().catch(err => {
138
+ console.error(`[redis-metrics] Failed to push Redis metrics:`, err);
219
139
  });
220
140
  });
221
141
  };
222
- _setCleanupHandlers = () => {
223
- process.on('SIGINT', this.cleanup);
224
- process.on('SIGTERM', this.cleanup);
225
- };
226
142
 
227
143
  /**
228
- * Cleanup queues and Redis client
144
+ * Cleanup Redis client
229
145
  */
230
146
  cleanup = async () => {
231
- for (const [queueName, queue] of this.queueCache) {
232
- try {
233
- await queue.close();
234
- } catch (err) {
235
- console.error(`[queue-metrics] Error closing queue ${queueName}:`, err);
236
- }
147
+ try {
148
+ this.redisClient?.quit();
149
+ } catch (err) {
150
+ console.error('[redis-metrics] Error closing Redis client:', err);
237
151
  }
238
-
239
- // Close Redis connection
240
- this.redisClient?.quit();
241
152
  process.exit(0);
242
153
  };
154
+ _setCleanupHandlers = () => {
155
+ process.on('SIGINT', this.cleanup);
156
+ process.on('SIGTERM', this.cleanup);
157
+ };
243
158
  }
244
159
  module.exports = {
245
160
  RedisMetricsClient
@@ -1 +1 @@
1
- {"version":3,"file":"metricsRedisClient.js","names":["Queue","require","MetricsClient","RedisMetricsClient","constructor","redisClient","metricsConfig","METRICS_QUEUE_INTERVAL_SEC","intervalSec","parseInt","process","env","getConfiguredQueueNames","METRICS_APP_REDIS_BQ","Error","allQueues","split","map","q","trim","filter","Boolean","length","Set","startupValidation","queueNames","console","info","error","message","scripDefaultMetrics","processType","queueCache","Map","queueJobsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisConnectionsGauge","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","collectRedisMetrics","getRedisInfo","section","Promise","resolve","reject","err","result","clientsInfo","memoryInfo","statsInfo","all","labels","getDefaultLabels","parseRedisInfo","infoStr","Object","fromEntries","line","startsWith","parts","clients","memory","stats","connected_clients","set","connection_type","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","warn","collectSingleQueueMetrics","queueName","has","redis","isWorker","getEvents","sendEvents","queue","get","health","checkHealth","queue_name","status","waiting","active","succeeded","failed","delayed","collectQueueMetrics","allSettled","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","includes","startPush","_startPush","catch","on","cleanup","close","quit","exit","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const Queue = require('bee-queue')\nconst { MetricsClient } = require('.')\n\n/**\n * RedisMetricsClient extends MetricsClient to collect\n * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass RedisMetricsClient extends MetricsClient {\n /**\n * @param {Object} options - Metrics client options + Redis client\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {Object} [options.metricsConfig] - MetricsClient configuration overrides\n */\n constructor({ redisClient, metricsConfig = {} } = {}) {\n const METRICS_QUEUE_INTERVAL_SEC =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) ||\n 5\n\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 scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'queue-metrics',\n intervalSec: METRICS_QUEUE_INTERVAL_SEC,\n startupValidation,\n })\n\n this.getConfiguredQueueNames = getConfiguredQueueNames\n this.startupValidation = startupValidation\n\n /** Redis client used for queue & Redis metrics */\n this.redisClient = redisClient\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 /** Gauge for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections_count',\n help: 'Number of Redis client connections',\n labelNames: this.withDefaultLabels(['connection_type']),\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 /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const getRedisInfo = section =>\n new Promise((resolve, reject) => {\n this.redisClient.info(section, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n\n const [clientsInfo, memoryInfo, statsInfo] = await Promise.all([\n getRedisInfo('clients'),\n getRedisInfo('memory'),\n getRedisInfo('stats'),\n ])\n\n const labels = this.getDefaultLabels()\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 clients = parseRedisInfo(clientsInfo)\n const memory = parseRedisInfo(memoryInfo)\n const stats = parseRedisInfo(statsInfo)\n\n if (clients.connected_clients) {\n this.redisConnectionsGauge.set(\n { ...labels, connection_type: 'connected' },\n parseInt(clients.connected_clients, 10) || 0\n )\n }\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 `[redis-metrics] Failed to collect Redis metrics:`,\n error.message\n )\n }\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.redisClient,\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\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 Redis client\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\n // Close Redis connection\n this.redisClient?.quit()\n process.exit(0)\n }\n}\n\nmodule.exports = { RedisMetricsClient }\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"metricsRedisClient.js","names":["MetricsClient","require","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","scripDefaultMetrics","processType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","collectRedisMetrics","getRedisInfo","section","Promise","resolve","reject","info","err","result","clientsInfo","memoryInfo","statsInfo","all","labels","getDefaultLabels","parseRedisInfo","infoStr","Object","fromEntries","split","filter","line","startsWith","map","parts","length","clients","memory","stats","connected_clients","set","connection_type","used_memory","memory_type","maxmemory","instantaneous_ops_per_sec","operation","error","console","warn","message","pushRedisMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","quit","exit","on","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const { MetricsClient } = require('.')\n\n/**\n * RedisMetricsClient extends MetricsClient to collect\n * Redis metrics periodically and push them to Prometheus Pushgateway.\n *\n * @extends MetricsClient\n */\nclass RedisMetricsClient extends MetricsClient {\n /**\n * @param {Object} options\n * @param {any} options.redisClient - Redis client instance (required)\n * @param {string} [options.appName] - Application name (from MetricsClient)\n * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)\n * @param {string} [options.processType] - Process type (from MetricsClient)\n * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)\n * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)\n * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)\n * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)\n * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)\n * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)\n * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)\n * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)\n */\n constructor({ redisClient, ...metricsConfig } = {}) {\n const intervalSec =\n metricsConfig.intervalSec ||\n parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) ||\n 5\n\n super({\n ...metricsConfig,\n scripDefaultMetrics: true,\n processType: metricsConfig.processType || 'redis-metrics',\n intervalSec,\n })\n\n /** Redis client used for metrics */\n this.redisClient = redisClient\n\n /** Gauge for Redis client connections */\n this.redisConnectionsGauge = this.createGauge({\n name: 'app_redis_connections_count',\n help: 'Number of Redis client connections',\n labelNames: this.withDefaultLabels(['connection_type']),\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 /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const getRedisInfo = section =>\n new Promise((resolve, reject) => {\n this.redisClient.info(section, (err, result) => {\n if (err) reject(err)\n else resolve(result)\n })\n })\n\n const [clientsInfo, memoryInfo, statsInfo] = await Promise.all([\n getRedisInfo('clients'),\n getRedisInfo('memory'),\n getRedisInfo('stats'),\n ])\n\n const labels = this.getDefaultLabels()\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 clients = parseRedisInfo(clientsInfo)\n const memory = parseRedisInfo(memoryInfo)\n const stats = parseRedisInfo(statsInfo)\n\n if (clients.connected_clients) {\n this.redisConnectionsGauge.set(\n { ...labels, connection_type: 'connected' },\n parseInt(clients.connected_clients, 10) || 0\n )\n }\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 `[redis-metrics] Failed to collect Redis metrics:`,\n error.message\n )\n }\n }\n\n /**\n * Collect metrics for all Redis and push to Prometheus Pushgateway\n * @returns {Promise<void>}\n */\n pushRedisMetrics = async () => {\n try {\n await this.collectRedisMetrics()\n await this.gatewayPush()\n\n if (this.metricsLogValues) {\n const metricObjects = await this.registry.getMetricsAsJSON()\n console.info(\n `[redis-metrics] Collected metrics for Redis`,\n JSON.stringify(metricObjects, null, 2)\n )\n }\n } catch (error) {\n console.error(\n `[redis-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(`[redis-metrics] Failed to push Redis metrics:`, err)\n })\n })\n }\n\n /**\n * Cleanup Redis client\n */\n cleanup = async () => {\n try {\n this.redisClient?.quit()\n } catch (err) {\n console.error('[redis-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,2 +1,8 @@
1
+ /**
2
+ * Creates a configured setClientName function.
3
+ *
4
+ * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.
5
+ * @returns {(client: import('redis').RedisClient, name: string) => void}
6
+ */
1
7
  export function createSetClientName(defaultAppName?: string | undefined): (client: import('redis').RedisClient, name: string) => void;
2
8
  //# sourceMappingURL=redisUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redisUtils.d.ts","sourceRoot":"","sources":["../src/redisUtils.js"],"names":[],"mappings":"AAMO,mFAFe,OAAO,OAAO,EAAE,WAAW,QAAQ,MAAM,KAAK,IAAI,CAuBvE"}
1
+ {"version":3,"file":"redisUtils.d.ts","sourceRoot":"","sources":["../src/redisUtils.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,mFAFsB,OAAO,OAAO,EAAE,WAAW,QAAQ,MAAM,KAAK,IAAI,CAuBvE"}
package/lib/redisUtils.js CHANGED
@@ -1,9 +1,5 @@
1
1
  "use strict";
2
2
 
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.createSetClientName = void 0;
7
3
  /**
8
4
  * Creates a configured setClientName function.
9
5
  *
@@ -27,5 +23,7 @@ const createSetClientName = (defaultAppName = 'undefined-app') => {
27
23
  }
28
24
  };
29
25
  };
30
- exports.createSetClientName = createSetClientName;
26
+ module.exports = {
27
+ createSetClientName
28
+ };
31
29
  //# sourceMappingURL=redisUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redisUtils.js","names":["createSetClientName","defaultAppName","client","name","appName","process","env","METRICS_APP_NAME","dyno","BUILD_DYNO_PROCESS_TYPE","NODE_ENV","on","send_command","err","console","error","log","pid","exports"],"sources":["../src/redisUtils.js"],"sourcesContent":["/**\n * Creates a configured setClientName function.\n *\n * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.\n * @returns {(client: import('redis').RedisClient, name: string) => void}\n */\nexport const createSetClientName = (defaultAppName = 'undefined-app') => {\n return (client, name) => {\n const appName = process.env.METRICS_APP_NAME || defaultAppName\n const dyno = process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined-dyno'\n\n if (process.env.NODE_ENV !== 'test') {\n client.on('connect', () => {\n client.send_command(\n 'CLIENT',\n ['SETNAME', `${appName}:${dyno}:${name}`],\n err => {\n if (err) {\n console.error(`Failed to set client name for ${name}:`, err)\n } else {\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n }\n }\n )\n })\n }\n }\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMA,mBAAmB,GAAGA,CAACC,cAAc,GAAG,eAAe,KAAK;EACvE,OAAO,CAACC,MAAM,EAAEC,IAAI,KAAK;IACvB,MAAMC,OAAO,GAAGC,OAAO,CAACC,GAAG,CAACC,gBAAgB,IAAIN,cAAc;IAC9D,MAAMO,IAAI,GAAGH,OAAO,CAACC,GAAG,CAACG,uBAAuB,IAAI,gBAAgB;IAEpE,IAAIJ,OAAO,CAACC,GAAG,CAACI,QAAQ,KAAK,MAAM,EAAE;MACnCR,MAAM,CAACS,EAAE,CAAC,SAAS,EAAE,MAAM;QACzBT,MAAM,CAACU,YAAY,CACjB,QAAQ,EACR,CAAC,SAAS,EAAE,GAAGR,OAAO,IAAII,IAAI,IAAIL,IAAI,EAAE,CAAC,EACzCU,GAAG,IAAI;UACL,IAAIA,GAAG,EAAE;YACPC,OAAO,CAACC,KAAK,CAAC,iCAAiCZ,IAAI,GAAG,EAAEU,GAAG,CAAC;UAC9D,CAAC,MAAM;YACLC,OAAO,CAACE,GAAG,CAAC,8BAA8BX,OAAO,CAACY,GAAG,KAAKd,IAAI,GAAG,CAAC;UACpE;QACF,CACF,CAAC;MACH,CAAC,CAAC;IACJ;EACF,CAAC;AACH,CAAC;AAAAe,OAAA,CAAAlB,mBAAA,GAAAA,mBAAA","ignoreList":[]}
1
+ {"version":3,"file":"redisUtils.js","names":["createSetClientName","defaultAppName","client","name","appName","process","env","METRICS_APP_NAME","dyno","BUILD_DYNO_PROCESS_TYPE","NODE_ENV","on","send_command","err","console","error","log","pid","module","exports"],"sources":["../src/redisUtils.js"],"sourcesContent":["/**\n * Creates a configured setClientName function.\n *\n * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.\n * @returns {(client: import('redis').RedisClient, name: string) => void}\n */\nconst createSetClientName = (defaultAppName = 'undefined-app') => {\n return (client, name) => {\n const appName = process.env.METRICS_APP_NAME || defaultAppName\n const dyno = process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined-dyno'\n\n if (process.env.NODE_ENV !== 'test') {\n client.on('connect', () => {\n client.send_command(\n 'CLIENT',\n ['SETNAME', `${appName}:${dyno}:${name}`],\n err => {\n if (err) {\n console.error(`Failed to set client name for ${name}:`, err)\n } else {\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n }\n }\n )\n })\n }\n }\n}\n\nmodule.exports = { createSetClientName }\n"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMA,mBAAmB,GAAGA,CAACC,cAAc,GAAG,eAAe,KAAK;EAChE,OAAO,CAACC,MAAM,EAAEC,IAAI,KAAK;IACvB,MAAMC,OAAO,GAAGC,OAAO,CAACC,GAAG,CAACC,gBAAgB,IAAIN,cAAc;IAC9D,MAAMO,IAAI,GAAGH,OAAO,CAACC,GAAG,CAACG,uBAAuB,IAAI,gBAAgB;IAEpE,IAAIJ,OAAO,CAACC,GAAG,CAACI,QAAQ,KAAK,MAAM,EAAE;MACnCR,MAAM,CAACS,EAAE,CAAC,SAAS,EAAE,MAAM;QACzBT,MAAM,CAACU,YAAY,CACjB,QAAQ,EACR,CAAC,SAAS,EAAE,GAAGR,OAAO,IAAII,IAAI,IAAIL,IAAI,EAAE,CAAC,EACzCU,GAAG,IAAI;UACL,IAAIA,GAAG,EAAE;YACPC,OAAO,CAACC,KAAK,CAAC,iCAAiCZ,IAAI,GAAG,EAAEU,GAAG,CAAC;UAC9D,CAAC,MAAM;YACLC,OAAO,CAACE,GAAG,CAAC,8BAA8BX,OAAO,CAACY,GAAG,KAAKd,IAAI,GAAG,CAAC;UACpE;QACF,CACF,CAAC;MACH,CAAC,CAAC;IACJ;EACF,CAAC;AACH,CAAC;AAEDe,MAAM,CAACC,OAAO,GAAG;EAAEnB;AAAoB,CAAC","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adalo/metrics",
3
- "version": "0.1.55",
3
+ "version": "0.1.57",
4
4
  "description": "Reusable metrics utilities for Node.js and Laravel apps",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
package/src/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from './metricsClient'
2
2
  export * from './metricsRedisClient'
3
+ export * from './metricsQueueRedisClient'
3
4
  export * from './redisUtils'
@@ -0,0 +1,222 @@
1
+ const Queue = require('bee-queue')
2
+ const { RedisMetricsClient } = require('.')
3
+
4
+ /**
5
+ * QueueRedisMetricsClient extends MetricsClient to collect
6
+ * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
7
+ *
8
+ * @extends RedisMetricsClient
9
+ */
10
+ class QueueRedisMetricsClient extends RedisMetricsClient {
11
+ /**
12
+ * @param {Object} options
13
+ * @param {any} options.redisClient - Redis client instance (required)
14
+ * @param {string} [options.appName] - Application name (from MetricsClient)
15
+ * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
16
+ * @param {string} [options.processType] - Process type (from MetricsClient)
17
+ * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)
18
+ * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)
19
+ * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)
20
+ * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)
21
+ * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)
22
+ * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)
23
+ * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)
24
+ * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
25
+ */
26
+ constructor({ redisClient, metricsConfig = {} } = {}) {
27
+ const getConfiguredQueueNames = () => {
28
+ if (!process.env.METRICS_APP_REDIS_BQ) {
29
+ throw new Error(
30
+ 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'
31
+ )
32
+ }
33
+
34
+ const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')
35
+ .map(q => q.trim())
36
+ .filter(Boolean)
37
+
38
+ if (allQueues.length === 0) {
39
+ throw new Error(
40
+ 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +
41
+ 'Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"'
42
+ )
43
+ }
44
+
45
+ return [...new Set(allQueues)]
46
+ }
47
+
48
+ const startupValidation = () => {
49
+ try {
50
+ const queueNames = getConfiguredQueueNames()
51
+ console.info(
52
+ `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`
53
+ )
54
+ return true
55
+ } catch (error) {
56
+ console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)
57
+ console.error(
58
+ `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`
59
+ )
60
+ console.error(
61
+ `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC="10"`
62
+ )
63
+ console.error(`[queue-metrics] Skipping queue metrics collection`)
64
+ return false
65
+ }
66
+ }
67
+
68
+ super({
69
+ ...metricsConfig,
70
+ redisClient,
71
+ startupValidation,
72
+ })
73
+
74
+ this.getConfiguredQueueNames = getConfiguredQueueNames
75
+ this.startupValidation = startupValidation
76
+
77
+ /** Cache for queue objects to avoid multiple connections */
78
+ this.queueCache = new Map()
79
+
80
+ /** Gauge for queue jobs by status */
81
+ this.queueJobsGauge = this.createGauge({
82
+ name: 'app_queue_jobs_count',
83
+ help: 'Number of app jobs in the queue by status',
84
+ labelNames: this.withDefaultLabels(['queue_name', 'status']),
85
+ })
86
+
87
+ this._setCleanupHandlers()
88
+ }
89
+
90
+ /**
91
+ * Collect metrics for a single Bee Queue and set gauges
92
+ * @param {string} queueName - Name of the queue
93
+ * @returns {Promise<void>}
94
+ */
95
+ collectSingleQueueMetrics = async queueName => {
96
+ try {
97
+ if (!this.queueCache.has(queueName)) {
98
+ this.queueCache.set(
99
+ queueName,
100
+ new Queue(queueName, {
101
+ redis: this.redisClient,
102
+ isWorker: false,
103
+ getEvents: false,
104
+ sendEvents: false,
105
+ })
106
+ )
107
+ }
108
+
109
+ const queue = this.queueCache.get(queueName)
110
+ const health = await queue.checkHealth()
111
+
112
+ const labels = {
113
+ ...this.getDefaultLabels(),
114
+ queue_name: queueName,
115
+ }
116
+
117
+ this.queueJobsGauge.set(
118
+ { ...labels, status: 'waiting' },
119
+ health.waiting || 0
120
+ )
121
+ this.queueJobsGauge.set(
122
+ { ...labels, status: 'active' },
123
+ health.active || 0
124
+ )
125
+ this.queueJobsGauge.set(
126
+ { ...labels, status: 'succeeded' },
127
+ health.succeeded || 0
128
+ )
129
+ this.queueJobsGauge.set(
130
+ { ...labels, status: 'failed' },
131
+ health.failed || 0
132
+ )
133
+ this.queueJobsGauge.set(
134
+ { ...labels, status: 'delayed' },
135
+ health.delayed || 0
136
+ )
137
+ } catch (error) {
138
+ console.warn(
139
+ `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,
140
+ error.message
141
+ )
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Collect metrics for all queues and Redis, then push to Pushgateway
147
+ * @returns {Promise<void>}
148
+ */
149
+ collectQueueMetrics = async () => {
150
+ try {
151
+ const queueNames = this.getConfiguredQueueNames()
152
+
153
+ await this.collectRedisMetrics()
154
+ await Promise.allSettled(
155
+ queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))
156
+ )
157
+
158
+ await this.gatewayPush()
159
+
160
+ if (this.metricsLogValues) {
161
+ const metricObjects = await this.registry.getMetricsAsJSON()
162
+ console.info(
163
+ `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,
164
+ JSON.stringify(metricObjects, null, 2)
165
+ )
166
+ }
167
+ } catch (error) {
168
+ if (
169
+ error.message?.includes('No queues configured') ||
170
+ error.message?.includes('METRICS_APP_REDIS_BQ')
171
+ ) {
172
+ console.error(
173
+ `[queue-metrics] ❌ Configuration error: ${error.message}`
174
+ )
175
+ console.error(
176
+ `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`
177
+ )
178
+ } else {
179
+ console.error(
180
+ `[queue-metrics] Failed to collect queue metrics: ${error.message}`
181
+ )
182
+ }
183
+ throw error
184
+ }
185
+ }
186
+
187
+ /**
188
+ * Start periodic collection.
189
+ * @param {number} [intervalSec=this.intervalSec] - Interval in seconds
190
+ */
191
+ startPush = (intervalSec = this.intervalSec) => {
192
+ this._startPush(intervalSec, () => {
193
+ this.collectQueueMetrics().catch(err => {
194
+ console.error(
195
+ `[queue-metrics] Failed to collect queue & Redis metrics:`,
196
+ err
197
+ )
198
+ })
199
+ })
200
+ }
201
+
202
+ _setCleanupHandlers = () => {
203
+ process.on('SIGINT', this.cleanup)
204
+ process.on('SIGTERM', this.cleanup)
205
+ }
206
+
207
+ /**
208
+ * Cleanup queues and Redis client
209
+ */
210
+ cleanup = async () => {
211
+ for (const [queueName, queue] of this.queueCache) {
212
+ try {
213
+ await queue.close()
214
+ } catch (err) {
215
+ console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)
216
+ }
217
+ }
218
+ process.exit(0)
219
+ }
220
+ }
221
+
222
+ module.exports = { QueueRedisMetricsClient }
@@ -1,89 +1,43 @@
1
- const Queue = require('bee-queue')
2
1
  const { MetricsClient } = require('.')
3
2
 
4
3
  /**
5
4
  * RedisMetricsClient extends MetricsClient to collect
6
- * Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
5
+ * Redis metrics periodically and push them to Prometheus Pushgateway.
7
6
  *
8
7
  * @extends MetricsClient
9
8
  */
10
9
  class RedisMetricsClient extends MetricsClient {
11
10
  /**
12
- * @param {Object} options - Metrics client options + Redis client
11
+ * @param {Object} options
13
12
  * @param {any} options.redisClient - Redis client instance (required)
14
- * @param {Object} [options.metricsConfig] - MetricsClient configuration overrides
13
+ * @param {string} [options.appName] - Application name (from MetricsClient)
14
+ * @param {string} [options.dynoId] - Dyno/instance ID (from MetricsClient)
15
+ * @param {string} [options.processType] - Process type (from MetricsClient)
16
+ * @param {boolean} [options.enabled] - Enable metrics collection (from MetricsClient)
17
+ * @param {boolean} [options.logValues] - Log metrics values (from MetricsClient)
18
+ * @param {string} [options.pushgatewayUrl] - PushGateway URL (from MetricsClient)
19
+ * @param {string} [options.pushgatewaySecret] - PushGateway secret token (from MetricsClient)
20
+ * @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from MetricsClient)
21
+ * @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from MetricsClient)
22
+ * @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation (from MetricsClient)
23
+ * @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
15
24
  */
16
- constructor({ redisClient, metricsConfig = {} } = {}) {
17
- const METRICS_QUEUE_INTERVAL_SEC =
25
+ constructor({ redisClient, ...metricsConfig } = {}) {
26
+ const intervalSec =
18
27
  metricsConfig.intervalSec ||
19
28
  parseInt(process.env.METRICS_QUEUE_INTERVAL_SEC || '', 10) ||
20
29
  5
21
30
 
22
- const getConfiguredQueueNames = () => {
23
- if (!process.env.METRICS_APP_REDIS_BQ) {
24
- throw new Error(
25
- 'No queues configured for monitoring. Set METRICS_APP_REDIS_BQ with comma-separated queue names'
26
- )
27
- }
28
-
29
- const allQueues = process.env.METRICS_APP_REDIS_BQ.split(',')
30
- .map(q => q.trim())
31
- .filter(Boolean)
32
-
33
- if (allQueues.length === 0) {
34
- throw new Error(
35
- 'METRICS_APP_REDIS_BQ is empty or contains only whitespace. ' +
36
- 'Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"'
37
- )
38
- }
39
-
40
- return [...new Set(allQueues)]
41
- }
42
-
43
- const startupValidation = () => {
44
- try {
45
- const queueNames = getConfiguredQueueNames()
46
- console.info(
47
- `[queue-metrics] Queue & Redis metrics collection starting for ${queueNames.length} queues`
48
- )
49
- return true
50
- } catch (error) {
51
- console.error(`[queue-metrics] ❌ Cannot start: ${error.message}`)
52
- console.error(
53
- `[queue-metrics] 💡 Example: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`
54
- )
55
- console.error(
56
- `[queue-metrics] 💡 Optional: METRICS_QUEUE_INTERVAL_SEC="10"`
57
- )
58
- console.error(`[queue-metrics] Skipping queue metrics collection`)
59
- return false
60
- }
61
- }
62
-
63
31
  super({
64
32
  ...metricsConfig,
65
33
  scripDefaultMetrics: true,
66
- processType: metricsConfig.processType || 'queue-metrics',
67
- intervalSec: METRICS_QUEUE_INTERVAL_SEC,
68
- startupValidation,
34
+ processType: metricsConfig.processType || 'redis-metrics',
35
+ intervalSec,
69
36
  })
70
37
 
71
- this.getConfiguredQueueNames = getConfiguredQueueNames
72
- this.startupValidation = startupValidation
73
-
74
- /** Redis client used for queue & Redis metrics */
38
+ /** Redis client used for metrics */
75
39
  this.redisClient = redisClient
76
40
 
77
- /** Cache for queue objects to avoid multiple connections */
78
- this.queueCache = new Map()
79
-
80
- /** Gauge for queue jobs by status */
81
- this.queueJobsGauge = this.createGauge({
82
- name: 'app_queue_jobs_count',
83
- help: 'Number of app jobs in the queue by status',
84
- labelNames: this.withDefaultLabels(['queue_name', 'status']),
85
- })
86
-
87
41
  /** Gauge for Redis client connections */
88
42
  this.redisConnectionsGauge = this.createGauge({
89
43
  name: 'app_redis_connections_count',
@@ -178,98 +132,25 @@ class RedisMetricsClient extends MetricsClient {
178
132
  }
179
133
 
180
134
  /**
181
- * Collect metrics for a single Bee Queue and set gauges
182
- * @param {string} queueName - Name of the queue
135
+ * Collect metrics for all Redis and push to Prometheus Pushgateway
183
136
  * @returns {Promise<void>}
184
137
  */
185
- collectSingleQueueMetrics = async queueName => {
138
+ pushRedisMetrics = async () => {
186
139
  try {
187
- if (!this.queueCache.has(queueName)) {
188
- this.queueCache.set(
189
- queueName,
190
- new Queue(queueName, {
191
- redis: this.redisClient,
192
- isWorker: false,
193
- getEvents: false,
194
- sendEvents: false,
195
- })
196
- )
197
- }
198
-
199
- const queue = this.queueCache.get(queueName)
200
- const health = await queue.checkHealth()
201
-
202
- const labels = {
203
- ...this.getDefaultLabels(),
204
- queue_name: queueName,
205
- }
206
-
207
- this.queueJobsGauge.set(
208
- { ...labels, status: 'waiting' },
209
- health.waiting || 0
210
- )
211
- this.queueJobsGauge.set(
212
- { ...labels, status: 'active' },
213
- health.active || 0
214
- )
215
- this.queueJobsGauge.set(
216
- { ...labels, status: 'succeeded' },
217
- health.succeeded || 0
218
- )
219
- this.queueJobsGauge.set(
220
- { ...labels, status: 'failed' },
221
- health.failed || 0
222
- )
223
- this.queueJobsGauge.set(
224
- { ...labels, status: 'delayed' },
225
- health.delayed || 0
226
- )
227
- } catch (error) {
228
- console.warn(
229
- `[queue-metrics] Failed to collect metrics for queue ${queueName}:`,
230
- error.message
231
- )
232
- }
233
- }
234
-
235
- /**
236
- * Collect metrics for all queues and Redis, then push to Pushgateway
237
- * @returns {Promise<void>}
238
- */
239
- collectQueueMetrics = async () => {
240
- try {
241
- const queueNames = this.getConfiguredQueueNames()
242
-
243
140
  await this.collectRedisMetrics()
244
- await Promise.allSettled(
245
- queueNames.map(queueName => this.collectSingleQueueMetrics(queueName))
246
- )
247
-
248
141
  await this.gatewayPush()
249
142
 
250
143
  if (this.metricsLogValues) {
251
144
  const metricObjects = await this.registry.getMetricsAsJSON()
252
145
  console.info(
253
- `[queue-metrics] Collected metrics for ${queueNames.length} queues:`,
146
+ `[redis-metrics] Collected metrics for Redis`,
254
147
  JSON.stringify(metricObjects, null, 2)
255
148
  )
256
149
  }
257
150
  } catch (error) {
258
- if (
259
- error.message?.includes('No queues configured') ||
260
- error.message?.includes('METRICS_APP_REDIS_BQ')
261
- ) {
262
- console.error(
263
- `[queue-metrics] ❌ Configuration error: ${error.message}`
264
- )
265
- console.error(
266
- `[queue-metrics] 💡 Example config: METRICS_APP_REDIS_BQ="adalo-compile,adalo-migrations"`
267
- )
268
- } else {
269
- console.error(
270
- `[queue-metrics] Failed to collect queue metrics: ${error.message}`
271
- )
272
- }
151
+ console.error(
152
+ `[redis-metrics] Failed to collect Redis metrics: ${error.message}`
153
+ )
273
154
  throw error
274
155
  }
275
156
  }
@@ -280,36 +161,28 @@ class RedisMetricsClient extends MetricsClient {
280
161
  */
281
162
  startPush = (intervalSec = this.intervalSec) => {
282
163
  this._startPush(intervalSec, () => {
283
- this.collectQueueMetrics().catch(err => {
284
- console.error(
285
- `[queue-metrics] Failed to collect queue & Redis metrics:`,
286
- err
287
- )
164
+ this.pushRedisMetrics().catch(err => {
165
+ console.error(`[redis-metrics] Failed to push Redis metrics:`, err)
288
166
  })
289
167
  })
290
168
  }
291
169
 
292
- _setCleanupHandlers = () => {
293
- process.on('SIGINT', this.cleanup)
294
- process.on('SIGTERM', this.cleanup)
295
- }
296
-
297
170
  /**
298
- * Cleanup queues and Redis client
171
+ * Cleanup Redis client
299
172
  */
300
173
  cleanup = async () => {
301
- for (const [queueName, queue] of this.queueCache) {
302
- try {
303
- await queue.close()
304
- } catch (err) {
305
- console.error(`[queue-metrics] Error closing queue ${queueName}:`, err)
306
- }
174
+ try {
175
+ this.redisClient?.quit()
176
+ } catch (err) {
177
+ console.error('[redis-metrics] Error closing Redis client:', err)
307
178
  }
308
-
309
- // Close Redis connection
310
- this.redisClient?.quit()
311
179
  process.exit(0)
312
180
  }
181
+
182
+ _setCleanupHandlers = () => {
183
+ process.on('SIGINT', this.cleanup)
184
+ process.on('SIGTERM', this.cleanup)
185
+ }
313
186
  }
314
187
 
315
188
  module.exports = { RedisMetricsClient }
package/src/redisUtils.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.
5
5
  * @returns {(client: import('redis').RedisClient, name: string) => void}
6
6
  */
7
- export const createSetClientName = (defaultAppName = 'undefined-app') => {
7
+ const createSetClientName = (defaultAppName = 'undefined-app') => {
8
8
  return (client, name) => {
9
9
  const appName = process.env.METRICS_APP_NAME || defaultAppName
10
10
  const dyno = process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined-dyno'
@@ -26,3 +26,5 @@ export const createSetClientName = (defaultAppName = 'undefined-app') => {
26
26
  }
27
27
  }
28
28
  }
29
+
30
+ module.exports = { createSetClientName }
package/tsconfig.json CHANGED
@@ -12,7 +12,6 @@
12
12
  "suppressImplicitAnyIndexErrors": true,
13
13
  "target": "ESNext",
14
14
  "resolveJsonModule": true,
15
- "noEmit": true
16
15
  },
17
16
  "include": ["./src"],
18
17
  "exclude": ["./node_modules"]