@adalo/metrics 0.1.113 → 0.1.115
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/baseMetricsClient.d.ts +171 -0
- package/lib/baseMetricsClient.d.ts.map +1 -0
- package/lib/baseMetricsClient.js +353 -0
- package/lib/baseMetricsClient.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +11 -0
- package/lib/index.js.map +1 -1
- package/lib/metricsClient.d.ts +11 -169
- package/lib/metricsClient.d.ts.map +1 -1
- package/lib/metricsClient.js +80 -350
- package/lib/metricsClient.js.map +1 -1
- package/lib/metricsDatabaseClient.d.ts +10 -12
- package/lib/metricsDatabaseClient.d.ts.map +1 -1
- package/lib/metricsDatabaseClient.js +11 -13
- package/lib/metricsDatabaseClient.js.map +1 -1
- package/lib/metricsQueueRedisClient.d.ts +1 -1
- package/lib/metricsQueueRedisClient.d.ts.map +1 -1
- package/lib/metricsQueueRedisClient.js +11 -12
- package/lib/metricsQueueRedisClient.js.map +1 -1
- package/lib/metricsRedisClient.d.ts +14 -16
- package/lib/metricsRedisClient.d.ts.map +1 -1
- package/lib/metricsRedisClient.js +21 -23
- package/lib/metricsRedisClient.js.map +1 -1
- package/package.json +1 -1
- package/src/baseMetricsClient.js +411 -0
- package/src/index.ts +1 -0
- package/src/metricsClient.js +82 -412
- package/src/metricsDatabaseClient.js +10 -12
- package/src/metricsQueueRedisClient.js +11 -12
- package/src/metricsRedisClient.js +17 -23
package/src/metricsClient.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
const client = require('prom-client')
|
|
2
1
|
const fs = require('fs')
|
|
3
2
|
const os = require('os')
|
|
4
|
-
const
|
|
3
|
+
const { BaseMetricsClient } = require('./baseMetricsClient')
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* MetricsClient handles Prometheus metrics collection and push.
|
|
8
7
|
* Supports gauges, counters, default metrics, and custom metrics.
|
|
8
|
+
* Extends BaseMetricsClient for common functionality.
|
|
9
9
|
*/
|
|
10
|
-
class MetricsClient {
|
|
10
|
+
class MetricsClient extends BaseMetricsClient {
|
|
11
11
|
/**
|
|
12
12
|
* @param {Object} config
|
|
13
13
|
* @param {string} [config.appName] Name of the application
|
|
@@ -19,62 +19,17 @@ class MetricsClient {
|
|
|
19
19
|
* @param {string} [config.pushgatewaySecret] PushGateway secret token
|
|
20
20
|
* @param {number} [config.intervalSec] Interval in seconds for pushing metrics
|
|
21
21
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
22
|
-
* @param {boolean} [config.scripDefaultMetrics] Enable to scip default metrics creation
|
|
23
22
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
24
23
|
*/
|
|
25
24
|
constructor(config = {}) {
|
|
26
|
-
|
|
27
|
-
this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno'
|
|
28
|
-
this.processType =
|
|
29
|
-
config.processType ||
|
|
30
|
-
process.env.BUILD_DYNO_PROCESS_TYPE ||
|
|
31
|
-
'undefined_build_dyno_type'
|
|
32
|
-
this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true'
|
|
33
|
-
this.logValues =
|
|
34
|
-
config.logValues ?? process.env.METRICS_LOG_VALUES === 'true'
|
|
35
|
-
this.pushgatewayUrl =
|
|
36
|
-
config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || ''
|
|
37
|
-
this.authToken =
|
|
38
|
-
config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || ''
|
|
39
|
-
this.intervalSec =
|
|
40
|
-
config.intervalSec ||
|
|
41
|
-
parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||
|
|
42
|
-
15
|
|
43
|
-
this.startupValidation = config.startupValidation
|
|
44
|
-
|
|
45
|
-
this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`
|
|
46
|
-
|
|
47
|
-
this._registry = new client.Registry()
|
|
48
|
-
client.collectDefaultMetrics({ register: this._registry })
|
|
49
|
-
|
|
50
|
-
this.defaultLabels = {
|
|
51
|
-
app: this.appName,
|
|
52
|
-
dyno_id: this.dynoId,
|
|
53
|
-
process_type: this.processType,
|
|
54
|
-
}
|
|
25
|
+
super(config)
|
|
55
26
|
|
|
56
|
-
this.gateway = new client.Pushgateway(
|
|
57
|
-
this.pushgatewayUrl,
|
|
58
|
-
{
|
|
59
|
-
headers: { Authorization: `Basic ${this.authToken}` },
|
|
60
|
-
agent: new https.Agent({ keepAlive: true }),
|
|
61
|
-
},
|
|
62
|
-
this._registry
|
|
63
|
-
)
|
|
64
|
-
this.gauges = {}
|
|
65
|
-
this.counters = {}
|
|
66
|
-
this.countersFunctions = {}
|
|
67
|
-
|
|
68
|
-
/** @type {Object<string, function(): number | Promise<number>>} */
|
|
69
|
-
this.gaugeUpdaters = {}
|
|
70
27
|
this._lastUsageMicros = 0
|
|
71
28
|
this._lastCheckTime = Date.now()
|
|
72
29
|
|
|
73
|
-
this.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
this._setCleanupHandlers()
|
|
30
|
+
this._httpRequestBuffer = []
|
|
31
|
+
|
|
32
|
+
this._initDefaultMetrics()
|
|
78
33
|
}
|
|
79
34
|
|
|
80
35
|
/**
|
|
@@ -118,9 +73,9 @@ class MetricsClient {
|
|
|
118
73
|
updateFn: process.uptime,
|
|
119
74
|
})
|
|
120
75
|
|
|
121
|
-
this.
|
|
122
|
-
name: '
|
|
123
|
-
help: '
|
|
76
|
+
this.createGauge({
|
|
77
|
+
name: 'http_app_requests_total',
|
|
78
|
+
help: 'Total number of HTTP requests (collected over interval)',
|
|
124
79
|
labelNames: this.withDefaultLabels([
|
|
125
80
|
'method',
|
|
126
81
|
'route',
|
|
@@ -130,9 +85,9 @@ class MetricsClient {
|
|
|
130
85
|
]),
|
|
131
86
|
})
|
|
132
87
|
|
|
133
|
-
this.
|
|
134
|
-
name: '
|
|
135
|
-
help: '
|
|
88
|
+
this.createGauge({
|
|
89
|
+
name: 'http_app_requests_total_duration',
|
|
90
|
+
help: 'Total duration of HTTP requests in milliseconds (collected over interval)',
|
|
136
91
|
labelNames: this.withDefaultLabels([
|
|
137
92
|
'method',
|
|
138
93
|
'route',
|
|
@@ -143,71 +98,6 @@ class MetricsClient {
|
|
|
143
98
|
})
|
|
144
99
|
}
|
|
145
100
|
|
|
146
|
-
/**
|
|
147
|
-
* Create a gauge metric.
|
|
148
|
-
* @param {Object} options - Gauge configuration
|
|
149
|
-
* @param {string} options.name - Name of the gauge
|
|
150
|
-
* @param {string} options.help - Help text describing the gauge
|
|
151
|
-
* @param {function(): number|Promise<number>} [options.updateFn] - Optional function returning the gauge value
|
|
152
|
-
* @param {string[]} [options.labelNames] - Optional custom label names
|
|
153
|
-
* @returns {import('prom-client').Gauge} The created Prometheus gauge
|
|
154
|
-
*/
|
|
155
|
-
createGauge = ({
|
|
156
|
-
name,
|
|
157
|
-
help,
|
|
158
|
-
updateFn,
|
|
159
|
-
labelNames = Object.keys(this.defaultLabels),
|
|
160
|
-
}) => {
|
|
161
|
-
if (this.gauges[name]) return this.gauges[name]
|
|
162
|
-
|
|
163
|
-
const g = new client.Gauge({
|
|
164
|
-
name,
|
|
165
|
-
help,
|
|
166
|
-
labelNames,
|
|
167
|
-
registers: [this._registry],
|
|
168
|
-
})
|
|
169
|
-
this.gauges[name] = g
|
|
170
|
-
|
|
171
|
-
if (updateFn && typeof updateFn === 'function') {
|
|
172
|
-
this.gaugeUpdaters[name] = updateFn
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
return g
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Create a Prometheus Counter metric.
|
|
180
|
-
*
|
|
181
|
-
* @param {Object} params - Counter configuration
|
|
182
|
-
* @param {string} params.name - Metric name
|
|
183
|
-
* @param {string} params.help - Metric description
|
|
184
|
-
* @param {string[]} [params.labelNames] - Optional list of label names. Defaults to this.defaultLabels keys.
|
|
185
|
-
*
|
|
186
|
-
* @returns {(labels?: Object, incrementValue?: number) => void}
|
|
187
|
-
* A function to increment the counter.
|
|
188
|
-
* Usage: (labels?, incrementValue?)
|
|
189
|
-
*/
|
|
190
|
-
createCounter({ name, help, labelNames = Object.keys(this.defaultLabels) }) {
|
|
191
|
-
if (this.counters[name]) return this.countersFunctions[name]
|
|
192
|
-
|
|
193
|
-
const c = new client.Counter({
|
|
194
|
-
name,
|
|
195
|
-
help,
|
|
196
|
-
labelNames,
|
|
197
|
-
registers: [this._registry],
|
|
198
|
-
})
|
|
199
|
-
this.counters[name] = c
|
|
200
|
-
|
|
201
|
-
this.countersFunctions = {
|
|
202
|
-
...this.countersFunctions,
|
|
203
|
-
[name]: (data = {}, value = 1) => {
|
|
204
|
-
c.inc({ ...this.defaultLabels, ...data }, value)
|
|
205
|
-
},
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
return this.countersFunctions[name]
|
|
209
|
-
}
|
|
210
|
-
|
|
211
101
|
/**
|
|
212
102
|
* Get CPU usage percent (cgroup-aware)
|
|
213
103
|
* @returns {number}
|
|
@@ -307,9 +197,9 @@ class MetricsClient {
|
|
|
307
197
|
}
|
|
308
198
|
|
|
309
199
|
/**
|
|
310
|
-
*
|
|
200
|
+
* Track an HTTP request (adds to buffer for interval collection).
|
|
311
201
|
*
|
|
312
|
-
* @param {Object} params - The parameters for the request
|
|
202
|
+
* @param {Object} params - The parameters for the request.
|
|
313
203
|
* @param {string} params.method - HTTP method (GET, POST, etc.).
|
|
314
204
|
* @param {string} params.route - The full requested URL or route.
|
|
315
205
|
* @param {number} params.status_code - HTTP response status code.
|
|
@@ -325,28 +215,80 @@ class MetricsClient {
|
|
|
325
215
|
databaseId = '',
|
|
326
216
|
duration,
|
|
327
217
|
}) {
|
|
328
|
-
this.
|
|
218
|
+
if (!this.enabled) return
|
|
219
|
+
|
|
220
|
+
this._httpRequestBuffer.push({
|
|
329
221
|
method,
|
|
330
222
|
route,
|
|
331
|
-
status_code,
|
|
332
|
-
appId,
|
|
333
|
-
databaseId,
|
|
223
|
+
status_code: String(status_code),
|
|
224
|
+
appId: appId || '',
|
|
225
|
+
databaseId: databaseId || '',
|
|
226
|
+
duration,
|
|
334
227
|
})
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Collect HTTP metrics from buffer, group by labels, and set gauges.
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
_collectHttpMetrics = () => {
|
|
235
|
+
if (this._httpRequestBuffer.length === 0) {
|
|
236
|
+
return
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const grouped = {}
|
|
240
|
+
const defaultLabels = this.getDefaultLabels()
|
|
241
|
+
|
|
242
|
+
this._httpRequestBuffer.forEach(req => {
|
|
243
|
+
const key = JSON.stringify({
|
|
244
|
+
method: req.method,
|
|
245
|
+
route: req.route,
|
|
246
|
+
appId: req.appId,
|
|
247
|
+
databaseId: req.databaseId,
|
|
248
|
+
status_code: req.status_code,
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
if (!grouped[key]) {
|
|
252
|
+
grouped[key] = {
|
|
253
|
+
labels: {
|
|
254
|
+
method: req.method,
|
|
255
|
+
route: req.route,
|
|
256
|
+
appId: req.appId,
|
|
257
|
+
databaseId: req.databaseId,
|
|
258
|
+
status_code: req.status_code,
|
|
259
|
+
},
|
|
260
|
+
count: 0,
|
|
261
|
+
totalDuration: 0,
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
grouped[key].count += 1
|
|
266
|
+
grouped[key].totalDuration += req.duration || 0
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
Object.values(grouped).forEach(({ labels, count, totalDuration }) => {
|
|
270
|
+
const allLabels = { ...defaultLabels, ...labels }
|
|
271
|
+
this.gauges.http_app_requests_total.set(allLabels, count)
|
|
272
|
+
this.gauges.http_app_requests_total_duration.set(
|
|
273
|
+
allLabels,
|
|
274
|
+
totalDuration
|
|
275
|
+
)
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
this._httpRequestBuffer = []
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Override pushMetrics to collect HTTP metrics before pushing.
|
|
283
|
+
*/
|
|
284
|
+
pushMetrics = async () => {
|
|
285
|
+
this._collectHttpMetrics()
|
|
286
|
+
await super.pushMetrics()
|
|
345
287
|
}
|
|
346
288
|
|
|
347
289
|
/**
|
|
348
290
|
* Express middleware to track HTTP requests.
|
|
349
|
-
* Track the `
|
|
291
|
+
* Track the `http_app_requests_total` and `http_app_requests_total_duration` metric.
|
|
350
292
|
*/
|
|
351
293
|
trackHttpRequestMiddleware = (req, res, next) => {
|
|
352
294
|
if (!this.enabled || req.method === 'OPTIONS') {
|
|
@@ -380,278 +322,6 @@ class MetricsClient {
|
|
|
380
322
|
|
|
381
323
|
next()
|
|
382
324
|
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Clear all collected counters
|
|
386
|
-
*/
|
|
387
|
-
clearAllCounters = () => {
|
|
388
|
-
if (this.metricsLogValues) {
|
|
389
|
-
console.log('Counters to clear: ', Object.keys(this.counters))
|
|
390
|
-
}
|
|
391
|
-
Object.values(this.counters).forEach(counter => counter.reset())
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Push all gauges and counters to PushGateway and optionally log.
|
|
396
|
-
*/
|
|
397
|
-
pushMetrics = async () => {
|
|
398
|
-
try {
|
|
399
|
-
for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {
|
|
400
|
-
try {
|
|
401
|
-
if (!updateFn) {
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
const result = updateFn()
|
|
405
|
-
const val = result instanceof Promise ? await result : result
|
|
406
|
-
if (val !== undefined) this.gauges[name].set(this.defaultLabels, val)
|
|
407
|
-
} catch (err) {
|
|
408
|
-
console.error(
|
|
409
|
-
`${this.prefixLogs} Failed to update gauge ${name}:`,
|
|
410
|
-
err
|
|
411
|
-
)
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
await this.gatewayPush()
|
|
416
|
-
this.clearAllCounters()
|
|
417
|
-
|
|
418
|
-
if (this.logValues) {
|
|
419
|
-
const metrics = await this._registry.getMetricsAsJSON()
|
|
420
|
-
console.log(
|
|
421
|
-
`${this.prefixLogs} Metrics:\n`,
|
|
422
|
-
JSON.stringify(metrics, null, 2)
|
|
423
|
-
)
|
|
424
|
-
}
|
|
425
|
-
} catch (err) {
|
|
426
|
-
console.error(`${this.prefixLogs} Failed to push metrics:`, err)
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
_startPush = (interval = this.intervalSec, customPushMetics = undefined) => {
|
|
431
|
-
if (!this.enabled) {
|
|
432
|
-
console.warn(`${this.prefixLogs} Metrics disabled`)
|
|
433
|
-
return
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
if (this.startupValidation && !this.startupValidation()) {
|
|
437
|
-
return
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
if (customPushMetics && typeof customPushMetics === 'function') {
|
|
441
|
-
setInterval(() => customPushMetics(), interval * 1000)
|
|
442
|
-
} else {
|
|
443
|
-
setInterval(() => {
|
|
444
|
-
this.pushMetrics().catch(err => {
|
|
445
|
-
console.error(`${this.prefixLogs} Failed to push metrics:`, err)
|
|
446
|
-
})
|
|
447
|
-
}, interval * 1000)
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
console.warn(
|
|
451
|
-
`${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s)`
|
|
452
|
-
)
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Start periodic metrics collection and push.
|
|
457
|
-
*
|
|
458
|
-
* This method wraps the internal `_startPush` method.
|
|
459
|
-
* If a `customPushMetrics` function is provided, it will be executed
|
|
460
|
-
* at the given interval instead of the default `pushMetrics` behavior.
|
|
461
|
-
*
|
|
462
|
-
* @param {number} [interval=this.intervalSec] - Interval in seconds between pushes.
|
|
463
|
-
* @param {() => void | Promise<void>} [customPushMetrics] - Optional custom push function. If provided, Prometheus push is skipped.
|
|
464
|
-
*/
|
|
465
|
-
startPush = (interval, customPushMetics = undefined) => {
|
|
466
|
-
this._startPush(interval, customPushMetics)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/**
|
|
470
|
-
* Cleanup metrics and exit process.
|
|
471
|
-
* @returns {Promise<void>}
|
|
472
|
-
*/
|
|
473
|
-
cleanup = async () => {
|
|
474
|
-
if (this.enabled) {
|
|
475
|
-
await this.gatewayDelete()
|
|
476
|
-
}
|
|
477
|
-
process.exit(0)
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
/**
|
|
481
|
-
* Remove old/stale dyno/instance metrics from PushGateway.
|
|
482
|
-
*
|
|
483
|
-
* Compares existing PushGateway metrics for this job and deletes any instances
|
|
484
|
-
* that do not match the current dynoId.
|
|
485
|
-
*
|
|
486
|
-
* @param {boolean} removeOldMetrics If true, performs cleanup; otherwise does nothing
|
|
487
|
-
* @returns {Promise<void>}
|
|
488
|
-
* @private
|
|
489
|
-
*/
|
|
490
|
-
_clearOldWorkers = async removeOldMetrics => {
|
|
491
|
-
if (!removeOldMetrics) return
|
|
492
|
-
|
|
493
|
-
try {
|
|
494
|
-
const url = `${this.pushgatewayUrl}/metrics`
|
|
495
|
-
const res = await fetch(url, {
|
|
496
|
-
headers: {
|
|
497
|
-
Authorization: `Basic ${this.authToken}`,
|
|
498
|
-
Accept: 'text/plain',
|
|
499
|
-
},
|
|
500
|
-
})
|
|
501
|
-
|
|
502
|
-
if (!res.ok) {
|
|
503
|
-
console.error(
|
|
504
|
-
`${this.prefixLogs} Failed to fetch metrics: ${res.status}`
|
|
505
|
-
)
|
|
506
|
-
return
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
const text = await res.text()
|
|
510
|
-
|
|
511
|
-
const metricRegex = /([a-zA-Z_:][a-zA-Z0-9_:]*)\{([^}]*)\}/gm
|
|
512
|
-
const labelRegex = /(\w+)="([^"]*)"/g
|
|
513
|
-
|
|
514
|
-
const uniqueLabelSets = new Set()
|
|
515
|
-
|
|
516
|
-
let match
|
|
517
|
-
// eslint-disable-next-line no-cond-assign
|
|
518
|
-
while ((match = metricRegex.exec(text)) !== null) {
|
|
519
|
-
const rawLabels = match[2]
|
|
520
|
-
let lr
|
|
521
|
-
const labels = {}
|
|
522
|
-
|
|
523
|
-
// eslint-disable-next-line no-cond-assign
|
|
524
|
-
while ((lr = labelRegex.exec(rawLabels)) !== null) {
|
|
525
|
-
// eslint-disable-next-line prefer-destructuring
|
|
526
|
-
labels[lr[1]] = lr[2]
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
if (
|
|
530
|
-
labels.job === this.appName &&
|
|
531
|
-
labels.process_type === this.processType
|
|
532
|
-
) {
|
|
533
|
-
uniqueLabelSets.add(JSON.stringify(labels))
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (uniqueLabelSets.size === 0) {
|
|
538
|
-
console.log(
|
|
539
|
-
`${this.prefixLogs} No metrics found for job ${this.appName}`
|
|
540
|
-
)
|
|
541
|
-
return
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
const oldLabelSets = [...uniqueLabelSets]
|
|
545
|
-
.map(s => JSON.parse(s))
|
|
546
|
-
.filter(
|
|
547
|
-
labels =>
|
|
548
|
-
labels.instance &&
|
|
549
|
-
labels.instance !== this.dynoId &&
|
|
550
|
-
labels.process_type === this.processType
|
|
551
|
-
)
|
|
552
|
-
|
|
553
|
-
if (oldLabelSets.length === 0) {
|
|
554
|
-
console.log(`${this.prefixLogs} No old dynos to delete.`)
|
|
555
|
-
return
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
for (const labels of oldLabelSets) {
|
|
559
|
-
try {
|
|
560
|
-
await this.gatewayDelete({ jobName: this.appName, groupings: labels })
|
|
561
|
-
console.log(
|
|
562
|
-
`${this.prefixLogs} Deleted metrics for dyno: ${
|
|
563
|
-
labels.instance
|
|
564
|
-
}, labels: ${Object.keys(labels)} `
|
|
565
|
-
)
|
|
566
|
-
} catch (err) {
|
|
567
|
-
console.error(
|
|
568
|
-
`${this.prefixLogs} Failed to delete metrics for ${labels.instance}:`,
|
|
569
|
-
err
|
|
570
|
-
)
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
console.log(
|
|
575
|
-
`${this.prefixLogs} Cleared all old instances for job ${this.appName}`
|
|
576
|
-
)
|
|
577
|
-
} catch (err) {
|
|
578
|
-
console.error(`${this.prefixLogs} Error deleting old metrics:`, err)
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
/**
|
|
583
|
-
* Delete metrics for this job/instance from PushGateway.
|
|
584
|
-
*
|
|
585
|
-
* @param {Object} [params]
|
|
586
|
-
* @param {string} [params.jobName] Job name (defaults to appName)
|
|
587
|
-
* @param {Object} [params.groupings] Grouping labels
|
|
588
|
-
* @param {string} [params.groupings.process_type] Process type label
|
|
589
|
-
* @param {string} [params.groupings.instance] Instance/dyno ID
|
|
590
|
-
* @returns {Promise<void>}
|
|
591
|
-
*/
|
|
592
|
-
gatewayDelete = async (params = {}) => {
|
|
593
|
-
return this.gateway.delete({
|
|
594
|
-
jobName: params.jobName || this.appName,
|
|
595
|
-
groupings: params.groupings || {
|
|
596
|
-
process_type: this.processType,
|
|
597
|
-
instance: this.dynoId,
|
|
598
|
-
},
|
|
599
|
-
})
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Push metrics to PushGateway.
|
|
604
|
-
*
|
|
605
|
-
* @param {object} [params]
|
|
606
|
-
* @param {string} [params.jobName]
|
|
607
|
-
* @param {object} [params.groupings]
|
|
608
|
-
* @returns {Promise<void>}
|
|
609
|
-
*/
|
|
610
|
-
gatewayPush = async (params = {}) => {
|
|
611
|
-
const groupings = {
|
|
612
|
-
process_type: this.processType,
|
|
613
|
-
instance: this.dynoId,
|
|
614
|
-
...(params.groupings || {}),
|
|
615
|
-
}
|
|
616
|
-
return this.gateway.push({
|
|
617
|
-
jobName: params.jobName || this.appName,
|
|
618
|
-
groupings,
|
|
619
|
-
})
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
/**
|
|
623
|
-
* Merge the default metric labels (`app`, `dyno_id`, `process_type`)
|
|
624
|
-
* with custom label names.
|
|
625
|
-
*
|
|
626
|
-
* @param {string[]} labels Additional label names
|
|
627
|
-
* @returns {string[]} Combined label names
|
|
628
|
-
*/
|
|
629
|
-
withDefaultLabels = (labels = []) => {
|
|
630
|
-
return [...Object.keys(this.defaultLabels), ...labels]
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
getDefaultLabels = (labels = []) => {
|
|
634
|
-
return this.defaultLabels
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
_setCleanupHandlers = () => {
|
|
638
|
-
process.on('SIGINT', this.cleanup)
|
|
639
|
-
process.on('SIGTERM', this.cleanup)
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
// GETTERS
|
|
643
|
-
|
|
644
|
-
get metricsEnabled() {
|
|
645
|
-
return this.enabled
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
get metricsLogValues() {
|
|
649
|
-
return this.logValues
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
get registry() {
|
|
653
|
-
return this._registry
|
|
654
|
-
}
|
|
655
325
|
}
|
|
656
326
|
|
|
657
327
|
module.exports = { MetricsClient }
|
|
@@ -1,28 +1,27 @@
|
|
|
1
1
|
const { Pool } = require('pg')
|
|
2
|
-
const {
|
|
2
|
+
const { BaseMetricsClient } = require('./baseMetricsClient')
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* DatabaseMetricsClient collects Postgres connection metrics
|
|
6
6
|
* and pushes them to Prometheus Pushgateway.
|
|
7
7
|
*
|
|
8
|
-
* @extends
|
|
8
|
+
* @extends BaseMetricsClient
|
|
9
9
|
*/
|
|
10
|
-
class DatabaseMetricsClient extends
|
|
10
|
+
class DatabaseMetricsClient extends BaseMetricsClient {
|
|
11
11
|
/**
|
|
12
12
|
* @param {Object} options
|
|
13
13
|
* @param {string} options.databaseUrl - Required main database URL
|
|
14
14
|
* @param {string} options.databaseName - Main database name for metrics
|
|
15
15
|
* @param {Object<string, string>} [options.additional_database_urls] - Optional additional DBs, keyed by custom name with URL as value
|
|
16
|
-
* @param {string} [options.appName] - Application name (from
|
|
17
|
-
* @param {string} [options.dynoId] - Dyno/instance ID (from
|
|
18
|
-
* @param {string} [options.processType] - Process type (from
|
|
19
|
-
* @param {boolean} [options.enabled] - Enable metrics collection (from
|
|
20
|
-
* @param {boolean} [options.logValues] - Log metrics values (from
|
|
21
|
-
* @param {string} [options.pushgatewayUrl] - PushGateway URL (from
|
|
22
|
-
* @param {string} [options.pushgatewaySecret] - PushGateway secret token (from
|
|
16
|
+
* @param {string} [options.appName] - Application name (from BaseMetricsClient)
|
|
17
|
+
* @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)
|
|
18
|
+
* @param {string} [options.processType] - Process type (from BaseMetricsClient)
|
|
19
|
+
* @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)
|
|
20
|
+
* @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)
|
|
21
|
+
* @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)
|
|
22
|
+
* @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)
|
|
23
23
|
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics
|
|
24
24
|
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service
|
|
25
|
-
* @param {boolean} [options.scripDefaultMetrics] - Skip default metrics creation
|
|
26
25
|
* @param {function} [options.startupValidation] - Function to validate startup
|
|
27
26
|
*/
|
|
28
27
|
constructor({
|
|
@@ -78,7 +77,6 @@ class DatabaseMetricsClient extends MetricsClient {
|
|
|
78
77
|
|
|
79
78
|
super({
|
|
80
79
|
...metricsConfig,
|
|
81
|
-
scripDefaultMetrics: true,
|
|
82
80
|
processType: metricsConfig.processType || 'database-metrics',
|
|
83
81
|
intervalSec,
|
|
84
82
|
startupValidation,
|
|
@@ -3,7 +3,7 @@ const { RedisMetricsClient } = require('.')
|
|
|
3
3
|
const { IOREDIS } = require('./redisUtils')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* QueueRedisMetricsClient extends
|
|
6
|
+
* QueueRedisMetricsClient extends RedisMetricsClient to collect
|
|
7
7
|
* Redis and Bee Queue metrics periodically and push them to Prometheus Pushgateway.
|
|
8
8
|
*
|
|
9
9
|
* @extends RedisMetricsClient
|
|
@@ -12,17 +12,16 @@ class QueueRedisMetricsClient extends RedisMetricsClient {
|
|
|
12
12
|
/**
|
|
13
13
|
* @param {Object} options
|
|
14
14
|
* @param {any} options.redisClient - Redis client instance (required)
|
|
15
|
-
* @param {string} [options.appName] - Application name (from
|
|
16
|
-
* @param {string} [options.dynoId] - Dyno/instance ID (from
|
|
17
|
-
* @param {string} [options.processType] - Process type (from
|
|
18
|
-
* @param {boolean} [options.enabled] - Enable metrics collection (from
|
|
19
|
-
* @param {boolean} [options.logValues] - Log metrics values (from
|
|
20
|
-
* @param {string} [options.pushgatewayUrl] - PushGateway URL (from
|
|
21
|
-
* @param {string} [options.pushgatewaySecret] - PushGateway secret token (from
|
|
22
|
-
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from
|
|
23
|
-
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from
|
|
24
|
-
* @param {
|
|
25
|
-
* @param {function} [options.startupValidation] - Function to validate startup (from MetricsClient)
|
|
15
|
+
* @param {string} [options.appName] - Application name (from BaseMetricsClient)
|
|
16
|
+
* @param {string} [options.dynoId] - Dyno/instance ID (from BaseMetricsClient)
|
|
17
|
+
* @param {string} [options.processType] - Process type (from BaseMetricsClient)
|
|
18
|
+
* @param {boolean} [options.enabled] - Enable metrics collection (from BaseMetricsClient)
|
|
19
|
+
* @param {boolean} [options.logValues] - Log metrics values (from BaseMetricsClient)
|
|
20
|
+
* @param {string} [options.pushgatewayUrl] - PushGateway URL (from BaseMetricsClient)
|
|
21
|
+
* @param {string} [options.pushgatewaySecret] - PushGateway secret token (from BaseMetricsClient)
|
|
22
|
+
* @param {number} [options.intervalSec] - Interval in seconds for pushing metrics (from BaseMetricsClient)
|
|
23
|
+
* @param {boolean} [options.removeOldMetrics] - Remove old metrics by service (from BaseMetricsClient)
|
|
24
|
+
* @param {function} [options.startupValidation] - Function to validate startup (from BaseMetricsClient)
|
|
26
25
|
*/
|
|
27
26
|
constructor({ redisClient, metricsConfig = {} } = {}) {
|
|
28
27
|
const getConfiguredQueueNames = () => {
|