@adalo/metrics 0.1.67 → 0.1.68

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.
@@ -5,7 +5,7 @@ const {
5
5
  RedisMetricsClient
6
6
  } = require('.');
7
7
  const {
8
- isIORedis
8
+ IOREDIS
9
9
  } = require('./redisUtils');
10
10
 
11
11
  /**
@@ -87,7 +87,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
87
87
  * @returns {object|any} Redis config object for BeeQueue or Redis client instance
88
88
  */
89
89
  getConfigForDifferentRedis = () => {
90
- if (isIORedis(this.redisClient)) {
90
+ if (this.redisClientType === IOREDIS) {
91
91
  const {
92
92
  host,
93
93
  port,
@@ -1 +1 @@
1
- {"version":3,"file":"metricsQueueRedisClient.js","names":["Queue","require","RedisMetricsClient","isIORedis","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","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","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('.')\nconst { isIORedis } = require('./redisUtils')\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 * 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 (isIORedis(this.redisClient)) {\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\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":[]}
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","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('.')\nconst { IOREDIS } = require('./redisUtils')\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 * 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\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":[]}
@@ -36,6 +36,7 @@ export class RedisMetricsClient extends MetricsClient {
36
36
  });
37
37
  /** Redis client used for metrics */
38
38
  redisClient: any;
39
+ redisClientType: string;
39
40
  /** Gauge for Redis client connections */
40
41
  redisConnectionsGauge: import("prom-client").Gauge<string>;
41
42
  /** Gauge for Redis memory usage */
@@ -1 +1 @@
1
- {"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAGA;;;;;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,6CA2CC;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAyDzB;IAED;;;OAGG;IACH,wBAFa,QAAQ,IAAI,CAAC,CAoBzB;IAED;;;OAGG;IACH,sDAMC;CA2BF"}
1
+ {"version":3,"file":"metricsRedisClient.d.ts","sourceRoot":"","sources":["../src/metricsRedisClient.js"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH;QAbwB,WAAW,EAAxB,GAAG;QACc,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QAChB,mBAAmB;QAClB,iBAAiB;OAyC9C;IA1BC,oCAAoC;IACpC,iBAA8B;IAC9B,wBAAsD;IAEtD,yCAAyC;IACzC,2DAIE;IAEF,mCAAmC;IACnC,sDAIE;IAEF,sCAAsC;IACtC,qDAIE;IAKJ,6CAuBC;IAED;;;OAGG;IACH,2BAFa,QAAQ,IAAI,CAAC,CAyDzB;IAED;;;OAGG;IACH,wBAFa,QAAQ,IAAI,CAAC,CAoBzB;IAED;;;OAGG;IACH,sDAMC;CA4BF"}
@@ -4,7 +4,10 @@ const {
4
4
  MetricsClient
5
5
  } = require('.');
6
6
  const {
7
- isIORedis
7
+ getRedisClientType,
8
+ REDIS_V4,
9
+ IOREDIS,
10
+ REDIS_V3
8
11
  } = require('./redisUtils');
9
12
 
10
13
  /**
@@ -43,6 +46,7 @@ class RedisMetricsClient extends MetricsClient {
43
46
 
44
47
  /** Redis client used for metrics */
45
48
  this.redisClient = redisClient;
49
+ this.redisClientType = getRedisClientType(redisClient);
46
50
 
47
51
  /** Gauge for Redis client connections */
48
52
  this.redisConnectionsGauge = this.createGauge({
@@ -68,23 +72,9 @@ class RedisMetricsClient extends MetricsClient {
68
72
  }
69
73
  getRedisInfo = async section => {
70
74
  if (!this.redisClient) throw new Error('Redis client not provided');
71
- console.log('Redis client constructor name:', this.redisClient.constructor.name);
72
- console.log('Redis client info function:', this.redisClient.info);
73
-
74
- // node-redis ioredis
75
- if (isIORedis(this.redisClient)) {
76
- console.log('Detected node-redis ioredis');
77
- try {
78
- const result = await this.redisClient.info(section);
79
- return result;
80
- } catch (err) {
81
- throw new Error(`Failed to get Redis INFO: ${err.message}`);
82
- }
83
- }
84
75
 
85
76
  // node-redis v3 (uses callback)
86
- if (typeof this.redisClient.send_command === 'function') {
87
- console.log('Detected node-redis v3');
77
+ if (this.redisClientType === REDIS_V3) {
88
78
  return new Promise((resolve, reject) => {
89
79
  this.redisClient.info(section, (err, result) => {
90
80
  if (err) reject(err);else resolve(result);
@@ -93,11 +83,9 @@ class RedisMetricsClient extends MetricsClient {
93
83
  }
94
84
 
95
85
  // node-redis v4 or ioredis (info returns Promise)
96
- if (typeof this.redisClient.info === 'function') {
97
- console.log('Detected node-redis v4');
86
+ if (this.redisClientType === REDIS_V4 || this.redisClientType === IOREDIS) {
98
87
  try {
99
- const result = await this.redisClient.info(section);
100
- return result;
88
+ return this.redisClient.info(section);
101
89
  } catch (err) {
102
90
  throw new Error(`Failed to get Redis INFO: ${err.message}`);
103
91
  }
@@ -183,11 +171,9 @@ class RedisMetricsClient extends MetricsClient {
183
171
  cleanup = async () => {
184
172
  try {
185
173
  if (!this.redisClient) return;
186
- if (typeof this.redisClient.quit === 'function') {
187
- // node-redis v3 or v4
174
+ if (this.redisClientType === REDIS_V3 || this.redisClientType === REDIS_V4) {
188
175
  await this.redisClient.quit();
189
- } else if (typeof this.redisClient.disconnect === 'function') {
190
- // ioredis
176
+ } else if (this.redisClientType === IOREDIS) {
191
177
  await this.redisClient.disconnect();
192
178
  }
193
179
  } catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"metricsRedisClient.js","names":["MetricsClient","require","isIORedis","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","scripDefaultMetrics","processType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","getRedisInfo","section","Error","console","log","info","result","err","message","send_command","Promise","resolve","reject","collectRedisMetrics","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","warn","pushRedisMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const { MetricsClient } = require('.')\nconst { isIORedis } = require('./redisUtils')\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 getRedisInfo = async section => {\n if (!this.redisClient) throw new Error('Redis client not provided')\n\n console.log(\n 'Redis client constructor name:',\n this.redisClient.constructor.name\n )\n console.log('Redis client info function:', this.redisClient.info)\n\n // node-redis ioredis\n if (isIORedis(this.redisClient)) {\n console.log('Detected node-redis ioredis')\n try {\n const result = await this.redisClient.info(section)\n return result\n } catch (err) {\n throw new Error(`Failed to get Redis INFO: ${err.message}`)\n }\n }\n\n // node-redis v3 (uses callback)\n if (typeof this.redisClient.send_command === 'function') {\n console.log('Detected node-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 (typeof this.redisClient.info === 'function') {\n console.log('Detected node-redis v4')\n try {\n const result = await this.redisClient.info(section)\n return result\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 /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const [clientsInfo, memoryInfo, statsInfo] = await Promise.all([\n this.getRedisInfo('clients'),\n this.getRedisInfo('memory'),\n this.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 and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n try {\n if (!this.redisClient) return\n\n if (typeof this.redisClient.quit === 'function') {\n // node-redis v3 or v4\n await this.redisClient.quit()\n } else if (typeof this.redisClient.disconnect === 'function') {\n // ioredis\n await this.redisClient.disconnect()\n }\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":";;AAAA,MAAM;EAAEA;AAAc,CAAC,GAAGC,OAAO,CAAC,GAAG,CAAC;AACtC,MAAM;EAAEC;AAAU,CAAC,GAAGD,OAAO,CAAC,cAAc,CAAC;;AAE7C;AACA;AACA;AACA;AACA;AACA;AACA,MAAME,kBAAkB,SAASH,aAAa,CAAC;EAC7C;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEI,WAAWA,CAAC;IAAEC,WAAW;IAAE,GAAGC;EAAc,CAAC,GAAG,CAAC,CAAC,EAAE;IAClD,MAAMC,WAAW,GACfD,aAAa,CAACC,WAAW,IACzBC,QAAQ,CAACC,OAAO,CAACC,GAAG,CAACC,0BAA0B,IAAI,EAAE,EAAE,EAAE,CAAC,IAC1D,CAAC;IAEH,KAAK,CAAC;MACJ,GAAGL,aAAa;MAChBM,mBAAmB,EAAE,IAAI;MACzBC,WAAW,EAAEP,aAAa,CAACO,WAAW,IAAI,eAAe;MACzDN;IACF,CAAC,CAAC;;IAEF;IACA,IAAI,CAACF,WAAW,GAAGA,WAAW;;IAE9B;IACA,IAAI,CAACS,qBAAqB,GAAG,IAAI,CAACC,WAAW,CAAC;MAC5CC,IAAI,EAAE,6BAA6B;MACnCC,IAAI,EAAE,oCAAoC;MAC1CC,UAAU,EAAE,IAAI,CAACC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC;IACxD,CAAC,CAAC;;IAEF;IACA,IAAI,CAACC,gBAAgB,GAAG,IAAI,CAACL,WAAW,CAAC;MACvCC,IAAI,EAAE,wBAAwB;MAC9BC,IAAI,EAAE,6BAA6B;MACnCC,UAAU,EAAE,IAAI,CAACC,iBAAiB,CAAC,CAAC,aAAa,CAAC;IACpD,CAAC,CAAC;;IAEF;IACA,IAAI,CAACE,eAAe,GAAG,IAAI,CAACN,WAAW,CAAC;MACtCC,IAAI,EAAE,uBAAuB;MAC7BC,IAAI,EAAE,4BAA4B;MAClCC,UAAU,EAAE,IAAI,CAACC,iBAAiB,CAAC,CAAC,WAAW,CAAC;IAClD,CAAC,CAAC;IAEF,IAAI,CAACG,mBAAmB,CAAC,CAAC;EAC5B;EAEAC,YAAY,GAAG,MAAMC,OAAO,IAAI;IAC9B,IAAI,CAAC,IAAI,CAACnB,WAAW,EAAE,MAAM,IAAIoB,KAAK,CAAC,2BAA2B,CAAC;IAEnEC,OAAO,CAACC,GAAG,CACT,gCAAgC,EAChC,IAAI,CAACtB,WAAW,CAACD,WAAW,CAACY,IAC/B,CAAC;IACDU,OAAO,CAACC,GAAG,CAAC,6BAA6B,EAAE,IAAI,CAACtB,WAAW,CAACuB,IAAI,CAAC;;IAEjE;IACA,IAAI1B,SAAS,CAAC,IAAI,CAACG,WAAW,CAAC,EAAE;MAC/BqB,OAAO,CAACC,GAAG,CAAC,6BAA6B,CAAC;MAC1C,IAAI;QACF,MAAME,MAAM,GAAG,MAAM,IAAI,CAACxB,WAAW,CAACuB,IAAI,CAACJ,OAAO,CAAC;QACnD,OAAOK,MAAM;MACf,CAAC,CAAC,OAAOC,GAAG,EAAE;QACZ,MAAM,IAAIL,KAAK,CAAC,6BAA6BK,GAAG,CAACC,OAAO,EAAE,CAAC;MAC7D;IACF;;IAEA;IACA,IAAI,OAAO,IAAI,CAAC1B,WAAW,CAAC2B,YAAY,KAAK,UAAU,EAAE;MACvDN,OAAO,CAACC,GAAG,CAAC,wBAAwB,CAAC;MACrC,OAAO,IAAIM,OAAO,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;QACtC,IAAI,CAAC9B,WAAW,CAACuB,IAAI,CAACJ,OAAO,EAAE,CAACM,GAAG,EAAED,MAAM,KAAK;UAC9C,IAAIC,GAAG,EAAEK,MAAM,CAACL,GAAG,CAAC,MACfI,OAAO,CAACL,MAAM,CAAC;QACtB,CAAC,CAAC;MACJ,CAAC,CAAC;IACJ;;IAEA;IACA,IAAI,OAAO,IAAI,CAACxB,WAAW,CAACuB,IAAI,KAAK,UAAU,EAAE;MAC/CF,OAAO,CAACC,GAAG,CAAC,wBAAwB,CAAC;MACrC,IAAI;QACF,MAAME,MAAM,GAAG,MAAM,IAAI,CAACxB,WAAW,CAACuB,IAAI,CAACJ,OAAO,CAAC;QACnD,OAAOK,MAAM;MACf,CAAC,CAAC,OAAOC,GAAG,EAAE;QACZ,MAAM,IAAIL,KAAK,CAAC,6BAA6BK,GAAG,CAACC,OAAO,EAAE,CAAC;MAC7D;IACF;IAEA,MAAM,IAAIN,KAAK,CAAC,+BAA+B,CAAC;EAClD,CAAC;;EAED;AACF;AACA;AACA;EACEW,mBAAmB,GAAG,MAAAA,CAAA,KAAY;IAChC,IAAI;MACF,MAAM,CAACC,WAAW,EAAEC,UAAU,EAAEC,SAAS,CAAC,GAAG,MAAMN,OAAO,CAACO,GAAG,CAAC,CAC7D,IAAI,CAACjB,YAAY,CAAC,SAAS,CAAC,EAC5B,IAAI,CAACA,YAAY,CAAC,QAAQ,CAAC,EAC3B,IAAI,CAACA,YAAY,CAAC,OAAO,CAAC,CAC3B,CAAC;MAEF,MAAMkB,MAAM,GAAG,IAAI,CAACC,gBAAgB,CAAC,CAAC;MAEtC,MAAMC,cAAc,GAAGC,OAAO,IAC5BC,MAAM,CAACC,WAAW,CAChBF,OAAO,CACJG,KAAK,CAAC,MAAM,CAAC,CACbC,MAAM,CAACC,IAAI,IAAIA,IAAI,IAAI,CAACA,IAAI,CAACC,UAAU,CAAC,GAAG,CAAC,CAAC,CAC7CC,GAAG,CAACF,IAAI,IAAIA,IAAI,CAACF,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAC/BC,MAAM,CAACI,KAAK,IAAIA,KAAK,CAACC,MAAM,KAAK,CAAC,IAAID,KAAK,CAAC,CAAC,CAAC,IAAIA,KAAK,CAAC,CAAC,CAAC,CAC/D,CAAC;MAEH,MAAME,OAAO,GAAGX,cAAc,CAACN,WAAW,CAAC;MAC3C,MAAMkB,MAAM,GAAGZ,cAAc,CAACL,UAAU,CAAC;MACzC,MAAMkB,KAAK,GAAGb,cAAc,CAACJ,SAAS,CAAC;MAEvC,IAAIe,OAAO,CAACG,iBAAiB,EAAE;QAC7B,IAAI,CAAC3C,qBAAqB,CAAC4C,GAAG,CAC5B;UAAE,GAAGjB,MAAM;UAAEkB,eAAe,EAAE;QAAY,CAAC,EAC3CnD,QAAQ,CAAC8C,OAAO,CAACG,iBAAiB,EAAE,EAAE,CAAC,IAAI,CAC7C,CAAC;MACH;MAEA,IAAIF,MAAM,CAACK,WAAW,EAAE;QACtB,IAAI,CAACxC,gBAAgB,CAACsC,GAAG,CACvB;UAAE,GAAGjB,MAAM;UAAEoB,WAAW,EAAE;QAAO,CAAC,EAClCrD,QAAQ,CAAC+C,MAAM,CAACK,WAAW,EAAE,EAAE,CAAC,IAAI,CACtC,CAAC;MACH;MACA,IAAIL,MAAM,CAACO,SAAS,EAAE;QACpB,IAAI,CAAC1C,gBAAgB,CAACsC,GAAG,CACvB;UAAE,GAAGjB,MAAM;UAAEoB,WAAW,EAAE;QAAM,CAAC,EACjCrD,QAAQ,CAAC+C,MAAM,CAACO,SAAS,EAAE,EAAE,CAAC,IAAI,CACpC,CAAC;MACH;MAEA,IAAIN,KAAK,CAACO,yBAAyB,EAAE;QACnC,IAAI,CAAC1C,eAAe,CAACqC,GAAG,CACtB;UAAE,GAAGjB,MAAM;UAAEuB,SAAS,EAAE;QAAc,CAAC,EACvCxD,QAAQ,CAACgD,KAAK,CAACO,yBAAyB,EAAE,EAAE,CAAC,IAAI,CACnD,CAAC;MACH;IACF,CAAC,CAAC,OAAOE,KAAK,EAAE;MACdvC,OAAO,CAACwC,IAAI,CACV,kDAAkD,EAClDD,KAAK,CAAClC,OACR,CAAC;IACH;EACF,CAAC;;EAED;AACF;AACA;AACA;EACEoC,gBAAgB,GAAG,MAAAA,CAAA,KAAY;IAC7B,IAAI;MACF,MAAM,IAAI,CAAC/B,mBAAmB,CAAC,CAAC;MAChC,MAAM,IAAI,CAACgC,WAAW,CAAC,CAAC;MAExB,IAAI,IAAI,CAACC,gBAAgB,EAAE;QACzB,MAAMC,aAAa,GAAG,MAAM,IAAI,CAACC,QAAQ,CAACC,gBAAgB,CAAC,CAAC;QAC5D9C,OAAO,CAACE,IAAI,CACV,6CAA6C,EAC7C6C,IAAI,CAACC,SAAS,CAACJ,aAAa,EAAE,IAAI,EAAE,CAAC,CACvC,CAAC;MACH;IACF,CAAC,CAAC,OAAOL,KAAK,EAAE;MACdvC,OAAO,CAACuC,KAAK,CACX,oDAAoDA,KAAK,CAAClC,OAAO,EACnE,CAAC;MACD,MAAMkC,KAAK;IACb;EACF,CAAC;;EAED;AACF;AACA;AACA;EACEU,SAAS,GAAGA,CAACpE,WAAW,GAAG,IAAI,CAACA,WAAW,KAAK;IAC9C,IAAI,CAACqE,UAAU,CAACrE,WAAW,EAAE,MAAM;MACjC,IAAI,CAAC4D,gBAAgB,CAAC,CAAC,CAACU,KAAK,CAAC/C,GAAG,IAAI;QACnCJ,OAAO,CAACuC,KAAK,CAAC,+CAA+C,EAAEnC,GAAG,CAAC;MACrE,CAAC,CAAC;IACJ,CAAC,CAAC;EACJ,CAAC;;EAED;AACF;AACA;AACA;EACEgD,OAAO,GAAG,MAAAA,CAAA,KAAY;IACpB,IAAI;MACF,IAAI,CAAC,IAAI,CAACzE,WAAW,EAAE;MAEvB,IAAI,OAAO,IAAI,CAACA,WAAW,CAAC0E,IAAI,KAAK,UAAU,EAAE;QAC/C;QACA,MAAM,IAAI,CAAC1E,WAAW,CAAC0E,IAAI,CAAC,CAAC;MAC/B,CAAC,MAAM,IAAI,OAAO,IAAI,CAAC1E,WAAW,CAAC2E,UAAU,KAAK,UAAU,EAAE;QAC5D;QACA,MAAM,IAAI,CAAC3E,WAAW,CAAC2E,UAAU,CAAC,CAAC;MACrC;IACF,CAAC,CAAC,OAAOlD,GAAG,EAAE;MACZJ,OAAO,CAACuC,KAAK,CAAC,6CAA6C,EAAEnC,GAAG,CAAC;IACnE;IACArB,OAAO,CAACwE,IAAI,CAAC,CAAC,CAAC;EACjB,CAAC;EAED3D,mBAAmB,GAAGA,CAAA,KAAM;IAC1Bb,OAAO,CAACyE,EAAE,CAAC,QAAQ,EAAE,IAAI,CAACJ,OAAO,CAAC;IAClCrE,OAAO,CAACyE,EAAE,CAAC,SAAS,EAAE,IAAI,CAACJ,OAAO,CAAC;EACrC,CAAC;AACH;AAEAK,MAAM,CAACC,OAAO,GAAG;EAAEjF;AAAmB,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"metricsRedisClient.js","names":["MetricsClient","require","getRedisClientType","REDIS_V4","IOREDIS","REDIS_V3","RedisMetricsClient","constructor","redisClient","metricsConfig","intervalSec","parseInt","process","env","METRICS_QUEUE_INTERVAL_SEC","scripDefaultMetrics","processType","redisClientType","redisConnectionsGauge","createGauge","name","help","labelNames","withDefaultLabels","redisMemoryGauge","redisStatsGauge","_setCleanupHandlers","getRedisInfo","section","Error","Promise","resolve","reject","info","err","result","message","collectRedisMetrics","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","pushRedisMetrics","gatewayPush","metricsLogValues","metricObjects","registry","getMetricsAsJSON","JSON","stringify","startPush","_startPush","catch","cleanup","quit","disconnect","exit","on","module","exports"],"sources":["../src/metricsRedisClient.js"],"sourcesContent":["const { MetricsClient } = require('.')\nconst {\n getRedisClientType,\n REDIS_V4,\n IOREDIS,\n REDIS_V3,\n} = require('./redisUtils')\n\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 this.redisClientType = getRedisClientType(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 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 /**\n * Collect basic Redis INFO metrics: clients, memory, stats\n * @returns {Promise<void>}\n */\n collectRedisMetrics = async () => {\n try {\n const [clientsInfo, memoryInfo, statsInfo] = await Promise.all([\n this.getRedisInfo('clients'),\n this.getRedisInfo('memory'),\n this.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 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('[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":[]}
@@ -26,4 +26,14 @@ export function createSetClientNameForIoredis(defaultAppName?: string | undefine
26
26
  * @returns {boolean} True if the client is ioredis
27
27
  */
28
28
  export function isIORedis(client: any): boolean;
29
+ /**
30
+ * Get Redis client type
31
+ *
32
+ * @param {any} client - Redis client instance
33
+ * @returns {string} One of IOREDIS, REDIS_V3, REDIS_V4
34
+ */
35
+ export function getRedisClientType(client: any): string;
36
+ export const REDIS_V4: "REDIS_V4";
37
+ export const REDIS_V3: "REDIS_V3";
38
+ export const IOREDIS: "IOREDIS";
29
39
  //# sourceMappingURL=redisUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"redisUtils.d.ts","sourceRoot":"","sources":["../src/redisUtils.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAuB/C;AA4BD;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAsB/C;AApDD;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAoB/C;AA8BD;;;;;GAKG;AACH,kCAHW,GAAG,GACD,OAAO,CAiBnB"}
1
+ {"version":3,"file":"redisUtils.d.ts","sourceRoot":"","sources":["../src/redisUtils.js"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAuB/C;AA4BD;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAsB/C;AApDD;;;;;GAKG;AACH,6FAFsB,GAAG,QAAQ,MAAM,KAAK,IAAI,CAoB/C;AA8BD;;;;;GAKG;AACH,kCAHW,GAAG,GACD,OAAO,CASnB;AAED;;;;;GAKG;AACH,2CAHW,GAAG,GACD,MAAM,CAiBlB;AA3HD,kCAA2B;AAC3B,kCAA2B;AAC3B,gCAAyB"}
package/lib/redisUtils.js CHANGED
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ const REDIS_V4 = 'REDIS_V4';
4
+ const REDIS_V3 = 'REDIS_V3';
5
+ const IOREDIS = 'IOREDIS';
6
+
3
7
  /**
4
8
  * Creates a configured setClientName function for node-redis v3.
5
9
  *
@@ -76,20 +80,38 @@ const createSetClientNameForRedisV4 = (defaultAppName = 'undefined-app') => {
76
80
  * @returns {boolean} True if the client is ioredis
77
81
  */
78
82
  const isIORedis = client => {
79
- const result = client && typeof client.sendCommand === 'function' && typeof client.disconnect === 'function' && client.options !== undefined;
80
- console.log('[debug] isIORedis client.sendCommand:', client.sendCommand);
81
- console.log('[debug] isIORedis client.sendCommand === \'function\':', typeof client.sendCommand === 'function');
82
- console.log('[debug] isIORedis client.disconnect:', client.disconnect);
83
- console.log('[debug] isIORedis client.disconnect === \'function\':', typeof client.disconnect === 'function');
84
- console.log('[debug] isIORedis client.options:', client.options);
85
- console.log('[debug] isIORedis client.options !== undefined:', client.options !== undefined);
86
- console.log('[debug] isIORedis check:', result, 'constructor:', client?.constructor?.name);
87
- return result;
83
+ return client && typeof client.sendCommand === 'function' && typeof client.disconnect === 'function' && client.options !== undefined;
84
+ };
85
+
86
+ /**
87
+ * Get Redis client type
88
+ *
89
+ * @param {any} client - Redis client instance
90
+ * @returns {string} One of IOREDIS, REDIS_V3, REDIS_V4
91
+ */
92
+ const getRedisClientType = client => {
93
+ if (isIORedis(client)) {
94
+ console.log('Detected node-redis ioredis');
95
+ return IOREDIS;
96
+ }
97
+ if (typeof client?.send_command === 'function') {
98
+ console.log('Detected node-redis redis_v3');
99
+ return REDIS_V3;
100
+ }
101
+ if (typeof client.info === 'function') {
102
+ console.log('Detected node-redis redis_v4');
103
+ return REDIS_V4;
104
+ }
105
+ throw new Error(`Failed to get Redis client type`);
88
106
  };
89
107
  module.exports = {
90
108
  createSetClientNameForRedisV3,
91
109
  createSetClientNameForRedisV4,
92
110
  createSetClientNameForIoredis,
93
- isIORedis
111
+ isIORedis,
112
+ getRedisClientType,
113
+ REDIS_V4,
114
+ REDIS_V3,
115
+ IOREDIS
94
116
  };
95
117
  //# sourceMappingURL=redisUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redisUtils.js","names":["createSetClientNameForRedisV3","defaultAppName","client","name","appName","process","env","METRICS_APP_NAME","dyno","BUILD_DYNO_PROCESS_TYPE","NODE_ENV","on","send_command","err","console","error","log","pid","createSetClientNameForIoredis","once","call","then","catch","createSetClientNameForRedisV4","sendCommand","isIORedis","result","disconnect","options","undefined","constructor","module","exports"],"sources":["../src/redisUtils.js"],"sourcesContent":["/**\n * Creates a configured setClientName function for node-redis v3.\n *\n * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForRedisV3 = (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\n/**\n * Creates a function to set Redis client name for ioredis.\n *\n * @param {string} [defaultAppName='undefined-app']\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForIoredis = (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.once('connect', () => {\n client\n .call('CLIENT', ['SETNAME', `${appName}:${dyno}:${name}`])\n .then(() => {\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n })\n .catch(err => {\n console.error(`Failed to set client name for ${name}:`, err)\n })\n })\n }\n }\n}\n\n/**\n * Creates a function to set Redis client name for node-redis v4.\n *\n * @param {string} [defaultAppName='undefined-app']\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForRedisV4 = (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('ready', async () => {\n try {\n await client.sendCommand([\n 'CLIENT',\n 'SETNAME',\n `${appName}:${dyno}:${name}`,\n ])\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n } catch (err) {\n console.error(`Failed to set client name for ${name}:`, err)\n }\n })\n }\n }\n}\n\n/**\n * Check if a Redis client is an ioredis instance\n *\n * @param {any} client - Redis client instance\n * @returns {boolean} True if the client is ioredis\n */\nconst isIORedis = client => {\n const result =\n client &&\n typeof client.sendCommand === 'function' &&\n typeof client.disconnect === 'function' &&\n client.options !== undefined;\n console.log('[debug] isIORedis client.sendCommand:', client.sendCommand);\n console.log('[debug] isIORedis client.sendCommand === \\'function\\':', typeof client.sendCommand === 'function');\n console.log('[debug] isIORedis client.disconnect:', client.disconnect);\n console.log('[debug] isIORedis client.disconnect === \\'function\\':', typeof client.disconnect === 'function');\n console.log('[debug] isIORedis client.options:', client.options);\n console.log('[debug] isIORedis client.options !== undefined:', client.options !== undefined);\n\n console.log('[debug] isIORedis check:', result, 'constructor:', client?.constructor?.name);\n return result;\n};\n\nmodule.exports = {\n createSetClientNameForRedisV3,\n createSetClientNameForRedisV4,\n createSetClientNameForIoredis,\n isIORedis,\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"redisUtils.js","names":["REDIS_V4","REDIS_V3","IOREDIS","createSetClientNameForRedisV3","defaultAppName","client","name","appName","process","env","METRICS_APP_NAME","dyno","BUILD_DYNO_PROCESS_TYPE","NODE_ENV","on","send_command","err","console","error","log","pid","createSetClientNameForIoredis","once","call","then","catch","createSetClientNameForRedisV4","sendCommand","isIORedis","disconnect","options","undefined","getRedisClientType","info","Error","module","exports"],"sources":["../src/redisUtils.js"],"sourcesContent":["const REDIS_V4 = 'REDIS_V4'\nconst REDIS_V3 = 'REDIS_V3'\nconst IOREDIS = 'IOREDIS'\n\n/**\n * Creates a configured setClientName function for node-redis v3.\n *\n * @param {string} [defaultAppName='undefined-app'] - Fallback app name if METRICS_APP_NAME is not set.\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForRedisV3 = (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\n/**\n * Creates a function to set Redis client name for ioredis.\n *\n * @param {string} [defaultAppName='undefined-app']\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForIoredis = (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.once('connect', () => {\n client\n .call('CLIENT', ['SETNAME', `${appName}:${dyno}:${name}`])\n .then(() => {\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n })\n .catch(err => {\n console.error(`Failed to set client name for ${name}:`, err)\n })\n })\n }\n }\n}\n\n/**\n * Creates a function to set Redis client name for node-redis v4.\n *\n * @param {string} [defaultAppName='undefined-app']\n * @returns {(client: any, name: string) => void}\n */\nconst createSetClientNameForRedisV4 = (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('ready', async () => {\n try {\n await client.sendCommand([\n 'CLIENT',\n 'SETNAME',\n `${appName}:${dyno}:${name}`,\n ])\n console.log(`Connected to Redis for pid:${process.pid} (${name})`)\n } catch (err) {\n console.error(`Failed to set client name for ${name}:`, err)\n }\n })\n }\n }\n}\n\n/**\n * Check if a Redis client is an ioredis instance\n *\n * @param {any} client - Redis client instance\n * @returns {boolean} True if the client is ioredis\n */\nconst isIORedis = client => {\n return (\n client &&\n typeof client.sendCommand === 'function' &&\n typeof client.disconnect === 'function' &&\n client.options !== undefined\n )\n}\n\n/**\n * Get Redis client type\n *\n * @param {any} client - Redis client instance\n * @returns {string} One of IOREDIS, REDIS_V3, REDIS_V4\n */\nconst getRedisClientType = client => {\n if (isIORedis(client)) {\n console.log('Detected node-redis ioredis')\n return IOREDIS\n }\n if (typeof client?.send_command === 'function') {\n console.log('Detected node-redis redis_v3')\n return REDIS_V3\n }\n if (typeof client.info === 'function') {\n console.log('Detected node-redis redis_v4')\n return REDIS_V4\n }\n\n throw new Error(`Failed to get Redis client type`)\n}\n\nmodule.exports = {\n createSetClientNameForRedisV3,\n createSetClientNameForRedisV4,\n createSetClientNameForIoredis,\n isIORedis,\n getRedisClientType,\n REDIS_V4,\n REDIS_V3,\n IOREDIS,\n}\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adalo/metrics",
3
- "version": "0.1.67",
3
+ "version": "0.1.68",
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",
@@ -1,6 +1,6 @@
1
1
  const Queue = require('bee-queue')
2
2
  const { RedisMetricsClient } = require('.')
3
- const { isIORedis } = require('./redisUtils')
3
+ const { IOREDIS } = require('./redisUtils')
4
4
 
5
5
  /**
6
6
  * QueueRedisMetricsClient extends MetricsClient to collect
@@ -98,7 +98,7 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
98
98
  * @returns {object|any} Redis config object for BeeQueue or Redis client instance
99
99
  */
100
100
  getConfigForDifferentRedis = () => {
101
- if (isIORedis(this.redisClient)) {
101
+ if (this.redisClientType === IOREDIS) {
102
102
  const { host, port, db, password } = this.redisClient.options
103
103
  return { host, port, db, password }
104
104
  }
@@ -1,5 +1,10 @@
1
1
  const { MetricsClient } = require('.')
2
- const { isIORedis } = require('./redisUtils')
2
+ const {
3
+ getRedisClientType,
4
+ REDIS_V4,
5
+ IOREDIS,
6
+ REDIS_V3,
7
+ } = require('./redisUtils')
3
8
 
4
9
  /**
5
10
  * RedisMetricsClient extends MetricsClient to collect
@@ -38,6 +43,7 @@ class RedisMetricsClient extends MetricsClient {
38
43
 
39
44
  /** Redis client used for metrics */
40
45
  this.redisClient = redisClient
46
+ this.redisClientType = getRedisClientType(redisClient)
41
47
 
42
48
  /** Gauge for Redis client connections */
43
49
  this.redisConnectionsGauge = this.createGauge({
@@ -66,26 +72,8 @@ class RedisMetricsClient extends MetricsClient {
66
72
  getRedisInfo = async section => {
67
73
  if (!this.redisClient) throw new Error('Redis client not provided')
68
74
 
69
- console.log(
70
- 'Redis client constructor name:',
71
- this.redisClient.constructor.name
72
- )
73
- console.log('Redis client info function:', this.redisClient.info)
74
-
75
- // node-redis ioredis
76
- if (isIORedis(this.redisClient)) {
77
- console.log('Detected node-redis ioredis')
78
- try {
79
- const result = await this.redisClient.info(section)
80
- return result
81
- } catch (err) {
82
- throw new Error(`Failed to get Redis INFO: ${err.message}`)
83
- }
84
- }
85
-
86
75
  // node-redis v3 (uses callback)
87
- if (typeof this.redisClient.send_command === 'function') {
88
- console.log('Detected node-redis v3')
76
+ if (this.redisClientType === REDIS_V3) {
89
77
  return new Promise((resolve, reject) => {
90
78
  this.redisClient.info(section, (err, result) => {
91
79
  if (err) reject(err)
@@ -95,11 +83,9 @@ class RedisMetricsClient extends MetricsClient {
95
83
  }
96
84
 
97
85
  // node-redis v4 or ioredis (info returns Promise)
98
- if (typeof this.redisClient.info === 'function') {
99
- console.log('Detected node-redis v4')
86
+ if (this.redisClientType === REDIS_V4 || this.redisClientType === IOREDIS) {
100
87
  try {
101
- const result = await this.redisClient.info(section)
102
- return result
88
+ return this.redisClient.info(section)
103
89
  } catch (err) {
104
90
  throw new Error(`Failed to get Redis INFO: ${err.message}`)
105
91
  }
@@ -213,11 +199,12 @@ class RedisMetricsClient extends MetricsClient {
213
199
  try {
214
200
  if (!this.redisClient) return
215
201
 
216
- if (typeof this.redisClient.quit === 'function') {
217
- // node-redis v3 or v4
202
+ if (
203
+ this.redisClientType === REDIS_V3 ||
204
+ this.redisClientType === REDIS_V4
205
+ ) {
218
206
  await this.redisClient.quit()
219
- } else if (typeof this.redisClient.disconnect === 'function') {
220
- // ioredis
207
+ } else if (this.redisClientType === IOREDIS) {
221
208
  await this.redisClient.disconnect()
222
209
  }
223
210
  } catch (err) {
package/src/redisUtils.js CHANGED
@@ -1,3 +1,7 @@
1
+ const REDIS_V4 = 'REDIS_V4'
2
+ const REDIS_V3 = 'REDIS_V3'
3
+ const IOREDIS = 'IOREDIS'
4
+
1
5
  /**
2
6
  * Creates a configured setClientName function for node-redis v3.
3
7
  *
@@ -88,25 +92,44 @@ const createSetClientNameForRedisV4 = (defaultAppName = 'undefined-app') => {
88
92
  * @returns {boolean} True if the client is ioredis
89
93
  */
90
94
  const isIORedis = client => {
91
- const result =
95
+ return (
92
96
  client &&
93
97
  typeof client.sendCommand === 'function' &&
94
98
  typeof client.disconnect === 'function' &&
95
- client.options !== undefined;
96
- console.log('[debug] isIORedis client.sendCommand:', client.sendCommand);
97
- console.log('[debug] isIORedis client.sendCommand === \'function\':', typeof client.sendCommand === 'function');
98
- console.log('[debug] isIORedis client.disconnect:', client.disconnect);
99
- console.log('[debug] isIORedis client.disconnect === \'function\':', typeof client.disconnect === 'function');
100
- console.log('[debug] isIORedis client.options:', client.options);
101
- console.log('[debug] isIORedis client.options !== undefined:', client.options !== undefined);
99
+ client.options !== undefined
100
+ )
101
+ }
102
102
 
103
- console.log('[debug] isIORedis check:', result, 'constructor:', client?.constructor?.name);
104
- return result;
105
- };
103
+ /**
104
+ * Get Redis client type
105
+ *
106
+ * @param {any} client - Redis client instance
107
+ * @returns {string} One of IOREDIS, REDIS_V3, REDIS_V4
108
+ */
109
+ const getRedisClientType = client => {
110
+ if (isIORedis(client)) {
111
+ console.log('Detected node-redis ioredis')
112
+ return IOREDIS
113
+ }
114
+ if (typeof client?.send_command === 'function') {
115
+ console.log('Detected node-redis redis_v3')
116
+ return REDIS_V3
117
+ }
118
+ if (typeof client.info === 'function') {
119
+ console.log('Detected node-redis redis_v4')
120
+ return REDIS_V4
121
+ }
122
+
123
+ throw new Error(`Failed to get Redis client type`)
124
+ }
106
125
 
107
126
  module.exports = {
108
127
  createSetClientNameForRedisV3,
109
128
  createSetClientNameForRedisV4,
110
129
  createSetClientNameForIoredis,
111
130
  isIORedis,
131
+ getRedisClientType,
132
+ REDIS_V4,
133
+ REDIS_V3,
134
+ IOREDIS,
112
135
  }