@adalo/metrics 0.1.173 → 0.1.174
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/README.md +7 -0
- package/__tests__/httpMetricsRedisCollector.test.js +203 -0
- package/__tests__/httpMetricsRedisRecorder.test.js +60 -0
- package/__tests__/httpMetricsRedisStore.test.js +431 -0
- package/docs/http-metrics-redis.md +19 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +44 -0
- package/lib/index.js.map +1 -1
- package/lib/metrics/baseMetricsClient.d.ts +2 -0
- package/lib/metrics/baseMetricsClient.d.ts.map +1 -1
- package/lib/metrics/baseMetricsClient.js +6 -3
- package/lib/metrics/baseMetricsClient.js.map +1 -1
- package/lib/metrics/httpMetricsRedisCollector.d.ts +50 -0
- package/lib/metrics/httpMetricsRedisCollector.d.ts.map +1 -0
- package/lib/metrics/httpMetricsRedisCollector.js +117 -0
- package/lib/metrics/httpMetricsRedisCollector.js.map +1 -0
- package/lib/metrics/httpMetricsRedisRecorder.d.ts +48 -0
- package/lib/metrics/httpMetricsRedisRecorder.d.ts.map +1 -0
- package/lib/metrics/httpMetricsRedisRecorder.js +86 -0
- package/lib/metrics/httpMetricsRedisRecorder.js.map +1 -0
- package/lib/metrics/httpMetricsRedisStore.d.ts +88 -0
- package/lib/metrics/httpMetricsRedisStore.d.ts.map +1 -0
- package/lib/metrics/httpMetricsRedisStore.js +223 -0
- package/lib/metrics/httpMetricsRedisStore.js.map +1 -0
- package/lib/metrics/metricsClient.d.ts +34 -27
- package/lib/metrics/metricsClient.d.ts.map +1 -1
- package/lib/metrics/metricsClient.js +35 -37
- package/lib/metrics/metricsClient.js.map +1 -1
- package/lib/metrics/metricsDatabaseClient.d.ts.map +1 -1
- package/lib/metrics/metricsDatabaseClient.js +6 -1
- package/lib/metrics/metricsDatabaseClient.js.map +1 -1
- package/lib/metrics/metricsProcessTypeUtils.d.ts +58 -0
- package/lib/metrics/metricsProcessTypeUtils.d.ts.map +1 -0
- package/lib/metrics/metricsProcessTypeUtils.js +86 -0
- package/lib/metrics/metricsProcessTypeUtils.js.map +1 -0
- package/lib/metrics/metricsQueueRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsQueueRedisClient.js +5 -0
- package/lib/metrics/metricsQueueRedisClient.js.map +1 -1
- package/lib/metrics/metricsRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsRedisClient.js +7 -1
- package/lib/metrics/metricsRedisClient.js.map +1 -1
- package/package.json +5 -5
- package/src/index.ts +4 -0
- package/src/metrics/baseMetricsClient.js +4 -1
- package/src/metrics/httpMetricsRedisCollector.js +131 -0
- package/src/metrics/httpMetricsRedisRecorder.js +74 -0
- package/src/metrics/httpMetricsRedisStore.js +208 -0
- package/src/metrics/metricsClient.js +34 -53
- package/src/metrics/metricsDatabaseClient.js +7 -1
- package/src/metrics/metricsProcessTypeUtils.js +98 -0
- package/src/metrics/metricsQueueRedisClient.js +6 -0
- package/src/metrics/metricsRedisClient.js +12 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# HTTP metrics via Redis (`HttpMetricsRedisRecorder` / `HttpMetricsRedisCollector`)
|
|
2
|
+
|
|
3
|
+
This file is a **quick entry point** for the Redis-backed HTTP aggregation path. **Full architecture, env vars, and diagrams** are in the repository guide:
|
|
4
|
+
|
|
5
|
+
**[docs/METRICS.md](../../docs/METRICS.md)**
|
|
6
|
+
|
|
7
|
+
## Cheat sheet
|
|
8
|
+
|
|
9
|
+
| Concern | Detail |
|
|
10
|
+
|--------|--------|
|
|
11
|
+
| **Writers** | `HttpMetricsRedisRecorder` — Express middleware records `method`, `route`, `status_code`, duration into Redis hashes. |
|
|
12
|
+
| **Reader** | `HttpMetricsRedisCollector` — separate process calls `pushMetrics()`, which **drains** Redis (atomic Lua) and increments `app_requests_*`, then pushes to VM-agent. |
|
|
13
|
+
| **Redis key shape** | `metrics:http:v2:<encode(appName)>:<encode(processType)>:count` and `:dur` — two hashes per writer group. |
|
|
14
|
+
| **Hash field** | Three logical parts: method, route, HTTP status (joined with an internal `FIELD_SEP`). |
|
|
15
|
+
| **Prometheus labels** | `method`, `route`, `status_code` (plus default `app` / `process_type` without `dyno_id` on these counters). |
|
|
16
|
+
| **Backend** | Web: `backend/monitoring.ts` + `METRICS_HTTP_ENABLED`. Drain: `backend/http-metrics-collector.ts`, Procfile `http-metrics:`. |
|
|
17
|
+
| **Prime 0 on new routes** | The first time a `(method, route, status_code)` appears **in this process**, the collector `inc(..., 0)` for count+duration on **that label set only**, **POST**, then applies drained counts for **all** rows. Existing series are **not** touched in the prime loop — e.g. in-memory `b` was **18**, drain has new `a:1` and `b:20`: prime push exports **`a=0`, `b=18`**; after apply, final push has **`a=1`, `b=38`**. If **all** label sets were already seen, there is **no** extra prime `POST`. |
|
|
18
|
+
|
|
19
|
+
For in-process HTTP metrics **without** Redis, see **`MetricsClient`** + `METRICS_HTTP_ENABLED` in **[docs/METRICS.md](../../docs/METRICS.md#http-metrics-two-valid-designs)**.
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export * from './metrics/baseMetricsClient';
|
|
2
2
|
export * from './metrics/metricsClient';
|
|
3
|
+
export * from './metrics/metricsProcessTypeUtils';
|
|
4
|
+
export * from './metrics/httpMetricsRedisStore';
|
|
5
|
+
export * from './metrics/httpMetricsRedisRecorder';
|
|
6
|
+
export * from './metrics/httpMetricsRedisCollector';
|
|
3
7
|
export * from './metrics/metricsRedisClient';
|
|
4
8
|
export * from './metrics/metricsQueueRedisClient';
|
|
5
9
|
export * from './metrics/metricsDatabaseClient';
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,mCAAmC,CAAA;AACjD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,mCAAmC,CAAA;AACjD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,oCAAoC,CAAA;AAClD,cAAc,qCAAqC,CAAA;AACnD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,mCAAmC,CAAA;AACjD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,cAAc,CAAA"}
|
package/lib/index.js
CHANGED
|
@@ -25,6 +25,50 @@ Object.keys(_metricsClient).forEach(function (key) {
|
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
});
|
|
28
|
+
var _metricsProcessTypeUtils = require("./metrics/metricsProcessTypeUtils");
|
|
29
|
+
Object.keys(_metricsProcessTypeUtils).forEach(function (key) {
|
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
|
31
|
+
if (key in exports && exports[key] === _metricsProcessTypeUtils[key]) return;
|
|
32
|
+
Object.defineProperty(exports, key, {
|
|
33
|
+
enumerable: true,
|
|
34
|
+
get: function () {
|
|
35
|
+
return _metricsProcessTypeUtils[key];
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
var _httpMetricsRedisStore = require("./metrics/httpMetricsRedisStore");
|
|
40
|
+
Object.keys(_httpMetricsRedisStore).forEach(function (key) {
|
|
41
|
+
if (key === "default" || key === "__esModule") return;
|
|
42
|
+
if (key in exports && exports[key] === _httpMetricsRedisStore[key]) return;
|
|
43
|
+
Object.defineProperty(exports, key, {
|
|
44
|
+
enumerable: true,
|
|
45
|
+
get: function () {
|
|
46
|
+
return _httpMetricsRedisStore[key];
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
var _httpMetricsRedisRecorder = require("./metrics/httpMetricsRedisRecorder");
|
|
51
|
+
Object.keys(_httpMetricsRedisRecorder).forEach(function (key) {
|
|
52
|
+
if (key === "default" || key === "__esModule") return;
|
|
53
|
+
if (key in exports && exports[key] === _httpMetricsRedisRecorder[key]) return;
|
|
54
|
+
Object.defineProperty(exports, key, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: function () {
|
|
57
|
+
return _httpMetricsRedisRecorder[key];
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
var _httpMetricsRedisCollector = require("./metrics/httpMetricsRedisCollector");
|
|
62
|
+
Object.keys(_httpMetricsRedisCollector).forEach(function (key) {
|
|
63
|
+
if (key === "default" || key === "__esModule") return;
|
|
64
|
+
if (key in exports && exports[key] === _httpMetricsRedisCollector[key]) return;
|
|
65
|
+
Object.defineProperty(exports, key, {
|
|
66
|
+
enumerable: true,
|
|
67
|
+
get: function () {
|
|
68
|
+
return _httpMetricsRedisCollector[key];
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
28
72
|
var _metricsRedisClient = require("./metrics/metricsRedisClient");
|
|
29
73
|
Object.keys(_metricsRedisClient).forEach(function (key) {
|
|
30
74
|
if (key === "default" || key === "__esModule") return;
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_baseMetricsClient","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_metricsClient","_metricsRedisClient","_metricsQueueRedisClient","_metricsDatabaseClient","_healthCheckClient","_healthCheckUtils","_healthCheckWorker","_redisUtils"],"sources":["../src/index.ts"],"sourcesContent":["export * from './metrics/baseMetricsClient'\nexport * from './metrics/metricsClient'\nexport * from './metrics/metricsRedisClient'\nexport * from './metrics/metricsQueueRedisClient'\nexport * from './metrics/metricsDatabaseClient'\nexport * from './health/healthCheckClient'\nexport * from './health/healthCheckUtils'\nexport * from './health/healthCheckWorker'\nexport * from './redisUtils'\n"],"mappings":";;;;;AAAA,IAAAA,kBAAA,GAAAC,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAH,kBAAA,EAAAI,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAL,kBAAA,CAAAK,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAT,kBAAA,CAAAK,GAAA;IAAA;EAAA;AAAA;AACA,IAAAK,cAAA,GAAAT,OAAA;AAAAC,MAAA,CAAAC,IAAA,CAAAO,cAAA,EAAAN,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAA,GAAA,IAAAC,OAAA,IAAAA,OAAA,CAAAD,GAAA,MAAAK,cAAA,CAAAL,GAAA;EAAAH,MAAA,CAAAK,cAAA,CAAAD,OAAA,EAAAD,GAAA;IAAAG,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,cAAA,CAAAL,GAAA;IAAA;EAAA;AAAA;AACA,IAAAM,
|
|
1
|
+
{"version":3,"file":"index.js","names":["_baseMetricsClient","require","Object","keys","forEach","key","exports","defineProperty","enumerable","get","_metricsClient","_metricsProcessTypeUtils","_httpMetricsRedisStore","_httpMetricsRedisRecorder","_httpMetricsRedisCollector","_metricsRedisClient","_metricsQueueRedisClient","_metricsDatabaseClient","_healthCheckClient","_healthCheckUtils","_healthCheckWorker","_redisUtils"],"sources":["../src/index.ts"],"sourcesContent":["export * from './metrics/baseMetricsClient'\nexport * from './metrics/metricsClient'\nexport * from './metrics/metricsProcessTypeUtils'\nexport * from './metrics/httpMetricsRedisStore'\nexport * from './metrics/httpMetricsRedisRecorder'\nexport * from './metrics/httpMetricsRedisCollector'\nexport * from './metrics/metricsRedisClient'\nexport * from './metrics/metricsQueueRedisClient'\nexport * from './metrics/metricsDatabaseClient'\nexport * from './health/healthCheckClient'\nexport * from './health/healthCheckUtils'\nexport * from './health/healthCheckWorker'\nexport * from './redisUtils'\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -17,6 +17,7 @@ export class BaseMetricsClient {
|
|
|
17
17
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
18
18
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
19
19
|
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
20
|
+
* @param {boolean} [config.blockNodeDefaultMetrics] When true, do not register prom-client default process metrics (heap, event loop, etc.). Default false — used by HTTP-only collectors.
|
|
20
21
|
*/
|
|
21
22
|
constructor(config?: {
|
|
22
23
|
appName?: string | undefined;
|
|
@@ -30,6 +31,7 @@ export class BaseMetricsClient {
|
|
|
30
31
|
removeOldMetrics?: boolean | undefined;
|
|
31
32
|
startupValidation?: Function | undefined;
|
|
32
33
|
disablePushgateway?: boolean | undefined;
|
|
34
|
+
blockNodeDefaultMetrics?: boolean | undefined;
|
|
33
35
|
});
|
|
34
36
|
appName: string;
|
|
35
37
|
dynoId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseMetricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/baseMetricsClient.js"],"names":[],"mappings":"AAKA;;;;GAIG;AACH;IACE
|
|
1
|
+
{"version":3,"file":"baseMetricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/baseMetricsClient.js"],"names":[],"mappings":"AAKA;;;;GAIG;AACH;IACE;;;;;;;;;;;;;;OAcG;IACH;QAb2B,OAAO;QACP,MAAM;QACN,WAAW;QACV,OAAO;QACP,SAAS;QACV,cAAc;QACd,iBAAiB;QACjB,WAAW;QACV,gBAAgB;QACf,iBAAiB;QAClB,kBAAkB;QAClB,uBAAuB;OA4DlD;IAzDC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,iBAAuE;IACvE,mBAC+D;IAC/D,uBACoE;IACpE,kBAC0E;IAC1E,oBAGI;IACJ,wCAAiD;IACjD,4BAEoD;IACpD,0BAEmD;IAEnD,mBAAyF;IAEzF,uEAAsC;IAKtC;;;;MAIC;IAED,oFAAoF;IACpF;;;MAGC;IAGD,aAAmB;IACnB,WAAgB;IAChB,aAAkB;IAClB,sBAA2B;IAE3B,mEAAmE;IACnE;YADkB,MAAM,SAAc,MAAM,GAAG,QAAQ,MAAM,CAAC;MACvC;IAKvB,sCAAwC;IAG1C;;;;;;;;OAQG;IACH;QAN2B,IAAI,EAApB,MAAM;QACU,IAAI,EAApB,MAAM;QACuC,QAAQ,UAAzC,MAAM,GAAC,QAAQ,MAAM,CAAC;QACf,UAAU;UAC3B,OAAO,aAAa,EAAE,KAAK,CAuBvC;IAED;;;;;;;;;;;;OAYG;IACH;QAT0B,IAAI,EAAnB,MAAM;QACS,IAAI,EAAnB,MAAM;QACY,UAAU;QACX,sBAAsB;kBAE3B,MAAM,mBAAmB,MAAM,KAAK,IAAI,CAgC9D;IAED;;OAEG;IACH,6BAKC;IAED;;OAEG;IACH,kCAiCC;IAED,sEAmDC;IA/CK,+CAA0D;IAiDhE,iCAEC;IAED;;;;;;;;;OASG;IACH,iFAEC;IAED;;;OAGG;IACH,eAFa,QAAQ,IAAI,CAAC,CAOzB;IAED;;;;;;;;;OASG;IACH,yBAEC;IAED;;;OAGG;IACH,qBAFa,QAAQ,IAAI,CAAC,CAezB;IAED;;;OAGG;IACH,8BAkDC;IAED;;;;;OAKG;IACH,8CAFa,QAAQ,IAAI,CAAC,CAgBzB;IAED;;;OAGG;IACH,uBAoDC;IAED;;;;;;OAMG;IACH,6BAHW,MAAM,EAAE,KACN,MAAM,EAAE,CAIpB;IAED;;;;;;OAMG;IACH,0CAHW,MAAM,EAAE,KACN,MAAM,EAAE,CAIpB;IAED;;;;MAEC;IAED,gCAGC;IAID,8BAEC;IAED,gCAEC;IAED,4EAEC;IAED,sCAEC;IAED,2DAWC;CACF"}
|
|
@@ -26,6 +26,7 @@ class BaseMetricsClient {
|
|
|
26
26
|
* @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name
|
|
27
27
|
* @param {function} [config.startupValidation] Add to validate on start push.
|
|
28
28
|
* @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)
|
|
29
|
+
* @param {boolean} [config.blockNodeDefaultMetrics] When true, do not register prom-client default process metrics (heap, event loop, etc.). Default false — used by HTTP-only collectors.
|
|
29
30
|
*/
|
|
30
31
|
constructor(config = {}) {
|
|
31
32
|
this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app';
|
|
@@ -41,9 +42,11 @@ class BaseMetricsClient {
|
|
|
41
42
|
this.removeOldMetrics = config.removeOldMetrics ?? process.env.METRICS_REMOVE_OLD_METRICS === 'true';
|
|
42
43
|
this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`;
|
|
43
44
|
this._registry = new client.Registry();
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
if (config.blockNodeDefaultMetrics) {
|
|
46
|
+
client.collectDefaultMetrics({
|
|
47
|
+
register: this._registry
|
|
48
|
+
});
|
|
49
|
+
}
|
|
47
50
|
this.defaultLabels = {
|
|
48
51
|
app: this.appName,
|
|
49
52
|
dyno_id: this.dynoId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"baseMetricsClient.js","names":["client","require","https","http","URL","BaseMetricsClient","constructor","config","appName","process","env","BUILD_APP_NAME","dynoId","HOSTNAME","processType","BUILD_DYNO_PROCESS_TYPE","enabled","METRICS_ENABLED","logValues","METRICS_LOG_VALUES","pushgatewayUrl","METRICS_PUSHGATEWAY_URL","authToken","pushgatewaySecret","METRICS_PUSHGATEWAY_SECRET","intervalSec","parseInt","METRICS_INTERVAL_SEC","startupValidation","disablePushgateway","METRICS_DISABLE_PUSHGATEWAY","removeOldMetrics","METRICS_REMOVE_OLD_METRICS","prefixLogs","_registry","Registry","collectDefaultMetrics","register","defaultLabels","app","dyno_id","process_type","defaultLabelsWithoutDynoId","gateway","gauges","counters","countersFunctions","gaugeUpdaters","_clearOldWorkers","_setCleanupHandlers","keepProcessAliveWhenDisabled","createGauge","name","help","updateFn","labelNames","Object","keys","g","Gauge","registers","createCounter","useLabelsWithoutDynoId","defaultSet","c","Counter","data","value","inc","clearAllCounters","metricsLogValues","console","log","values","forEach","counter","reset","_pushMetrics","entries","result","val","Promise","undefined","set","err","error","gatewayPush","metrics","getMetricsAsJSON","JSON","stringify","_startPush","interval","customPushMetics","warn","_idleInterval","setInterval","clearInterval","runPush","resolve","pushMetrics","catch","pushOrigin","trim","origin","startPush","cleanup","gatewayDelete","exit","_deleteFromVMByLabels","message","esc","s","String","replace","selector","u","reject","Error","path","encodeURIComponent","req","protocol","request","hostname","port","method","headers","Authorization","agent","Agent","keepAlive","res","statusCode","on","chunk","end","params","_pushToVMAgent","pushUrl","pathname","search","contentType","then","setHeader","Buffer","byteLength","withDefaultLabels","labels","withDefaultLabelsWithoutDynoId","getDefaultLabels","metricsEnabled","registry","getMetricsAsString","metricsMiddleware","status","module","exports"],"sources":["../../src/metrics/baseMetricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst https = require('https')\nconst http = require('http')\nconst { URL } = require('url')\n\n/**\n * BaseMetricsClient provides common functionality for all metrics clients.\n * Handles registry setup, push to remote (VM-agent), default labels, and common operations.\n * Always pushes registry to the configured URL (POST Prometheus text format + Basic auth). No Pushgateway.\n */\nclass BaseMetricsClient {\n /**\n * @param {Object} config\n * @param {string} [config.appName] Name of the application\n * @param {string} [config.dynoId] Dyno/instance ID\n * @param {string} [config.processType] Process type (web, worker, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] Push URL (VM-agent import endpoint, e.g. .../api/v1/import/prometheus). /metrics is for GET (scrape), not POST (push).\n * @param {string} [config.pushgatewaySecret] Basic auth secret (Base64 of user:password)\n * @param {number} [config.intervalSec] Interval in seconds for pushing metrics\n * @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name\n * @param {function} [config.startupValidation] Add to validate on start push.\n * @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)\n */\n constructor(config = {}) {\n this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno'\n this.processType =\n config.processType ||\n process.env.BUILD_DYNO_PROCESS_TYPE ||\n 'undefined_build_dyno_type'\n this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true'\n this.logValues =\n config.logValues ?? process.env.METRICS_LOG_VALUES === 'true'\n this.pushgatewayUrl =\n config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || ''\n this.authToken =\n config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || ''\n this.intervalSec =\n config.intervalSec ||\n parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||\n 15\n this.startupValidation = config.startupValidation\n this.disablePushgateway =\n config.disablePushgateway ??\n process.env.METRICS_DISABLE_PUSHGATEWAY === 'true'\n this.removeOldMetrics =\n config.removeOldMetrics ??\n process.env.METRICS_REMOVE_OLD_METRICS === 'true'\n\n this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`\n\n this._registry = new client.Registry()\n client.collectDefaultMetrics({ register: this._registry })\n\n this.defaultLabels = {\n app: this.appName,\n dyno_id: this.dynoId,\n process_type: this.processType,\n }\n\n /** Default labels without dyno_id (for HTTP metrics so dyno_id is not included). */\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: this.processType,\n }\n\n // Always push to configured URL (VM-agent). No Pushgateway.\n this.gateway = null\n this.gauges = {}\n this.counters = {}\n this.countersFunctions = {}\n\n /** @type {Object<string, function(): number | Promise<number>>} */\n this.gaugeUpdaters = {}\n\n this._clearOldWorkers(config.removeOldMetrics)\n this._setCleanupHandlers()\n\n this.keepProcessAliveWhenDisabled = true\n }\n\n /**\n * Create a gauge metric.\n * @param {Object} options - Gauge configuration\n * @param {string} options.name - Name of the gauge\n * @param {string} options.help - Help text describing the gauge\n * @param {function(): number|Promise<number>} [options.updateFn] - Optional function returning the gauge value\n * @param {string[]} [options.labelNames] - Optional custom label names\n * @returns {import('prom-client').Gauge} The created Prometheus gauge\n */\n createGauge = ({\n name,\n help,\n updateFn,\n labelNames = Object.keys(this.defaultLabels),\n }) => {\n if (this.gauges[name]) return this.gauges[name]\n\n const g = new client.Gauge({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.gauges[name] = g\n\n if (updateFn && typeof updateFn === 'function') {\n this.gaugeUpdaters[name] = updateFn\n }\n\n return g\n }\n\n /**\n * Create a Prometheus Counter metric.\n *\n * @param {Object} params - Counter configuration\n * @param {string} params.name - Metric name\n * @param {string} params.help - Metric description\n * @param {string[]} [params.labelNames] - Optional list of label names. Defaults to this.defaultLabels keys.\n * @param {boolean} [params.useLabelsWithoutDynoId=false] - If true, counter uses app/process_type only (no dyno_id). Use for HTTP metrics.\n *\n * @returns {(labels?: Object, incrementValue?: number) => void}\n * A function to increment the counter.\n * Usage: (labels?, incrementValue?)\n */\n createCounter({\n name,\n help,\n labelNames = Object.keys(this.defaultLabels),\n useLabelsWithoutDynoId = false,\n }) {\n if (this.counters[name]) return this.countersFunctions[name]\n\n const defaultSet = useLabelsWithoutDynoId\n ? this.defaultLabelsWithoutDynoId\n : this.defaultLabels\n\n const c = new client.Counter({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.counters[name] = c\n\n this.countersFunctions = {\n ...this.countersFunctions,\n [name]: (data = {}, value = 1) => {\n c.inc({ ...defaultSet, ...data }, value)\n },\n }\n\n return this.countersFunctions[name]\n }\n\n /**\n * Clear all collected counters\n */\n clearAllCounters = () => {\n if (this.metricsLogValues) {\n console.log('Counters to clear: ', Object.keys(this.counters))\n }\n Object.values(this.counters).forEach(counter => counter.reset())\n }\n\n /**\n * Push all gauges and counters to PushGateway and optionally log.\n */\n _pushMetrics = async () => {\n try {\n for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {\n try {\n if (!updateFn) {\n continue\n }\n const result = updateFn()\n const val = result instanceof Promise ? await result : result\n if (val !== undefined) this.gauges[name].set(this.defaultLabels, val)\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to update gauge ${name}:`,\n err\n )\n }\n }\n\n if (!this.disablePushgateway) {\n await this.gatewayPush()\n }\n // this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)\n\n if (this.logValues) {\n const metrics = await this._registry.getMetricsAsJSON()\n console.log(\n `${this.prefixLogs} Metrics:\\n`,\n JSON.stringify(metrics, null, 2)\n )\n }\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n }\n }\n\n _startPush = (interval = this.intervalSec, customPushMetics = undefined) => {\n if (!this.enabled) {\n console.warn(`${this.prefixLogs} Metrics disabled`)\n if (this.keepProcessAliveWhenDisabled && !this._idleInterval) {\n this._idleInterval = setInterval(() => {}, 60 * 60 * 1000)\n }\n return\n }\n\n if (this._idleInterval) {\n clearInterval(this._idleInterval)\n this._idleInterval = null\n }\n\n if (this.startupValidation && !this.startupValidation()) {\n return\n }\n\n const runPush = () => {\n if (customPushMetics && typeof customPushMetics === 'function') {\n return Promise.resolve(customPushMetics())\n }\n return this.pushMetrics()\n }\n\n if (customPushMetics && typeof customPushMetics === 'function') {\n setInterval(() => customPushMetics(), interval * 1000)\n } else {\n setInterval(() => {\n runPush().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n })\n }, interval * 1000)\n }\n\n // First push immediately so metrics appear without waiting for the first interval\n runPush().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics (initial):`, err)\n })\n\n let pushOrigin = 'none'\n try {\n if (this.pushgatewayUrl && this.pushgatewayUrl.trim()) {\n pushOrigin = new URL(this.pushgatewayUrl.trim()).origin\n }\n } catch {\n pushOrigin = 'invalid URL'\n }\n console.warn(\n `${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s, push: ${pushOrigin})`\n )\n }\n\n pushMetrics = async () => {\n return this._pushMetrics()\n }\n\n /**\n * Start periodic metrics collection and push.\n *\n * This method wraps the internal `_startPush` method.\n * If a `customPushMetrics` function is provided, it will be executed\n * at the given interval instead of the default `pushMetrics` behavior.\n *\n * @param {number} [interval=this.intervalSec] - Interval in seconds between pushes.\n * @param {() => void | Promise<void>} [customPushMetrics] - Optional custom push function. If provided, Prometheus push is skipped.\n */\n startPush = (interval, customPushMetics = undefined) => {\n this._startPush(interval, customPushMetics)\n }\n\n /**\n * Cleanup metrics and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n if (this.enabled) {\n await this.gatewayDelete()\n }\n process.exit(0)\n }\n\n /**\n * Remove old/stale dyno/instance metrics from PushGateway.\n *\n * Compares existing PushGateway metrics for this job and deletes any instances\n * that do not match the current dynoId.\n *\n * @param {boolean} removeOldMetrics If true, performs cleanup; otherwise does nothing\n * @returns {Promise<void>}\n * @private\n */\n _clearOldWorkers = async removeOldMetrics => {\n // No Pushgateway; VM-agent does not support per-instance delete. Skip.\n }\n\n /**\n * On shutdown: optionally delete this instance's metrics from VictoriaMetrics (by app, dyno_id, process_type).\n * @returns {Promise<void>}\n */\n gatewayDelete = async () => {\n if (\n this.removeOldMetrics &&\n this.pushgatewayUrl &&\n this.pushgatewayUrl.trim()\n ) {\n await this._deleteFromVMByLabels().catch(err => {\n console.warn(\n `${this.prefixLogs} Deletion from VM on shutdown failed:`,\n err.message\n )\n })\n }\n }\n\n /**\n * Call VictoriaMetrics delete_series API to remove all series matching this instance's labels (app, dyno_id, process_type).\n * @private\n */\n _deleteFromVMByLabels = () => {\n const esc = s => String(s).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n const selector = `{app=\"${esc(this.appName)}\",dyno_id=\"${esc(\n this.dynoId\n )}\",process_type=\"${esc(this.processType)}\"}`\n let origin\n try {\n const u = new URL((this.pushgatewayUrl || '').trim())\n origin = u.origin\n } catch {\n return Promise.reject(new Error('Invalid push URL'))\n }\n const path = `/api/v1/admin/tsdb/delete_series?match[]=${encodeURIComponent(\n selector\n )}`\n return new Promise((resolve, reject) => {\n const u = new URL(origin)\n const req = (u.protocol === 'https:' ? https : http).request(\n {\n hostname: u.hostname,\n port: u.port || (u.protocol === 'https:' ? 443 : 80),\n path,\n method: 'POST',\n headers: {\n 'Content-Length': '0',\n Authorization: this.authToken\n ? `Basic ${this.authToken}`\n : undefined,\n },\n agent:\n u.protocol === 'https:'\n ? new https.Agent({ keepAlive: false })\n : undefined,\n },\n res => {\n if (res.statusCode >= 200 && res.statusCode < 300) resolve()\n else {\n let data = ''\n res.on('data', chunk => {\n data += chunk\n })\n res.on('end', () =>\n reject(new Error(`Delete failed: ${res.statusCode} ${data}`))\n )\n }\n }\n )\n req.on('error', reject)\n req.end()\n })\n }\n\n /**\n * Push registry to configured URL (VM-agent). POST Prometheus text format + Basic auth.\n *\n * @param {object} [params] Unused; kept for API compatibility.\n * @returns {Promise<void>}\n */\n gatewayPush = async (params = {}) => {\n if (this.disablePushgateway) {\n console.warn(\n `${this.prefixLogs} Metrics push skipped: METRICS_DISABLE_PUSHGATEWAY is set`\n )\n return Promise.resolve()\n }\n if (!this.pushgatewayUrl || !this.pushgatewayUrl.trim()) {\n console.warn(\n `${this.prefixLogs} Metrics push skipped: METRICS_PUSHGATEWAY_URL is not set`\n )\n return Promise.resolve()\n }\n return this._pushToVMAgent()\n }\n\n /**\n * POST registry (Prometheus text format) to VM-agent. VM-agent accepts push at /api/v1/import/prometheus; /metrics is GET (scrape) only.\n * @private\n */\n _pushToVMAgent = () => {\n let pushUrl = (this.pushgatewayUrl || '').trim()\n try {\n const u = new URL(pushUrl)\n if (!u.pathname || u.pathname === '/' || u.pathname === '/metrics') {\n pushUrl = `${u.origin}/api/v1/import/prometheus${u.search}`\n }\n } catch {\n // leave pushUrl as-is\n }\n return new Promise((resolve, reject) => {\n const u = new URL(pushUrl)\n const req = (u.protocol === 'https:' ? https : http).request(\n {\n hostname: u.hostname,\n port: u.port || (u.protocol === 'https:' ? 443 : 80),\n path: u.pathname + u.search,\n method: 'POST',\n headers: {\n 'Content-Type': client.register.contentType,\n Authorization: this.authToken\n ? `Basic ${this.authToken}`\n : undefined,\n },\n agent:\n u.protocol === 'https:'\n ? new https.Agent({ keepAlive: true })\n : undefined,\n },\n res => {\n if (res.statusCode >= 200 && res.statusCode < 300) {\n resolve()\n } else {\n let data = ''\n res.on('data', chunk => {\n data += chunk\n })\n res.on('end', () =>\n reject(new Error(`Push failed: ${res.statusCode} ${data}`))\n )\n }\n }\n )\n req.on('error', reject)\n this._registry\n .metrics()\n .then(metrics => {\n req.setHeader('Content-Length', Buffer.byteLength(metrics, 'utf8'))\n req.end(metrics, 'utf8')\n })\n .catch(reject)\n })\n }\n\n /**\n * Merge the default metric labels (`app`, `dyno_id`, `process_type`)\n * with custom label names.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabels = (labels = []) => {\n return [...Object.keys(this.defaultLabels), ...labels]\n }\n\n /**\n * Merge default labels without dyno_id (`app`, `process_type`) with custom label names.\n * Use for HTTP metrics so dyno_id is not included.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabelsWithoutDynoId = (labels = []) => {\n return [...Object.keys(this.defaultLabelsWithoutDynoId), ...labels]\n }\n\n getDefaultLabels = (labels = []) => {\n return this.defaultLabels\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n // GETTERS\n\n get metricsEnabled() {\n return this.enabled\n }\n\n get metricsLogValues() {\n return this.logValues\n }\n\n get registry() {\n return this._registry\n }\n\n async getMetricsAsString() {\n return this._registry.metrics()\n }\n\n metricsMiddleware() {\n return async (req, res) => {\n try {\n const metrics = await this.getMetricsAsString()\n res.set('Content-Type', client.register.contentType)\n res.end(metrics)\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to get metrics:`, err)\n res.status(500).end('Failed to collect metrics')\n }\n }\n }\n}\n\nmodule.exports = { BaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"baseMetricsClient.js","names":["client","require","https","http","URL","BaseMetricsClient","constructor","config","appName","process","env","BUILD_APP_NAME","dynoId","HOSTNAME","processType","BUILD_DYNO_PROCESS_TYPE","enabled","METRICS_ENABLED","logValues","METRICS_LOG_VALUES","pushgatewayUrl","METRICS_PUSHGATEWAY_URL","authToken","pushgatewaySecret","METRICS_PUSHGATEWAY_SECRET","intervalSec","parseInt","METRICS_INTERVAL_SEC","startupValidation","disablePushgateway","METRICS_DISABLE_PUSHGATEWAY","removeOldMetrics","METRICS_REMOVE_OLD_METRICS","prefixLogs","_registry","Registry","blockNodeDefaultMetrics","collectDefaultMetrics","register","defaultLabels","app","dyno_id","process_type","defaultLabelsWithoutDynoId","gateway","gauges","counters","countersFunctions","gaugeUpdaters","_clearOldWorkers","_setCleanupHandlers","keepProcessAliveWhenDisabled","createGauge","name","help","updateFn","labelNames","Object","keys","g","Gauge","registers","createCounter","useLabelsWithoutDynoId","defaultSet","c","Counter","data","value","inc","clearAllCounters","metricsLogValues","console","log","values","forEach","counter","reset","_pushMetrics","entries","result","val","Promise","undefined","set","err","error","gatewayPush","metrics","getMetricsAsJSON","JSON","stringify","_startPush","interval","customPushMetics","warn","_idleInterval","setInterval","clearInterval","runPush","resolve","pushMetrics","catch","pushOrigin","trim","origin","startPush","cleanup","gatewayDelete","exit","_deleteFromVMByLabels","message","esc","s","String","replace","selector","u","reject","Error","path","encodeURIComponent","req","protocol","request","hostname","port","method","headers","Authorization","agent","Agent","keepAlive","res","statusCode","on","chunk","end","params","_pushToVMAgent","pushUrl","pathname","search","contentType","then","setHeader","Buffer","byteLength","withDefaultLabels","labels","withDefaultLabelsWithoutDynoId","getDefaultLabels","metricsEnabled","registry","getMetricsAsString","metricsMiddleware","status","module","exports"],"sources":["../../src/metrics/baseMetricsClient.js"],"sourcesContent":["const client = require('prom-client')\nconst https = require('https')\nconst http = require('http')\nconst { URL } = require('url')\n\n/**\n * BaseMetricsClient provides common functionality for all metrics clients.\n * Handles registry setup, push to remote (VM-agent), default labels, and common operations.\n * Always pushes registry to the configured URL (POST Prometheus text format + Basic auth). No Pushgateway.\n */\nclass BaseMetricsClient {\n /**\n * @param {Object} config\n * @param {string} [config.appName] Name of the application\n * @param {string} [config.dynoId] Dyno/instance ID\n * @param {string} [config.processType] Process type (web, worker, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] Push URL (VM-agent import endpoint, e.g. .../api/v1/import/prometheus). /metrics is for GET (scrape), not POST (push).\n * @param {string} [config.pushgatewaySecret] Basic auth secret (Base64 of user:password)\n * @param {number} [config.intervalSec] Interval in seconds for pushing metrics\n * @param {boolean} [config.removeOldMetrics] Enable to clear metrics by service name\n * @param {function} [config.startupValidation] Add to validate on start push.\n * @param {boolean} [config.disablePushgateway] Disable pushing to Pushgateway (use HTTP scraping instead)\n * @param {boolean} [config.blockNodeDefaultMetrics] When true, do not register prom-client default process metrics (heap, event loop, etc.). Default false — used by HTTP-only collectors.\n */\n constructor(config = {}) {\n this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app'\n this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno'\n this.processType =\n config.processType ||\n process.env.BUILD_DYNO_PROCESS_TYPE ||\n 'undefined_build_dyno_type'\n this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true'\n this.logValues =\n config.logValues ?? process.env.METRICS_LOG_VALUES === 'true'\n this.pushgatewayUrl =\n config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || ''\n this.authToken =\n config.pushgatewaySecret || process.env.METRICS_PUSHGATEWAY_SECRET || ''\n this.intervalSec =\n config.intervalSec ||\n parseInt(process.env.METRICS_INTERVAL_SEC || '', 10) ||\n 15\n this.startupValidation = config.startupValidation\n this.disablePushgateway =\n config.disablePushgateway ??\n process.env.METRICS_DISABLE_PUSHGATEWAY === 'true'\n this.removeOldMetrics =\n config.removeOldMetrics ??\n process.env.METRICS_REMOVE_OLD_METRICS === 'true'\n\n this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`\n\n this._registry = new client.Registry()\n if (config.blockNodeDefaultMetrics) {\n client.collectDefaultMetrics({ register: this._registry })\n }\n\n this.defaultLabels = {\n app: this.appName,\n dyno_id: this.dynoId,\n process_type: this.processType,\n }\n\n /** Default labels without dyno_id (for HTTP metrics so dyno_id is not included). */\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: this.processType,\n }\n\n // Always push to configured URL (VM-agent). No Pushgateway.\n this.gateway = null\n this.gauges = {}\n this.counters = {}\n this.countersFunctions = {}\n\n /** @type {Object<string, function(): number | Promise<number>>} */\n this.gaugeUpdaters = {}\n\n this._clearOldWorkers(config.removeOldMetrics)\n this._setCleanupHandlers()\n\n this.keepProcessAliveWhenDisabled = true\n }\n\n /**\n * Create a gauge metric.\n * @param {Object} options - Gauge configuration\n * @param {string} options.name - Name of the gauge\n * @param {string} options.help - Help text describing the gauge\n * @param {function(): number|Promise<number>} [options.updateFn] - Optional function returning the gauge value\n * @param {string[]} [options.labelNames] - Optional custom label names\n * @returns {import('prom-client').Gauge} The created Prometheus gauge\n */\n createGauge = ({\n name,\n help,\n updateFn,\n labelNames = Object.keys(this.defaultLabels),\n }) => {\n if (this.gauges[name]) return this.gauges[name]\n\n const g = new client.Gauge({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.gauges[name] = g\n\n if (updateFn && typeof updateFn === 'function') {\n this.gaugeUpdaters[name] = updateFn\n }\n\n return g\n }\n\n /**\n * Create a Prometheus Counter metric.\n *\n * @param {Object} params - Counter configuration\n * @param {string} params.name - Metric name\n * @param {string} params.help - Metric description\n * @param {string[]} [params.labelNames] - Optional list of label names. Defaults to this.defaultLabels keys.\n * @param {boolean} [params.useLabelsWithoutDynoId=false] - If true, counter uses app/process_type only (no dyno_id). Use for HTTP metrics.\n *\n * @returns {(labels?: Object, incrementValue?: number) => void}\n * A function to increment the counter.\n * Usage: (labels?, incrementValue?)\n */\n createCounter({\n name,\n help,\n labelNames = Object.keys(this.defaultLabels),\n useLabelsWithoutDynoId = false,\n }) {\n if (this.counters[name]) return this.countersFunctions[name]\n\n const defaultSet = useLabelsWithoutDynoId\n ? this.defaultLabelsWithoutDynoId\n : this.defaultLabels\n\n const c = new client.Counter({\n name,\n help,\n labelNames,\n registers: [this._registry],\n })\n this.counters[name] = c\n\n this.countersFunctions = {\n ...this.countersFunctions,\n [name]: (data = {}, value = 1) => {\n c.inc({ ...defaultSet, ...data }, value)\n },\n }\n\n return this.countersFunctions[name]\n }\n\n /**\n * Clear all collected counters\n */\n clearAllCounters = () => {\n if (this.metricsLogValues) {\n console.log('Counters to clear: ', Object.keys(this.counters))\n }\n Object.values(this.counters).forEach(counter => counter.reset())\n }\n\n /**\n * Push all gauges and counters to PushGateway and optionally log.\n */\n _pushMetrics = async () => {\n try {\n for (const [name, updateFn] of Object.entries(this.gaugeUpdaters)) {\n try {\n if (!updateFn) {\n continue\n }\n const result = updateFn()\n const val = result instanceof Promise ? await result : result\n if (val !== undefined) this.gauges[name].set(this.defaultLabels, val)\n } catch (err) {\n console.error(\n `${this.prefixLogs} Failed to update gauge ${name}:`,\n err\n )\n }\n }\n\n if (!this.disablePushgateway) {\n await this.gatewayPush()\n }\n // this.clearAllCounters() //TODO: or uncommit or delete (based on grafana expectation)\n\n if (this.logValues) {\n const metrics = await this._registry.getMetricsAsJSON()\n console.log(\n `${this.prefixLogs} Metrics:\\n`,\n JSON.stringify(metrics, null, 2)\n )\n }\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n }\n }\n\n _startPush = (interval = this.intervalSec, customPushMetics = undefined) => {\n if (!this.enabled) {\n console.warn(`${this.prefixLogs} Metrics disabled`)\n if (this.keepProcessAliveWhenDisabled && !this._idleInterval) {\n this._idleInterval = setInterval(() => {}, 60 * 60 * 1000)\n }\n return\n }\n\n if (this._idleInterval) {\n clearInterval(this._idleInterval)\n this._idleInterval = null\n }\n\n if (this.startupValidation && !this.startupValidation()) {\n return\n }\n\n const runPush = () => {\n if (customPushMetics && typeof customPushMetics === 'function') {\n return Promise.resolve(customPushMetics())\n }\n return this.pushMetrics()\n }\n\n if (customPushMetics && typeof customPushMetics === 'function') {\n setInterval(() => customPushMetics(), interval * 1000)\n } else {\n setInterval(() => {\n runPush().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics:`, err)\n })\n }, interval * 1000)\n }\n\n // First push immediately so metrics appear without waiting for the first interval\n runPush().catch(err => {\n console.error(`${this.prefixLogs} Failed to push metrics (initial):`, err)\n })\n\n let pushOrigin = 'none'\n try {\n if (this.pushgatewayUrl && this.pushgatewayUrl.trim()) {\n pushOrigin = new URL(this.pushgatewayUrl.trim()).origin\n }\n } catch {\n pushOrigin = 'invalid URL'\n }\n console.warn(\n `${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s, push: ${pushOrigin})`\n )\n }\n\n pushMetrics = async () => {\n return this._pushMetrics()\n }\n\n /**\n * Start periodic metrics collection and push.\n *\n * This method wraps the internal `_startPush` method.\n * If a `customPushMetrics` function is provided, it will be executed\n * at the given interval instead of the default `pushMetrics` behavior.\n *\n * @param {number} [interval=this.intervalSec] - Interval in seconds between pushes.\n * @param {() => void | Promise<void>} [customPushMetrics] - Optional custom push function. If provided, Prometheus push is skipped.\n */\n startPush = (interval, customPushMetics = undefined) => {\n this._startPush(interval, customPushMetics)\n }\n\n /**\n * Cleanup metrics and exit process.\n * @returns {Promise<void>}\n */\n cleanup = async () => {\n if (this.enabled) {\n await this.gatewayDelete()\n }\n process.exit(0)\n }\n\n /**\n * Remove old/stale dyno/instance metrics from PushGateway.\n *\n * Compares existing PushGateway metrics for this job and deletes any instances\n * that do not match the current dynoId.\n *\n * @param {boolean} removeOldMetrics If true, performs cleanup; otherwise does nothing\n * @returns {Promise<void>}\n * @private\n */\n _clearOldWorkers = async removeOldMetrics => {\n // No Pushgateway; VM-agent does not support per-instance delete. Skip.\n }\n\n /**\n * On shutdown: optionally delete this instance's metrics from VictoriaMetrics (by app, dyno_id, process_type).\n * @returns {Promise<void>}\n */\n gatewayDelete = async () => {\n if (\n this.removeOldMetrics &&\n this.pushgatewayUrl &&\n this.pushgatewayUrl.trim()\n ) {\n await this._deleteFromVMByLabels().catch(err => {\n console.warn(\n `${this.prefixLogs} Deletion from VM on shutdown failed:`,\n err.message\n )\n })\n }\n }\n\n /**\n * Call VictoriaMetrics delete_series API to remove all series matching this instance's labels (app, dyno_id, process_type).\n * @private\n */\n _deleteFromVMByLabels = () => {\n const esc = s => String(s).replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')\n const selector = `{app=\"${esc(this.appName)}\",dyno_id=\"${esc(\n this.dynoId\n )}\",process_type=\"${esc(this.processType)}\"}`\n let origin\n try {\n const u = new URL((this.pushgatewayUrl || '').trim())\n origin = u.origin\n } catch {\n return Promise.reject(new Error('Invalid push URL'))\n }\n const path = `/api/v1/admin/tsdb/delete_series?match[]=${encodeURIComponent(\n selector\n )}`\n return new Promise((resolve, reject) => {\n const u = new URL(origin)\n const req = (u.protocol === 'https:' ? https : http).request(\n {\n hostname: u.hostname,\n port: u.port || (u.protocol === 'https:' ? 443 : 80),\n path,\n method: 'POST',\n headers: {\n 'Content-Length': '0',\n Authorization: this.authToken\n ? `Basic ${this.authToken}`\n : undefined,\n },\n agent:\n u.protocol === 'https:'\n ? new https.Agent({ keepAlive: false })\n : undefined,\n },\n res => {\n if (res.statusCode >= 200 && res.statusCode < 300) resolve()\n else {\n let data = ''\n res.on('data', chunk => {\n data += chunk\n })\n res.on('end', () =>\n reject(new Error(`Delete failed: ${res.statusCode} ${data}`))\n )\n }\n }\n )\n req.on('error', reject)\n req.end()\n })\n }\n\n /**\n * Push registry to configured URL (VM-agent). POST Prometheus text format + Basic auth.\n *\n * @param {object} [params] Unused; kept for API compatibility.\n * @returns {Promise<void>}\n */\n gatewayPush = async (params = {}) => {\n if (this.disablePushgateway) {\n console.warn(\n `${this.prefixLogs} Metrics push skipped: METRICS_DISABLE_PUSHGATEWAY is set`\n )\n return Promise.resolve()\n }\n if (!this.pushgatewayUrl || !this.pushgatewayUrl.trim()) {\n console.warn(\n `${this.prefixLogs} Metrics push skipped: METRICS_PUSHGATEWAY_URL is not set`\n )\n return Promise.resolve()\n }\n return this._pushToVMAgent()\n }\n\n /**\n * POST registry (Prometheus text format) to VM-agent. VM-agent accepts push at /api/v1/import/prometheus; /metrics is GET (scrape) only.\n * @private\n */\n _pushToVMAgent = () => {\n let pushUrl = (this.pushgatewayUrl || '').trim()\n try {\n const u = new URL(pushUrl)\n if (!u.pathname || u.pathname === '/' || u.pathname === '/metrics') {\n pushUrl = `${u.origin}/api/v1/import/prometheus${u.search}`\n }\n } catch {\n // leave pushUrl as-is\n }\n return new Promise((resolve, reject) => {\n const u = new URL(pushUrl)\n const req = (u.protocol === 'https:' ? https : http).request(\n {\n hostname: u.hostname,\n port: u.port || (u.protocol === 'https:' ? 443 : 80),\n path: u.pathname + u.search,\n method: 'POST',\n headers: {\n 'Content-Type': client.register.contentType,\n Authorization: this.authToken\n ? `Basic ${this.authToken}`\n : undefined,\n },\n agent:\n u.protocol === 'https:'\n ? new https.Agent({ keepAlive: true })\n : undefined,\n },\n res => {\n if (res.statusCode >= 200 && res.statusCode < 300) {\n resolve()\n } else {\n let data = ''\n res.on('data', chunk => {\n data += chunk\n })\n res.on('end', () =>\n reject(new Error(`Push failed: ${res.statusCode} ${data}`))\n )\n }\n }\n )\n req.on('error', reject)\n this._registry\n .metrics()\n .then(metrics => {\n req.setHeader('Content-Length', Buffer.byteLength(metrics, 'utf8'))\n req.end(metrics, 'utf8')\n })\n .catch(reject)\n })\n }\n\n /**\n * Merge the default metric labels (`app`, `dyno_id`, `process_type`)\n * with custom label names.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabels = (labels = []) => {\n return [...Object.keys(this.defaultLabels), ...labels]\n }\n\n /**\n * Merge default labels without dyno_id (`app`, `process_type`) with custom label names.\n * Use for HTTP metrics so dyno_id is not included.\n *\n * @param {string[]} labels Additional label names\n * @returns {string[]} Combined label names\n */\n withDefaultLabelsWithoutDynoId = (labels = []) => {\n return [...Object.keys(this.defaultLabelsWithoutDynoId), ...labels]\n }\n\n getDefaultLabels = (labels = []) => {\n return this.defaultLabels\n }\n\n _setCleanupHandlers = () => {\n process.on('SIGINT', this.cleanup)\n process.on('SIGTERM', this.cleanup)\n }\n\n // GETTERS\n\n get metricsEnabled() {\n return this.enabled\n }\n\n get metricsLogValues() {\n return this.logValues\n }\n\n get registry() {\n return this._registry\n }\n\n async getMetricsAsString() {\n return this._registry.metrics()\n }\n\n metricsMiddleware() {\n return async (req, res) => {\n try {\n const metrics = await this.getMetricsAsString()\n res.set('Content-Type', client.register.contentType)\n res.end(metrics)\n } catch (err) {\n console.error(`${this.prefixLogs} Failed to get metrics:`, err)\n res.status(500).end('Failed to collect metrics')\n }\n }\n }\n}\n\nmodule.exports = { BaseMetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drain worker: reads HTTP aggregates from Redis (written by {@link HttpMetricsRedisRecorder}),
|
|
3
|
+
* applies them to `app_requests_*` counters, then pushes the registry to the VM-agent (same as {@link BaseMetricsClient}).
|
|
4
|
+
* **Minimal usage:** `{ redisClient }` only. Redis keys use segment **`web`** unless you pass **`redisProcessTypeForKeys`**.
|
|
5
|
+
* `processType` / `appName` / `dynoId` follow {@link BaseMetricsClient} defaults (e.g. `BUILD_DYNO_PROCESS_TYPE`) and do **not** select Redis hash names.
|
|
6
|
+
* Always passes `blockNodeDefaultMetrics: true` (HTTP-focused registry).
|
|
7
|
+
*
|
|
8
|
+
* @extends BaseMetricsClient
|
|
9
|
+
*/
|
|
10
|
+
export class HttpMetricsRedisCollector extends BaseMetricsClient {
|
|
11
|
+
/**
|
|
12
|
+
* @param {Object} [config]
|
|
13
|
+
* @param {import('redis').RedisClient} config.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).
|
|
14
|
+
* @param {string} [config.appName] Application name (defaults per {@link BaseMetricsClient})
|
|
15
|
+
* @param {string} [config.dynoId] Dyno/instance ID
|
|
16
|
+
* @param {string} [config.processType] Label `process_type` on push (default from env / base)
|
|
17
|
+
* @param {boolean} [config.enabled] Enable collection and push
|
|
18
|
+
* @param {boolean} [config.logValues] Log metric JSON to console
|
|
19
|
+
* @param {string} [config.pushgatewayUrl] VM-agent import URL
|
|
20
|
+
* @param {string} [config.pushgatewaySecret] Basic auth secret (Base64)
|
|
21
|
+
* @param {number} [config.intervalSec] Push interval (seconds)
|
|
22
|
+
* @param {boolean} [config.removeOldMetrics] Clear old series on shutdown where supported
|
|
23
|
+
* @param {function} [config.startupValidation] Run before first push
|
|
24
|
+
* @param {boolean} [config.disablePushgateway] Skip POST to VM-agent
|
|
25
|
+
* @param {string} [config.redisProcessTypeForKeys] Segment in Redis keys for HTTP hashes (default **`web`**). Optional; only if writers use a non-`web` segment.
|
|
26
|
+
* @param {number} [config.ttlSec] Passed to {@link HttpMetricsRedisStore} (should match writers)
|
|
27
|
+
*/
|
|
28
|
+
constructor(config?: {
|
|
29
|
+
redisClient: import('redis').RedisClient;
|
|
30
|
+
appName?: string | undefined;
|
|
31
|
+
dynoId?: string | undefined;
|
|
32
|
+
processType?: string | undefined;
|
|
33
|
+
enabled?: boolean | undefined;
|
|
34
|
+
logValues?: boolean | undefined;
|
|
35
|
+
pushgatewayUrl?: string | undefined;
|
|
36
|
+
pushgatewaySecret?: string | undefined;
|
|
37
|
+
intervalSec?: number | undefined;
|
|
38
|
+
removeOldMetrics?: boolean | undefined;
|
|
39
|
+
startupValidation?: Function | undefined;
|
|
40
|
+
disablePushgateway?: boolean | undefined;
|
|
41
|
+
redisProcessTypeForKeys?: string | undefined;
|
|
42
|
+
ttlSec?: number | undefined;
|
|
43
|
+
} | undefined);
|
|
44
|
+
_store: HttpMetricsRedisStore;
|
|
45
|
+
/** @type {Set<string>} Redis field keys already primed with inc(0) + push in this process */
|
|
46
|
+
_httpCounterPrimedKeys: Set<string>;
|
|
47
|
+
}
|
|
48
|
+
import { BaseMetricsClient } from "./baseMetricsClient";
|
|
49
|
+
import { HttpMetricsRedisStore } from "./httpMetricsRedisStore";
|
|
50
|
+
//# sourceMappingURL=httpMetricsRedisCollector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpMetricsRedisCollector.d.ts","sourceRoot":"","sources":["../../src/metrics/httpMetricsRedisCollector.js"],"names":[],"mappings":"AAMA;;;;;;;;GAQG;AACH;IACE;;;;;;;;;;;;;;;;OAgBG;IACH;qBAfW,OAAO,OAAO,EAAE,WAAW;;;;;;;;;;;;;;mBAgErC;IA/BC,8BAKE;IAEF,6FAA6F;IAC7F,wBADW,IAAI,MAAM,CAAC,CACiB;CAqE1C"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
BaseMetricsClient
|
|
5
|
+
} = require('./baseMetricsClient');
|
|
6
|
+
const {
|
|
7
|
+
HttpMetricsRedisStore,
|
|
8
|
+
buildFieldKey
|
|
9
|
+
} = require('./httpMetricsRedisStore');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Drain worker: reads HTTP aggregates from Redis (written by {@link HttpMetricsRedisRecorder}),
|
|
13
|
+
* applies them to `app_requests_*` counters, then pushes the registry to the VM-agent (same as {@link BaseMetricsClient}).
|
|
14
|
+
* **Minimal usage:** `{ redisClient }` only. Redis keys use segment **`web`** unless you pass **`redisProcessTypeForKeys`**.
|
|
15
|
+
* `processType` / `appName` / `dynoId` follow {@link BaseMetricsClient} defaults (e.g. `BUILD_DYNO_PROCESS_TYPE`) and do **not** select Redis hash names.
|
|
16
|
+
* Always passes `blockNodeDefaultMetrics: true` (HTTP-focused registry).
|
|
17
|
+
*
|
|
18
|
+
* @extends BaseMetricsClient
|
|
19
|
+
*/
|
|
20
|
+
class HttpMetricsRedisCollector extends BaseMetricsClient {
|
|
21
|
+
/**
|
|
22
|
+
* @param {Object} [config]
|
|
23
|
+
* @param {import('redis').RedisClient} config.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).
|
|
24
|
+
* @param {string} [config.appName] Application name (defaults per {@link BaseMetricsClient})
|
|
25
|
+
* @param {string} [config.dynoId] Dyno/instance ID
|
|
26
|
+
* @param {string} [config.processType] Label `process_type` on push (default from env / base)
|
|
27
|
+
* @param {boolean} [config.enabled] Enable collection and push
|
|
28
|
+
* @param {boolean} [config.logValues] Log metric JSON to console
|
|
29
|
+
* @param {string} [config.pushgatewayUrl] VM-agent import URL
|
|
30
|
+
* @param {string} [config.pushgatewaySecret] Basic auth secret (Base64)
|
|
31
|
+
* @param {number} [config.intervalSec] Push interval (seconds)
|
|
32
|
+
* @param {boolean} [config.removeOldMetrics] Clear old series on shutdown where supported
|
|
33
|
+
* @param {function} [config.startupValidation] Run before first push
|
|
34
|
+
* @param {boolean} [config.disablePushgateway] Skip POST to VM-agent
|
|
35
|
+
* @param {string} [config.redisProcessTypeForKeys] Segment in Redis keys for HTTP hashes (default **`web`**). Optional; only if writers use a non-`web` segment.
|
|
36
|
+
* @param {number} [config.ttlSec] Passed to {@link HttpMetricsRedisStore} (should match writers)
|
|
37
|
+
*/
|
|
38
|
+
constructor(config = {}) {
|
|
39
|
+
const {
|
|
40
|
+
redisClient
|
|
41
|
+
} = config;
|
|
42
|
+
if (redisClient == null) {
|
|
43
|
+
throw new Error('HttpMetricsRedisCollector: redisClient is required');
|
|
44
|
+
}
|
|
45
|
+
super({
|
|
46
|
+
...config,
|
|
47
|
+
blockNodeDefaultMetrics: true
|
|
48
|
+
});
|
|
49
|
+
const keyProcessType = config.redisProcessTypeForKeys || 'web';
|
|
50
|
+
this.defaultLabelsWithoutDynoId = {
|
|
51
|
+
app: this.appName,
|
|
52
|
+
process_type: keyProcessType
|
|
53
|
+
};
|
|
54
|
+
this._store = new HttpMetricsRedisStore({
|
|
55
|
+
redisClient,
|
|
56
|
+
appName: this.appName,
|
|
57
|
+
processType: keyProcessType,
|
|
58
|
+
ttlSec: config.ttlSec
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** @type {Set<string>} Redis field keys already primed with inc(0) + push in this process */
|
|
62
|
+
this._httpCounterPrimedKeys = new Set();
|
|
63
|
+
this.createCounter({
|
|
64
|
+
name: 'app_requests_total',
|
|
65
|
+
help: 'Total number of HTTP requests',
|
|
66
|
+
labelNames: this.withDefaultLabelsWithoutDynoId(['method', 'route', 'status_code']),
|
|
67
|
+
useLabelsWithoutDynoId: true
|
|
68
|
+
});
|
|
69
|
+
this.createCounter({
|
|
70
|
+
name: 'app_requests_total_duration',
|
|
71
|
+
help: 'Total duration of HTTP requests in milliseconds',
|
|
72
|
+
labelNames: this.withDefaultLabelsWithoutDynoId(['method', 'route', 'status_code']),
|
|
73
|
+
useLabelsWithoutDynoId: true
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Drains Redis into counters, then runs gauge updates and VM-agent push ({@link BaseMetricsClient#_pushMetrics}).
|
|
79
|
+
* @returns {Promise<void>}
|
|
80
|
+
*/
|
|
81
|
+
pushMetrics = async () => {
|
|
82
|
+
if (this._store && this.countersFunctions?.app_requests_total && this.countersFunctions?.app_requests_total_duration) {
|
|
83
|
+
const {
|
|
84
|
+
ok,
|
|
85
|
+
rows
|
|
86
|
+
} = await this._store.drainRows();
|
|
87
|
+
if (ok && rows.length > 0) {
|
|
88
|
+
const applyCount = (labels, value) => this.countersFunctions.app_requests_total(labels, value);
|
|
89
|
+
const applyDur = (labels, value) => this.countersFunctions.app_requests_total_duration(labels, value);
|
|
90
|
+
let primedAny = false;
|
|
91
|
+
for (const row of rows) {
|
|
92
|
+
const key = buildFieldKey(row.labels.method, row.labels.route, row.labels.status_code);
|
|
93
|
+
if (!this._httpCounterPrimedKeys.has(key)) {
|
|
94
|
+
this._httpCounterPrimedKeys.add(key);
|
|
95
|
+
applyCount(row.labels, 0);
|
|
96
|
+
applyDur(row.labels, 0);
|
|
97
|
+
primedAny = true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (primedAny) {
|
|
101
|
+
await this.gatewayPush();
|
|
102
|
+
}
|
|
103
|
+
for (const row of rows) {
|
|
104
|
+
applyCount(row.labels, row.count);
|
|
105
|
+
if (row.dur > 0) {
|
|
106
|
+
applyDur(row.labels, row.dur);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return this._pushMetrics();
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
module.exports = {
|
|
115
|
+
HttpMetricsRedisCollector
|
|
116
|
+
};
|
|
117
|
+
//# sourceMappingURL=httpMetricsRedisCollector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpMetricsRedisCollector.js","names":["BaseMetricsClient","require","HttpMetricsRedisStore","buildFieldKey","HttpMetricsRedisCollector","constructor","config","redisClient","Error","blockNodeDefaultMetrics","keyProcessType","redisProcessTypeForKeys","defaultLabelsWithoutDynoId","app","appName","process_type","_store","processType","ttlSec","_httpCounterPrimedKeys","Set","createCounter","name","help","labelNames","withDefaultLabelsWithoutDynoId","useLabelsWithoutDynoId","pushMetrics","countersFunctions","app_requests_total","app_requests_total_duration","ok","rows","drainRows","length","applyCount","labels","value","applyDur","primedAny","row","key","method","route","status_code","has","add","gatewayPush","count","dur","_pushMetrics","module","exports"],"sources":["../../src/metrics/httpMetricsRedisCollector.js"],"sourcesContent":["const { BaseMetricsClient } = require('./baseMetricsClient')\nconst {\n HttpMetricsRedisStore,\n buildFieldKey,\n} = require('./httpMetricsRedisStore')\n\n/**\n * Drain worker: reads HTTP aggregates from Redis (written by {@link HttpMetricsRedisRecorder}),\n * applies them to `app_requests_*` counters, then pushes the registry to the VM-agent (same as {@link BaseMetricsClient}).\n * **Minimal usage:** `{ redisClient }` only. Redis keys use segment **`web`** unless you pass **`redisProcessTypeForKeys`**.\n * `processType` / `appName` / `dynoId` follow {@link BaseMetricsClient} defaults (e.g. `BUILD_DYNO_PROCESS_TYPE`) and do **not** select Redis hash names.\n * Always passes `blockNodeDefaultMetrics: true` (HTTP-focused registry).\n *\n * @extends BaseMetricsClient\n */\nclass HttpMetricsRedisCollector extends BaseMetricsClient {\n /**\n * @param {Object} [config]\n * @param {import('redis').RedisClient} config.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).\n * @param {string} [config.appName] Application name (defaults per {@link BaseMetricsClient})\n * @param {string} [config.dynoId] Dyno/instance ID\n * @param {string} [config.processType] Label `process_type` on push (default from env / base)\n * @param {boolean} [config.enabled] Enable collection and push\n * @param {boolean} [config.logValues] Log metric JSON to console\n * @param {string} [config.pushgatewayUrl] VM-agent import URL\n * @param {string} [config.pushgatewaySecret] Basic auth secret (Base64)\n * @param {number} [config.intervalSec] Push interval (seconds)\n * @param {boolean} [config.removeOldMetrics] Clear old series on shutdown where supported\n * @param {function} [config.startupValidation] Run before first push\n * @param {boolean} [config.disablePushgateway] Skip POST to VM-agent\n * @param {string} [config.redisProcessTypeForKeys] Segment in Redis keys for HTTP hashes (default **`web`**). Optional; only if writers use a non-`web` segment.\n * @param {number} [config.ttlSec] Passed to {@link HttpMetricsRedisStore} (should match writers)\n */\n constructor(config = {}) {\n const { redisClient } = config\n if (redisClient == null) {\n throw new Error('HttpMetricsRedisCollector: redisClient is required')\n }\n\n super({\n ...config,\n blockNodeDefaultMetrics: true,\n })\n\n const keyProcessType = config.redisProcessTypeForKeys || 'web'\n\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: keyProcessType,\n }\n\n this._store = new HttpMetricsRedisStore({\n redisClient,\n appName: this.appName,\n processType: keyProcessType,\n ttlSec: config.ttlSec,\n })\n\n /** @type {Set<string>} Redis field keys already primed with inc(0) + push in this process */\n this._httpCounterPrimedKeys = new Set()\n\n this.createCounter({\n name: 'app_requests_total',\n help: 'Total number of HTTP requests',\n labelNames: this.withDefaultLabelsWithoutDynoId([\n 'method',\n 'route',\n 'status_code',\n ]),\n useLabelsWithoutDynoId: true,\n })\n\n this.createCounter({\n name: 'app_requests_total_duration',\n help: 'Total duration of HTTP requests in milliseconds',\n labelNames: this.withDefaultLabelsWithoutDynoId([\n 'method',\n 'route',\n 'status_code',\n ]),\n useLabelsWithoutDynoId: true,\n })\n }\n\n /**\n * Drains Redis into counters, then runs gauge updates and VM-agent push ({@link BaseMetricsClient#_pushMetrics}).\n * @returns {Promise<void>}\n */\n pushMetrics = async () => {\n if (\n this._store &&\n this.countersFunctions?.app_requests_total &&\n this.countersFunctions?.app_requests_total_duration\n ) {\n const { ok, rows } = await this._store.drainRows()\n if (ok && rows.length > 0) {\n const applyCount = (labels, value) =>\n this.countersFunctions.app_requests_total(labels, value)\n const applyDur = (labels, value) =>\n this.countersFunctions.app_requests_total_duration(labels, value)\n\n let primedAny = false\n for (const row of rows) {\n const key = buildFieldKey(\n row.labels.method,\n row.labels.route,\n row.labels.status_code\n )\n if (!this._httpCounterPrimedKeys.has(key)) {\n this._httpCounterPrimedKeys.add(key)\n applyCount(row.labels, 0)\n applyDur(row.labels, 0)\n primedAny = true\n }\n }\n if (primedAny) {\n await this.gatewayPush()\n }\n for (const row of rows) {\n applyCount(row.labels, row.count)\n if (row.dur > 0) {\n applyDur(row.labels, row.dur)\n }\n }\n }\n }\n return this._pushMetrics()\n }\n}\n\nmodule.exports = { HttpMetricsRedisCollector }\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Records HTTP request aggregates only to Redis (no in-process Prometheus counters on this path).
|
|
3
|
+
* Pair with {@link HttpMetricsRedisCollector} on a drain process to flush into counters and push to the VM-agent.
|
|
4
|
+
*
|
|
5
|
+
* @see HttpMetricsRedisStore
|
|
6
|
+
*/
|
|
7
|
+
export class HttpMetricsRedisRecorder {
|
|
8
|
+
/**
|
|
9
|
+
* @param {Object} opts
|
|
10
|
+
* @param {import('redis').RedisClient} opts.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).
|
|
11
|
+
* @param {string} [opts.appName] Optional override; default same as {@link BaseMetricsClient}: `BUILD_APP_NAME` or `unknown-app`.
|
|
12
|
+
* @param {string} [opts.processType] Redis key segment (default **`web`**, same as {@link HttpMetricsRedisCollector}).
|
|
13
|
+
* @param {number} [opts.ttlSec] Redis hash key TTL in seconds (sliding; default 120).
|
|
14
|
+
*/
|
|
15
|
+
constructor({ redisClient, appName, processType, ttlSec }?: {
|
|
16
|
+
redisClient: import('redis').RedisClient;
|
|
17
|
+
appName?: string | undefined;
|
|
18
|
+
processType?: string | undefined;
|
|
19
|
+
ttlSec?: number | undefined;
|
|
20
|
+
});
|
|
21
|
+
processType: string;
|
|
22
|
+
appName: string;
|
|
23
|
+
_store: HttpMetricsRedisStore;
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object} params
|
|
26
|
+
* @param {string} params.method
|
|
27
|
+
* @param {string} params.route
|
|
28
|
+
* @param {number} params.status_code
|
|
29
|
+
* @param {number} params.duration
|
|
30
|
+
*/
|
|
31
|
+
trackHttpRequest({ method, route, status_code, duration }: {
|
|
32
|
+
method: string;
|
|
33
|
+
route: string;
|
|
34
|
+
status_code: number;
|
|
35
|
+
duration: number;
|
|
36
|
+
}): void;
|
|
37
|
+
/**
|
|
38
|
+
* Express middleware: appends a `finish` listener and writes one aggregate row per request to Redis.
|
|
39
|
+
* Does not check `METRICS_ENABLED`; the app should only mount this when HTTP Redis metrics should run.
|
|
40
|
+
*
|
|
41
|
+
* @param {import('http').IncomingMessage} req
|
|
42
|
+
* @param {import('http').ServerResponse} res
|
|
43
|
+
* @param {function} next
|
|
44
|
+
*/
|
|
45
|
+
trackHttpRequestMiddleware: (req: import('http').IncomingMessage, res: import('http').ServerResponse, next: Function) => void;
|
|
46
|
+
}
|
|
47
|
+
import { HttpMetricsRedisStore } from "./httpMetricsRedisStore";
|
|
48
|
+
//# sourceMappingURL=httpMetricsRedisRecorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpMetricsRedisRecorder.d.ts","sourceRoot":"","sources":["../../src/metrics/httpMetricsRedisRecorder.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH;IACE;;;;;;OAMG;IACH;QAL6C,WAAW,EAA7C,OAAO,OAAO,EAAE,WAAW;QACb,OAAO;QACP,WAAW;QACX,MAAM;OAgB9B;IARC,oBAA8B;IAC9B,gBAA8B;IAC9B,8BAKE;IAGJ;;;;;;OAMG;IACH;QAL0B,MAAM,EAArB,MAAM;QACS,KAAK,EAApB,MAAM;QACS,WAAW,EAA1B,MAAM;QACS,QAAQ,EAAvB,MAAM;aAIhB;IAED;;;;;;;OAOG;IACH,kCAJW,OAAO,MAAM,EAAE,eAAe,OAC9B,OAAO,MAAM,EAAE,cAAc,0BAsBvC;CACF"}
|