@adalo/metrics 0.0.0-staging.16 → 0.0.0-staging.18
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 +16 -27
- 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 +3 -5
- package/lib/metrics/baseMetricsClient.d.ts.map +1 -1
- package/lib/metrics/baseMetricsClient.js +5 -12
- package/lib/metrics/baseMetricsClient.js.map +1 -1
- package/lib/metrics/httpMetricsRedisCollector.d.ts +47 -0
- package/lib/metrics/httpMetricsRedisCollector.d.ts.map +1 -0
- package/lib/metrics/httpMetricsRedisCollector.js +108 -0
- package/lib/metrics/httpMetricsRedisCollector.js.map +1 -0
- package/lib/metrics/httpMetricsRedisRecorder.d.ts +52 -0
- package/lib/metrics/httpMetricsRedisRecorder.d.ts.map +1 -0
- package/lib/metrics/httpMetricsRedisRecorder.js +93 -0
- package/lib/metrics/httpMetricsRedisRecorder.js.map +1 -0
- package/lib/metrics/httpMetricsRedisStore.d.ts +39 -10
- package/lib/metrics/httpMetricsRedisStore.d.ts.map +1 -1
- package/lib/metrics/httpMetricsRedisStore.js +62 -30
- package/lib/metrics/httpMetricsRedisStore.js.map +1 -1
- package/lib/metrics/metricsClient.d.ts +58 -42
- package/lib/metrics/metricsClient.d.ts.map +1 -1
- package/lib/metrics/metricsClient.js +89 -225
- package/lib/metrics/metricsClient.js.map +1 -1
- package/lib/metrics/metricsDatabaseClient.d.ts.map +1 -1
- package/lib/metrics/metricsDatabaseClient.js +4 -0
- package/lib/metrics/metricsDatabaseClient.js.map +1 -1
- package/lib/metrics/metricsProcessTypeUtils.d.ts +29 -0
- package/lib/metrics/metricsProcessTypeUtils.d.ts.map +1 -0
- package/lib/metrics/metricsProcessTypeUtils.js +41 -0
- package/lib/metrics/metricsProcessTypeUtils.js.map +1 -0
- package/lib/metrics/metricsQueueRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsQueueRedisClient.js +4 -0
- package/lib/metrics/metricsQueueRedisClient.js.map +1 -1
- package/lib/metrics/metricsRedisClient.d.ts.map +1 -1
- package/lib/metrics/metricsRedisClient.js +4 -0
- package/lib/metrics/metricsRedisClient.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +4 -0
- package/src/metrics/baseMetricsClient.js +4 -13
- package/src/metrics/httpMetricsRedisCollector.js +131 -0
- package/src/metrics/httpMetricsRedisRecorder.js +93 -0
- package/src/metrics/httpMetricsRedisStore.js +85 -33
- package/src/metrics/metricsClient.js +86 -300
- package/src/metrics/metricsDatabaseClient.js +7 -0
- package/src/metrics/metricsProcessTypeUtils.js +47 -0
- package/src/metrics/metricsQueueRedisClient.js +7 -0
- package/src/metrics/metricsRedisClient.js +6 -0
- package/lib/metrics/shouldRunMetricsPush.d.ts +0 -20
- package/lib/metrics/shouldRunMetricsPush.d.ts.map +0 -1
- package/lib/metrics/shouldRunMetricsPush.js +0 -39
- package/lib/metrics/shouldRunMetricsPush.js.map +0 -1
- package/src/metrics/shouldRunMetricsPush.js +0 -43
package/README.md
CHANGED
|
@@ -14,37 +14,26 @@ Utility library for Prometheus metrics and HTTP request counting in Node.js appl
|
|
|
14
14
|
- In `package.json`: `"@adalo/metrics": "staging"` (resolves to latest `@adalo/metrics@staging`), or pin a specific version: `"@adalo/metrics": "0.0.0-staging.123"`.
|
|
15
15
|
- Deploy that app to staging and verify metrics/behavior. When satisfied, merge **metrics-js** into **main** and release a normal version; then update the app back to `"@adalo/metrics": "^x.y.z"` or `"latest"`.
|
|
16
16
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
## Constructor
|
|
18
|
+
```ts
|
|
19
|
+
new MetricsClient({
|
|
20
|
+
appName, // defaults: process.env.BUILD_APP_NAME || 'unknown-app'
|
|
21
|
+
dynoId, // defaults: process.env.HOSTNAME || 'unknown-dyno'
|
|
22
|
+
processType, // defaults: process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined_build_dyno_type'
|
|
23
|
+
enabled, // defaults: process.env.METRICS_ENABLED === 'true'
|
|
24
|
+
logValues, // defaults: process.env.METRICS_LOG_VALUES === 'true'
|
|
25
|
+
pushgatewayUrl, // defaults: process.env.METRICS_PUSHGATEWAY_URL || ''
|
|
26
|
+
pushgatewaySecret, // defaults: process.env.METRICS_PUSHGATEWAY_SECRET || '' (Base64 of user:password)
|
|
27
|
+
intervalSec, // defaults: process.env.METRICS_INTERVAL_SEC || 15
|
|
28
|
+
httpMetricsEnabled, // defaults: METRICS_HTTP_ENABLED === 'true' (in-process HTTP counters only)
|
|
29
|
+
})
|
|
23
30
|
```
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
## Constructor (`MetricsClient`)
|
|
28
|
-
|
|
29
|
-
All fields are optional; defaults come from environment variables where noted.
|
|
32
|
+
### HTTP metrics: `MetricsClient` vs Redis
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|-------|---------|
|
|
33
|
-
| `appName`, `dynoId`, `processType` | Label `app`, `dyno_id`, `process_type`. Use `processType: 'metrics'` for the Procfile **`metrics:`** worker (metrics-exporter) so HTTP Redis drain + push behaves correctly with `DYNO=metrics.*` or `BUILD_DYNO_PROCESS_TYPE=metrics`. |
|
|
34
|
-
| `enabled`, `logValues`, `pushgatewayUrl`, `pushgatewaySecret`, `intervalSec`, `removeOldMetrics`, `startupValidation`, `disablePushgateway`, `includeNodeDefaultMetrics` | Same as base client (push to VM-agent, interval, etc.). |
|
|
35
|
-
| `httpMetricsEnabled`, `httpMetricsRedisUrl`, `httpMetricsRedisAggregation` | HTTP counters / Redis aggregation (multi-dyno Redis HTTP). |
|
|
36
|
-
|
|
37
|
-
**`startPush(interval?, customPushMetrics?)`** — both arguments are optional. With no args, the interval is `intervalSec` from config / `METRICS_INTERVAL_SEC` (default 15s).
|
|
38
|
-
|
|
39
|
-
### Metrics exporter entrypoint
|
|
40
|
-
|
|
41
|
-
```ts
|
|
42
|
-
import { MetricsClient } from '@adalo/metrics'
|
|
43
|
-
|
|
44
|
-
const client = new MetricsClient({ processType: 'metrics' })
|
|
45
|
-
client.startPush()
|
|
46
|
-
```
|
|
34
|
+
**`MetricsClient`** only registers **in-process** `app_requests_*` counters when `METRICS_HTTP_ENABLED` / `httpMetricsEnabled` is on. For **Redis-backed** HTTP aggregation (multi-web / cluster), use **`HttpMetricsRedisRecorder`** (writers) and **`HttpMetricsRedisCollector`** (drain + push) with an injected **`redisClient`** — same idea as `RedisMetricsClient`, not mixed into `MetricsClient`.
|
|
47
35
|
|
|
36
|
+
`DatabaseMetricsClient` / `QueueRedisMetricsClient` / `RedisMetricsClient` call **`process.exit(0)` with no logs** if `BUILD_DYNO_PROCESS_TYPE` (or `processType`) does not match `database-metrics` / `queue-metrics` / (`redis-metrics` or `queue-metrics`) respectively.
|
|
48
37
|
## Example Usage
|
|
49
38
|
```ts
|
|
50
39
|
import { MetricsClient } from '@adalo/metrics-js'
|
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,7 +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.
|
|
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.
|
|
21
21
|
*/
|
|
22
22
|
constructor(config?: {
|
|
23
23
|
appName?: string | undefined;
|
|
@@ -31,12 +31,11 @@ export class BaseMetricsClient {
|
|
|
31
31
|
removeOldMetrics?: boolean | undefined;
|
|
32
32
|
startupValidation?: Function | undefined;
|
|
33
33
|
disablePushgateway?: boolean | undefined;
|
|
34
|
-
|
|
34
|
+
blockNodeDefaultMetrics?: boolean | undefined;
|
|
35
35
|
});
|
|
36
36
|
appName: string;
|
|
37
37
|
dynoId: string;
|
|
38
38
|
processType: string;
|
|
39
|
-
includeNodeDefaultMetrics: boolean;
|
|
40
39
|
enabled: boolean;
|
|
41
40
|
logValues: boolean;
|
|
42
41
|
pushgatewayUrl: string;
|
|
@@ -110,8 +109,7 @@ export class BaseMetricsClient {
|
|
|
110
109
|
_pushMetrics: () => Promise<void>;
|
|
111
110
|
_startPush: (interval?: number, customPushMetics?: undefined) => void;
|
|
112
111
|
_idleInterval: NodeJS.Timer | null | undefined;
|
|
113
|
-
|
|
114
|
-
pushMetrics(): Promise<void>;
|
|
112
|
+
pushMetrics: () => Promise<void>;
|
|
115
113
|
/**
|
|
116
114
|
* Start periodic metrics collection and push.
|
|
117
115
|
*
|
|
@@ -1 +1 @@
|
|
|
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,
|
|
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,13 +26,12 @@ 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.
|
|
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.
|
|
30
30
|
*/
|
|
31
31
|
constructor(config = {}) {
|
|
32
32
|
this.appName = config.appName || process.env.BUILD_APP_NAME || 'unknown-app';
|
|
33
33
|
this.dynoId = config.dynoId || process.env.HOSTNAME || 'unknown-dyno';
|
|
34
34
|
this.processType = config.processType || process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined_build_dyno_type';
|
|
35
|
-
this.includeNodeDefaultMetrics = config.includeNodeDefaultMetrics !== false;
|
|
36
35
|
this.enabled = config.enabled ?? process.env.METRICS_ENABLED === 'true';
|
|
37
36
|
this.logValues = config.logValues ?? process.env.METRICS_LOG_VALUES === 'true';
|
|
38
37
|
this.pushgatewayUrl = config.pushgatewayUrl || process.env.METRICS_PUSHGATEWAY_URL || '';
|
|
@@ -43,7 +42,7 @@ class BaseMetricsClient {
|
|
|
43
42
|
this.removeOldMetrics = config.removeOldMetrics ?? process.env.METRICS_REMOVE_OLD_METRICS === 'true';
|
|
44
43
|
this.prefixLogs = `[${this.processType}] [${this.appName}] [${this.dynoId}] [Monitoring]`;
|
|
45
44
|
this._registry = new client.Registry();
|
|
46
|
-
if (
|
|
45
|
+
if (config.blockNodeDefaultMetrics) {
|
|
47
46
|
client.collectDefaultMetrics({
|
|
48
47
|
register: this._registry
|
|
49
48
|
});
|
|
@@ -227,11 +226,9 @@ class BaseMetricsClient {
|
|
|
227
226
|
}
|
|
228
227
|
console.warn(`${this.prefixLogs} Metrics collection started. (interval: ${this.intervalSec}s, push: ${pushOrigin})`);
|
|
229
228
|
};
|
|
230
|
-
|
|
231
|
-
/** Must be a prototype method (not a class field) so subclasses can `super.pushMetrics()`. */
|
|
232
|
-
async pushMetrics() {
|
|
229
|
+
pushMetrics = async () => {
|
|
233
230
|
return this._pushMetrics();
|
|
234
|
-
}
|
|
231
|
+
};
|
|
235
232
|
|
|
236
233
|
/**
|
|
237
234
|
* Start periodic metrics collection and push.
|
|
@@ -361,7 +358,6 @@ class BaseMetricsClient {
|
|
|
361
358
|
}
|
|
362
359
|
return new Promise((resolve, reject) => {
|
|
363
360
|
const u = new URL(pushUrl);
|
|
364
|
-
let payloadBytes = 0;
|
|
365
361
|
const req = (u.protocol === 'https:' ? https : http).request({
|
|
366
362
|
hostname: u.hostname,
|
|
367
363
|
port: u.port || (u.protocol === 'https:' ? 443 : 80),
|
|
@@ -375,9 +371,7 @@ class BaseMetricsClient {
|
|
|
375
371
|
keepAlive: true
|
|
376
372
|
}) : undefined
|
|
377
373
|
}, res => {
|
|
378
|
-
res.resume();
|
|
379
374
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
380
|
-
console.warn(`${this.prefixLogs} metrics_pushed pid=${process.pid} bytes=${payloadBytes} status=${res.statusCode}`);
|
|
381
375
|
resolve();
|
|
382
376
|
} else {
|
|
383
377
|
let data = '';
|
|
@@ -389,8 +383,7 @@ class BaseMetricsClient {
|
|
|
389
383
|
});
|
|
390
384
|
req.on('error', reject);
|
|
391
385
|
this._registry.metrics().then(metrics => {
|
|
392
|
-
|
|
393
|
-
req.setHeader('Content-Length', payloadBytes);
|
|
386
|
+
req.setHeader('Content-Length', Buffer.byteLength(metrics, 'utf8'));
|
|
394
387
|
req.end(metrics, 'utf8');
|
|
395
388
|
}).catch(reject);
|
|
396
389
|
});
|
|
@@ -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","includeNodeDefaultMetrics","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","payloadBytes","contentType","resume","pid","then","Buffer","byteLength","setHeader","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.includeNodeDefaultMetrics] Register prom-client default process metrics (heap, etc.); defaults true unless MetricsClient forces false for web+Redis HTTP recording dynos.\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.includeNodeDefaultMetrics =\n config.includeNodeDefaultMetrics !== false\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 (this.includeNodeDefaultMetrics) {\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 /** Must be a prototype method (not a class field) so subclasses can `super.pushMetrics()`. */\n async pushMetrics() {\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 let payloadBytes = 0\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 res.resume()\n if (res.statusCode >= 200 && res.statusCode < 300) {\n console.warn(\n `${this.prefixLogs} metrics_pushed pid=${process.pid} bytes=${payloadBytes} status=${res.statusCode}`\n )\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 payloadBytes = Buffer.byteLength(metrics, 'utf8')\n req.setHeader('Content-Length', payloadBytes)\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,47 @@
|
|
|
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
|
+
* Always passes `blockNodeDefaultMetrics: true` to the base client (HTTP-only registry; no default Node heap/event-loop metrics).
|
|
5
|
+
* Redis key segment must match writers (`appName` + `processType` / {@link HttpMetricsRedisStore}).
|
|
6
|
+
*
|
|
7
|
+
* @extends BaseMetricsClient
|
|
8
|
+
*/
|
|
9
|
+
export class HttpMetricsRedisCollector extends BaseMetricsClient {
|
|
10
|
+
/**
|
|
11
|
+
* @param {Object} [config]
|
|
12
|
+
* @param {import('redis').RedisClient} config.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).
|
|
13
|
+
* @param {string} [config.appName] Application name (defaults per {@link BaseMetricsClient})
|
|
14
|
+
* @param {string} [config.dynoId] Dyno/instance ID
|
|
15
|
+
* @param {string} [config.processType] Label `process_type` on push (default from env / base)
|
|
16
|
+
* @param {boolean} [config.enabled] Enable collection and push
|
|
17
|
+
* @param {boolean} [config.logValues] Log metric JSON to console
|
|
18
|
+
* @param {string} [config.pushgatewayUrl] VM-agent import URL
|
|
19
|
+
* @param {string} [config.pushgatewaySecret] Basic auth secret (Base64)
|
|
20
|
+
* @param {number} [config.intervalSec] Push interval (seconds)
|
|
21
|
+
* @param {boolean} [config.removeOldMetrics] Clear old series on shutdown where supported
|
|
22
|
+
* @param {function} [config.startupValidation] Run before first push
|
|
23
|
+
* @param {boolean} [config.disablePushgateway] Skip POST to VM-agent
|
|
24
|
+
* @param {string} [config.redisProcessTypeForKeys] Segment in Redis keys for HTTP hashes (default `web`; env `METRICS_HTTP_REDIS_KEY_PROCESS_TYPE` overrides)
|
|
25
|
+
* @param {number} [config.ttlSec] Passed to {@link HttpMetricsRedisStore} (should match writers)
|
|
26
|
+
*/
|
|
27
|
+
constructor(config?: {
|
|
28
|
+
redisClient: import('redis').RedisClient;
|
|
29
|
+
appName?: string | undefined;
|
|
30
|
+
dynoId?: string | undefined;
|
|
31
|
+
processType?: string | undefined;
|
|
32
|
+
enabled?: boolean | undefined;
|
|
33
|
+
logValues?: boolean | undefined;
|
|
34
|
+
pushgatewayUrl?: string | undefined;
|
|
35
|
+
pushgatewaySecret?: string | undefined;
|
|
36
|
+
intervalSec?: number | undefined;
|
|
37
|
+
removeOldMetrics?: boolean | undefined;
|
|
38
|
+
startupValidation?: Function | undefined;
|
|
39
|
+
disablePushgateway?: boolean | undefined;
|
|
40
|
+
redisProcessTypeForKeys?: string | undefined;
|
|
41
|
+
ttlSec?: number | undefined;
|
|
42
|
+
} | undefined);
|
|
43
|
+
_store: HttpMetricsRedisStore;
|
|
44
|
+
}
|
|
45
|
+
import { BaseMetricsClient } from "./baseMetricsClient";
|
|
46
|
+
import { HttpMetricsRedisStore } from "./httpMetricsRedisStore";
|
|
47
|
+
//# sourceMappingURL=httpMetricsRedisCollector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpMetricsRedisCollector.d.ts","sourceRoot":"","sources":["../../src/metrics/httpMetricsRedisCollector.js"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH;IACE;;;;;;;;;;;;;;;;OAgBG;IACH;qBAfW,OAAO,OAAO,EAAE,WAAW;;;;;;;;;;;;;;mBAoErC;IAhCC,8BAKE;CA6DL"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const cluster = require('cluster');
|
|
4
|
+
const {
|
|
5
|
+
BaseMetricsClient
|
|
6
|
+
} = require('./baseMetricsClient');
|
|
7
|
+
const {
|
|
8
|
+
HttpMetricsRedisStore
|
|
9
|
+
} = require('./httpMetricsRedisStore');
|
|
10
|
+
function clusterWorkerTag() {
|
|
11
|
+
try {
|
|
12
|
+
if (cluster.isWorker && cluster.worker) {
|
|
13
|
+
return ` cluster_worker_id=${cluster.worker.id}`;
|
|
14
|
+
}
|
|
15
|
+
} catch (_) {
|
|
16
|
+
/* ignore */
|
|
17
|
+
}
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Drain worker: reads HTTP aggregates from Redis (written by {@link HttpMetricsRedisRecorder}),
|
|
23
|
+
* applies them to `app_requests_*` counters, then pushes the registry to the VM-agent (same as {@link BaseMetricsClient}).
|
|
24
|
+
* Always passes `blockNodeDefaultMetrics: true` to the base client (HTTP-only registry; no default Node heap/event-loop metrics).
|
|
25
|
+
* Redis key segment must match writers (`appName` + `processType` / {@link HttpMetricsRedisStore}).
|
|
26
|
+
*
|
|
27
|
+
* @extends BaseMetricsClient
|
|
28
|
+
*/
|
|
29
|
+
class HttpMetricsRedisCollector extends BaseMetricsClient {
|
|
30
|
+
/**
|
|
31
|
+
* @param {Object} [config]
|
|
32
|
+
* @param {import('redis').RedisClient} config.redisClient **Required.** Injected client (same pattern as {@link RedisMetricsClient}).
|
|
33
|
+
* @param {string} [config.appName] Application name (defaults per {@link BaseMetricsClient})
|
|
34
|
+
* @param {string} [config.dynoId] Dyno/instance ID
|
|
35
|
+
* @param {string} [config.processType] Label `process_type` on push (default from env / base)
|
|
36
|
+
* @param {boolean} [config.enabled] Enable collection and push
|
|
37
|
+
* @param {boolean} [config.logValues] Log metric JSON to console
|
|
38
|
+
* @param {string} [config.pushgatewayUrl] VM-agent import URL
|
|
39
|
+
* @param {string} [config.pushgatewaySecret] Basic auth secret (Base64)
|
|
40
|
+
* @param {number} [config.intervalSec] Push interval (seconds)
|
|
41
|
+
* @param {boolean} [config.removeOldMetrics] Clear old series on shutdown where supported
|
|
42
|
+
* @param {function} [config.startupValidation] Run before first push
|
|
43
|
+
* @param {boolean} [config.disablePushgateway] Skip POST to VM-agent
|
|
44
|
+
* @param {string} [config.redisProcessTypeForKeys] Segment in Redis keys for HTTP hashes (default `web`; env `METRICS_HTTP_REDIS_KEY_PROCESS_TYPE` overrides)
|
|
45
|
+
* @param {number} [config.ttlSec] Passed to {@link HttpMetricsRedisStore} (should match writers)
|
|
46
|
+
*/
|
|
47
|
+
constructor(config = {}) {
|
|
48
|
+
const {
|
|
49
|
+
redisClient
|
|
50
|
+
} = config;
|
|
51
|
+
if (redisClient == null) {
|
|
52
|
+
throw new Error('HttpMetricsRedisCollector: redisClient is required');
|
|
53
|
+
}
|
|
54
|
+
super({
|
|
55
|
+
...config,
|
|
56
|
+
blockNodeDefaultMetrics: true
|
|
57
|
+
});
|
|
58
|
+
const keyProcessType = config.redisProcessTypeForKeys || process.env.METRICS_HTTP_REDIS_KEY_PROCESS_TYPE || 'web';
|
|
59
|
+
this.defaultLabelsWithoutDynoId = {
|
|
60
|
+
app: this.appName,
|
|
61
|
+
process_type: keyProcessType
|
|
62
|
+
};
|
|
63
|
+
this._store = new HttpMetricsRedisStore({
|
|
64
|
+
redisClient,
|
|
65
|
+
appName: this.appName,
|
|
66
|
+
processType: keyProcessType,
|
|
67
|
+
ttlSec: config.ttlSec
|
|
68
|
+
});
|
|
69
|
+
this.createCounter({
|
|
70
|
+
name: 'app_requests_total',
|
|
71
|
+
help: 'Total number of HTTP requests',
|
|
72
|
+
labelNames: this.withDefaultLabelsWithoutDynoId(['method', 'route', 'appId', 'databaseId', 'status_code']),
|
|
73
|
+
useLabelsWithoutDynoId: true
|
|
74
|
+
});
|
|
75
|
+
this.createCounter({
|
|
76
|
+
name: 'app_requests_total_duration',
|
|
77
|
+
help: 'Total duration of HTTP requests in milliseconds',
|
|
78
|
+
labelNames: this.withDefaultLabelsWithoutDynoId(['method', 'route', 'appId', 'databaseId', 'status_code']),
|
|
79
|
+
useLabelsWithoutDynoId: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Drains Redis into counters, then runs gauge updates and VM-agent push ({@link BaseMetricsClient#_pushMetrics}).
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
pushMetrics = async () => {
|
|
88
|
+
const {
|
|
89
|
+
pid
|
|
90
|
+
} = process;
|
|
91
|
+
const clusterTag = clusterWorkerTag();
|
|
92
|
+
// --- TEMP_HTTP_METRICS_DIAG: remove when done debugging ---
|
|
93
|
+
console.warn(`[TEMP_HTTP_METRICS_DIAG] http_metrics_publish_start pid=${pid}${clusterTag} dyno_id=${this.dynoId} process_type=${this.processType} app=${this.appName}`);
|
|
94
|
+
// --- end TEMP_HTTP_METRICS_DIAG ---
|
|
95
|
+
if (this._store && this.countersFunctions?.app_requests_total && this.countersFunctions?.app_requests_total_duration) {
|
|
96
|
+
await this._store.flushToCounters((labels, value) => this.countersFunctions.app_requests_total(labels, value), (labels, value) => this.countersFunctions.app_requests_total_duration(labels, value));
|
|
97
|
+
}
|
|
98
|
+
const out = await this._pushMetrics();
|
|
99
|
+
// --- TEMP_HTTP_METRICS_DIAG: remove when done debugging ---
|
|
100
|
+
console.warn(`[TEMP_HTTP_METRICS_DIAG] http_metrics_publish_finished pid=${pid}${clusterTag} dyno_id=${this.dynoId} (registry POST to VM-agent / import completed for this tick)`);
|
|
101
|
+
// --- end TEMP_HTTP_METRICS_DIAG ---
|
|
102
|
+
return out;
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
module.exports = {
|
|
106
|
+
HttpMetricsRedisCollector
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=httpMetricsRedisCollector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpMetricsRedisCollector.js","names":["cluster","require","BaseMetricsClient","HttpMetricsRedisStore","clusterWorkerTag","isWorker","worker","id","_","HttpMetricsRedisCollector","constructor","config","redisClient","Error","blockNodeDefaultMetrics","keyProcessType","redisProcessTypeForKeys","process","env","METRICS_HTTP_REDIS_KEY_PROCESS_TYPE","defaultLabelsWithoutDynoId","app","appName","process_type","_store","processType","ttlSec","createCounter","name","help","labelNames","withDefaultLabelsWithoutDynoId","useLabelsWithoutDynoId","pushMetrics","pid","clusterTag","console","warn","dynoId","countersFunctions","app_requests_total","app_requests_total_duration","flushToCounters","labels","value","out","_pushMetrics","module","exports"],"sources":["../../src/metrics/httpMetricsRedisCollector.js"],"sourcesContent":["const cluster = require('cluster')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\nconst { HttpMetricsRedisStore } = require('./httpMetricsRedisStore')\n\nfunction clusterWorkerTag() {\n try {\n if (cluster.isWorker && cluster.worker) {\n return ` cluster_worker_id=${cluster.worker.id}`\n }\n } catch (_) {\n /* ignore */\n }\n return ''\n}\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 * Always passes `blockNodeDefaultMetrics: true` to the base client (HTTP-only registry; no default Node heap/event-loop metrics).\n * Redis key segment must match writers (`appName` + `processType` / {@link HttpMetricsRedisStore}).\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`; env `METRICS_HTTP_REDIS_KEY_PROCESS_TYPE` overrides)\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 =\n config.redisProcessTypeForKeys ||\n process.env.METRICS_HTTP_REDIS_KEY_PROCESS_TYPE ||\n '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 this.createCounter({\n name: 'app_requests_total',\n help: 'Total number of HTTP requests',\n labelNames: this.withDefaultLabelsWithoutDynoId([\n 'method',\n 'route',\n 'appId',\n 'databaseId',\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 'appId',\n 'databaseId',\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 const { pid } = process\n const clusterTag = clusterWorkerTag()\n // --- TEMP_HTTP_METRICS_DIAG: remove when done debugging ---\n console.warn(\n `[TEMP_HTTP_METRICS_DIAG] http_metrics_publish_start pid=${pid}${clusterTag} dyno_id=${this.dynoId} process_type=${this.processType} app=${this.appName}`\n )\n // --- end TEMP_HTTP_METRICS_DIAG ---\n if (\n this._store &&\n this.countersFunctions?.app_requests_total &&\n this.countersFunctions?.app_requests_total_duration\n ) {\n await this._store.flushToCounters(\n (labels, value) =>\n this.countersFunctions.app_requests_total(labels, value),\n (labels, value) =>\n this.countersFunctions.app_requests_total_duration(labels, value)\n )\n }\n const out = await this._pushMetrics()\n // --- TEMP_HTTP_METRICS_DIAG: remove when done debugging ---\n console.warn(\n `[TEMP_HTTP_METRICS_DIAG] http_metrics_publish_finished pid=${pid}${clusterTag} dyno_id=${this.dynoId} (registry POST to VM-agent / import completed for this tick)`\n )\n // --- end TEMP_HTTP_METRICS_DIAG ---\n return out\n }\n}\n\nmodule.exports = { HttpMetricsRedisCollector }\n"],"mappings":"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","ignoreList":[]}
|