@adalo/metrics 0.0.0-staging.15 → 0.0.0-staging.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/metrics/baseMetricsClient.d.ts.map +1 -1
- package/lib/metrics/baseMetricsClient.js +5 -1
- package/lib/metrics/baseMetricsClient.js.map +1 -1
- package/lib/metrics/metricsClient.d.ts +9 -0
- package/lib/metrics/metricsClient.d.ts.map +1 -1
- package/lib/metrics/metricsClient.js +54 -2
- package/lib/metrics/metricsClient.js.map +1 -1
- package/package.json +1 -1
- package/src/metrics/baseMetricsClient.js +7 -1
- package/src/metrics/metricsClient.js +60 -2
|
@@ -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,yBAAyB;OA8DpD;IA3DC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,mCAC4C;IAC5C,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,8FAA8F;IAC9F,6BAEC;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,
|
|
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,yBAAyB;OA8DpD;IA3DC,gBAA4E;IAC5E,eAAqE;IACrE,oBAG6B;IAC7B,mCAC4C;IAC5C,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,8FAA8F;IAC9F,6BAEC;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,uBA0DC;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"}
|
|
@@ -361,6 +361,7 @@ class BaseMetricsClient {
|
|
|
361
361
|
}
|
|
362
362
|
return new Promise((resolve, reject) => {
|
|
363
363
|
const u = new URL(pushUrl);
|
|
364
|
+
let payloadBytes = 0;
|
|
364
365
|
const req = (u.protocol === 'https:' ? https : http).request({
|
|
365
366
|
hostname: u.hostname,
|
|
366
367
|
port: u.port || (u.protocol === 'https:' ? 443 : 80),
|
|
@@ -374,7 +375,9 @@ class BaseMetricsClient {
|
|
|
374
375
|
keepAlive: true
|
|
375
376
|
}) : undefined
|
|
376
377
|
}, res => {
|
|
378
|
+
res.resume();
|
|
377
379
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
380
|
+
console.warn(`${this.prefixLogs} metrics_pushed pid=${process.pid} bytes=${payloadBytes} status=${res.statusCode}`);
|
|
378
381
|
resolve();
|
|
379
382
|
} else {
|
|
380
383
|
let data = '';
|
|
@@ -386,7 +389,8 @@ class BaseMetricsClient {
|
|
|
386
389
|
});
|
|
387
390
|
req.on('error', reject);
|
|
388
391
|
this._registry.metrics().then(metrics => {
|
|
389
|
-
|
|
392
|
+
payloadBytes = Buffer.byteLength(metrics, 'utf8');
|
|
393
|
+
req.setHeader('Content-Length', payloadBytes);
|
|
390
394
|
req.end(metrics, 'utf8');
|
|
391
395
|
}).catch(reject);
|
|
392
396
|
});
|
|
@@ -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","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.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 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","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":[]}
|
|
@@ -51,7 +51,16 @@ export class MetricsClient extends BaseMetricsClient {
|
|
|
51
51
|
_skippedPushWorkerLogged: boolean;
|
|
52
52
|
_lastUsageMicros: number;
|
|
53
53
|
_lastCheckTime: number;
|
|
54
|
+
_metricsBootstrapLogged: boolean;
|
|
55
|
+
_httpLogWindowStart: number;
|
|
56
|
+
_httpLogBatchCount: number;
|
|
57
|
+
_httpLogLastSample: string;
|
|
54
58
|
_logMetricsBootstrap: () => void;
|
|
59
|
+
/**
|
|
60
|
+
* Throttled HTTP recording log (not gated by METRICS_LOG_VALUES). Same pod can run many workers
|
|
61
|
+
* (same dyno_id); pid + cluster_worker_id distinguish processes.
|
|
62
|
+
*/
|
|
63
|
+
_maybeLogHttpRecord(method: any, route: any, status_code: any): void;
|
|
55
64
|
get isWebRedisHttpRecordingOnly(): boolean;
|
|
56
65
|
_initDefaultMetrics: () => void;
|
|
57
66
|
getCpuUsagePercent: () => number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsClient.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"metricsClient.d.ts","sourceRoot":"","sources":["../../src/metrics/metricsClient.js"],"names":[],"mappings":"AA4CA;;;;;;GAMG;AACH;IACE;;;;;;;;;;;;;;;;;OAiBG;IACH;;;;;;;;;;;;;;;;mBAiGC;IApDC,4BAA4C;IAC5C,qCAA8D;IAM9D,8CAOU;IAEV,oCAEC;IAED,6BAA2D;IAG3D,iCAAwE;IACxE,+BAA8C;IAgB9C,kCAAqC;IAErC,yBAAyB;IACzB,uBAAgC;IAEhC,iCAAoC;IACpC,4BAA4B;IAC5B,2BAA2B;IAC3B,2BAA4B;IAM9B,iCAmBC;IAED;;;OAGG;IACH,qEAmBC;IAED,2CAEC;IAED,gCAiFC;IAED,iCAyBC;IAED,2BAeC;IAED,kCASC;IAED,kCAcC;IAED,2BAKC;IAED;;;;;;;aAyCC;IAED;;;;;OAKG;IACH,sEAHiB,IAAI,GAAG,QAAQ,IAAI,CAAC,kBACxB,IAAI,CAoBhB;IA4BD,oEA+BC;CACF"}
|
|
@@ -32,6 +32,20 @@ function isMetricsExporterProcessType(processType) {
|
|
|
32
32
|
return processType === 'metrics';
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/** Extra tag when `cluster` workers are used (same pod hostname, different PIDs). */
|
|
36
|
+
function clusterWorkerTag() {
|
|
37
|
+
try {
|
|
38
|
+
const cluster = require('cluster');
|
|
39
|
+
if (cluster.isWorker && cluster.worker) {
|
|
40
|
+
return ` cluster_worker_id=${cluster.worker.id}`;
|
|
41
|
+
}
|
|
42
|
+
} catch (_) {
|
|
43
|
+
/* ignore */
|
|
44
|
+
}
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
const HTTP_METRICS_LOG_INTERVAL_MS = 5000;
|
|
48
|
+
|
|
35
49
|
/**
|
|
36
50
|
* MetricsClient handles Prometheus metrics collection and push.
|
|
37
51
|
*
|
|
@@ -114,6 +128,10 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
114
128
|
this._skippedPushWorkerLogged = false;
|
|
115
129
|
this._lastUsageMicros = 0;
|
|
116
130
|
this._lastCheckTime = Date.now();
|
|
131
|
+
this._metricsBootstrapLogged = false;
|
|
132
|
+
this._httpLogWindowStart = 0;
|
|
133
|
+
this._httpLogBatchCount = 0;
|
|
134
|
+
this._httpLogLastSample = '';
|
|
117
135
|
this._initDefaultMetrics();
|
|
118
136
|
this._logMetricsBootstrap();
|
|
119
137
|
}
|
|
@@ -121,10 +139,39 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
121
139
|
if (!this.enabled) {
|
|
122
140
|
return;
|
|
123
141
|
}
|
|
142
|
+
if (this._metricsBootstrapLogged) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this._metricsBootstrapLogged = true;
|
|
124
146
|
const wc = process.env.WEB_CONCURRENCY || '';
|
|
125
147
|
const httpMode = !this.httpMetricsEnabled ? 'off' : this._httpRedisStore ? 'redis' : 'local_counters';
|
|
126
|
-
|
|
148
|
+
const pidTag = `pid=${process.pid}`;
|
|
149
|
+
const clusterTag = clusterWorkerTag();
|
|
150
|
+
console.warn(`${this.prefixLogs} metrics bootstrap ${pidTag}${clusterTag} WEB_CONCURRENCY=${wc || '(unset)'} host_cpus=${this._bootstrapHostCpuCount} dyno_id=${this.dynoId} process_type=${this.processType} scheduling_id=${process.env.DYNO || 'n/a'} http_metrics=${httpMode} redis_http=${this.httpMetricsRedisAggregation} web_redis_only=${this._webRedisHttpRecordingOnly}`);
|
|
127
151
|
};
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Throttled HTTP recording log (not gated by METRICS_LOG_VALUES). Same pod can run many workers
|
|
155
|
+
* (same dyno_id); pid + cluster_worker_id distinguish processes.
|
|
156
|
+
*/
|
|
157
|
+
_maybeLogHttpRecord(method, route, status_code) {
|
|
158
|
+
if (!this.enabled || !this.httpMetricsEnabled) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
this._httpLogBatchCount += 1;
|
|
162
|
+
this._httpLogLastSample = `${method} ${route} ${status_code}`;
|
|
163
|
+
const now = Date.now();
|
|
164
|
+
if (!this._httpLogWindowStart) {
|
|
165
|
+
this._httpLogWindowStart = now;
|
|
166
|
+
}
|
|
167
|
+
if (now - this._httpLogWindowStart < HTTP_METRICS_LOG_INTERVAL_MS) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const clusterTag = clusterWorkerTag();
|
|
171
|
+
console.warn(`${this.prefixLogs} http_metrics_record pid=${process.pid}${clusterTag} process_type=${this.processType} dyno_id=${this.dynoId} count=${this._httpLogBatchCount} sample=${this._httpLogLastSample}`);
|
|
172
|
+
this._httpLogWindowStart = now;
|
|
173
|
+
this._httpLogBatchCount = 0;
|
|
174
|
+
}
|
|
128
175
|
get isWebRedisHttpRecordingOnly() {
|
|
129
176
|
return Boolean(this._webRedisHttpRecordingOnly);
|
|
130
177
|
}
|
|
@@ -260,6 +307,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
260
307
|
if (!this.httpMetricsEnabled) return;
|
|
261
308
|
if (this._httpRedisStore) {
|
|
262
309
|
this._httpRedisStore.record(method, route, status_code, appId, databaseId, duration);
|
|
310
|
+
this._maybeLogHttpRecord(method, route, status_code);
|
|
263
311
|
return;
|
|
264
312
|
}
|
|
265
313
|
this.countersFunctions?.app_requests_total({
|
|
@@ -276,6 +324,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
276
324
|
appId,
|
|
277
325
|
databaseId
|
|
278
326
|
}, duration);
|
|
327
|
+
this._maybeLogHttpRecord(method, route, status_code);
|
|
279
328
|
}
|
|
280
329
|
|
|
281
330
|
/**
|
|
@@ -302,7 +351,10 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
302
351
|
return;
|
|
303
352
|
}
|
|
304
353
|
if (this._httpRedisStore && shouldRunMetricsPush(this) && this.countersFunctions?.app_requests_total && this.countersFunctions?.app_requests_total_duration) {
|
|
305
|
-
await this._httpRedisStore.flushToCounters((labels, value) => this.countersFunctions.app_requests_total(labels, value), (labels, value) => this.countersFunctions.app_requests_total_duration(labels, value));
|
|
354
|
+
const flushed = await this._httpRedisStore.flushToCounters((labels, value) => this.countersFunctions.app_requests_total(labels, value), (labels, value) => this.countersFunctions.app_requests_total_duration(labels, value));
|
|
355
|
+
if (flushed) {
|
|
356
|
+
console.warn(`${this.prefixLogs} http_metrics_redis_flush pid=${process.pid}${clusterWorkerTag()} process_type=${this.processType} dyno_id=${this.dynoId} drained=true`);
|
|
357
|
+
}
|
|
306
358
|
}
|
|
307
359
|
// eslint-disable-next-line consistent-return
|
|
308
360
|
return super.pushMetrics();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metricsClient.js","names":["fs","require","os","BaseMetricsClient","shouldRunMetricsPush","HttpMetricsRedisStore","isRedisPeerInstalled","isWebServingDynoContext","processType","dyno","process","env","DYNO","test","isMetricsExporterProcessType","MetricsClient","constructor","config","processTypeBeforeSuper","BUILD_DYNO_PROCESS_TYPE","redisUrl","httpMetricsRedisUrl","METRICS_HTTP_REDIS_URL","REDIS_URL","httpMetricsEnabled","undefined","METRICS_HTTP_ENABLED","httpMetricsRedisAggregation","Boolean","console","warn","isWebCtx","webRedisRecordingOnly","NODE_ENV","includeNodeDefaultMetrics","redisKeyProcessType","_httpRedisStore","appName","_webRedisHttpRecordingOnly","exportRuntimeGauges","wcParsed","parseInt","WEB_CONCURRENCY","_bootstrapWebConcurrency","Number","isFinite","_bootstrapHostCpuCount","cpus","length","defaultLabelsWithoutDynoId","app","process_type","_skippedPushWorkerLogged","_lastUsageMicros","_lastCheckTime","Date","now","_initDefaultMetrics","_logMetricsBootstrap","enabled","wc","httpMode","prefixLogs","dynoId","isWebRedisHttpRecordingOnly","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","uptime","registerHttpCounters","createCounter","labelNames","withDefaultLabelsWithoutDynoId","useLabelsWithoutDynoId","stat","readFileSync","match","currentUsage","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","trackHttpRequest","method","route","status_code","appId","databaseId","duration","record","countersFunctions","app_requests_total","app_requests_total_duration","startPush","interval","customPushMetrics","METRICS_SUPPRESS_SKIP_PUSH_LOG","_startPush","pushMetrics","flushToCounters","labels","value","trackHttpRequestMiddleware","req","res","next","on","params","body","query","datasourceId","statusCode","module","exports"],"sources":["../../src/metrics/metricsClient.js"],"sourcesContent":["const fs = require('fs')\nconst os = require('os')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\nconst { shouldRunMetricsPush } = require('./shouldRunMetricsPush')\nconst {\n HttpMetricsRedisStore,\n isRedisPeerInstalled,\n} = require('./httpMetricsRedisStore')\n\n/**\n * Heroku-style: DYNO=web.1 → web serving; DYNO=metrics.1 → VM-agent exporter (Procfile `metrics:`).\n * Without DYNO (local Docker), falls back to BUILD_DYNO_PROCESS_TYPE === 'web'.\n */\nfunction isWebServingDynoContext(processType) {\n const dyno = process.env.DYNO || ''\n if (dyno) {\n return /^web\\./.test(dyno)\n }\n return processType === 'web'\n}\n\nfunction isMetricsExporterProcessType(processType) {\n const dyno = process.env.DYNO || ''\n if (dyno) {\n return /^metrics\\./.test(dyno)\n }\n return processType === 'metrics'\n}\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n *\n * **Redis HTTP:** When `METRICS_HTTP_ENABLED` and a Redis URL exist, HTTP counts use Redis\n * (key segment from BUILD_APP_NAME + process type). Production **web.*** dynos only write Redis;\n * run Procfile **`metrics`** + **metrics-exporter.js** to drain and POST. Tests: `httpMetricsRedisAggregation: false`.\n */\nclass MetricsClient extends 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, metrics, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.httpMetricsEnabled] Enable HTTP request metrics (app_requests_total, app_requests_total_duration); defaults from METRICS_HTTP_ENABLED\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] Push URL (VM-agent import endpoint)\n * @param {string} [config.pushgatewaySecret] Basic auth secret (Base64 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 VM-agent (use HTTP scraping instead)\n * @param {boolean} [config.includeNodeDefaultMetrics] Register prom-client default process metrics\n * @param {string} [config.httpMetricsRedisUrl] Overrides METRICS_HTTP_REDIS_URL / REDIS_URL for the HTTP Redis store\n * @param {boolean} [config.httpMetricsRedisAggregation] When unset, on if Redis + HTTP metrics; set false to force in-process HTTP counters only\n */\n constructor(config = {}) {\n const processTypeBeforeSuper =\n config.processType || process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined_build_dyno_type'\n\n const redisUrl =\n config.httpMetricsRedisUrl ||\n process.env.METRICS_HTTP_REDIS_URL ||\n process.env.REDIS_URL ||\n ''\n\n let httpMetricsEnabled\n if (config.httpMetricsEnabled !== undefined) {\n httpMetricsEnabled = config.httpMetricsEnabled\n } else if (process.env.METRICS_HTTP_ENABLED === 'true') {\n httpMetricsEnabled = true\n } else if (isMetricsExporterProcessType(processTypeBeforeSuper) && redisUrl) {\n // metrics: dyno must drain Redis HTTP keys; many stacks omit METRICS_HTTP_ENABLED here\n httpMetricsEnabled = true\n } else {\n httpMetricsEnabled = false\n }\n\n let httpMetricsRedisAggregation =\n Boolean(redisUrl) &&\n Boolean(httpMetricsEnabled) &&\n config.httpMetricsRedisAggregation !== false\n\n if (httpMetricsRedisAggregation && !isRedisPeerInstalled()) {\n console.warn(\n '[MetricsClient] METRICS_HTTP_ENABLED with REDIS_URL needs the peer package `redis` in your application (npm install redis@3). Falling back to in-process HTTP counters. @adalo/metrics does not bundle redis.'\n )\n httpMetricsRedisAggregation = false\n }\n\n const isWebCtx = isWebServingDynoContext(processTypeBeforeSuper)\n const webRedisRecordingOnly =\n Boolean(httpMetricsRedisAggregation) &&\n isWebCtx &&\n process.env.NODE_ENV === 'production'\n\n super({\n ...config,\n ...(webRedisRecordingOnly ? { includeNodeDefaultMetrics: false } : {}),\n })\n\n this.httpMetricsEnabled = httpMetricsEnabled\n this.httpMetricsRedisAggregation = httpMetricsRedisAggregation\n\n const redisKeyProcessType = isMetricsExporterProcessType(this.processType)\n ? 'web'\n : this.processType\n\n this._httpRedisStore =\n this.httpMetricsEnabled && this.httpMetricsRedisAggregation\n ? new HttpMetricsRedisStore({\n redisUrl,\n appName: this.appName,\n processType: redisKeyProcessType,\n })\n : null\n\n this._webRedisHttpRecordingOnly = Boolean(\n webRedisRecordingOnly && this._httpRedisStore\n )\n\n this.exportRuntimeGauges = !this._webRedisHttpRecordingOnly\n\n const wcParsed = parseInt(process.env.WEB_CONCURRENCY || '', 10)\n this._bootstrapWebConcurrency = Number.isFinite(wcParsed) ? wcParsed : 0\n this._bootstrapHostCpuCount = os.cpus().length\n\n if (this.httpMetricsRedisAggregation && redisUrl) {\n if (isMetricsExporterProcessType(this.processType)) {\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: 'web',\n }\n } else if (!this._webRedisHttpRecordingOnly) {\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: this.processType,\n }\n }\n }\n\n this._skippedPushWorkerLogged = false\n\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._initDefaultMetrics()\n this._logMetricsBootstrap()\n }\n\n _logMetricsBootstrap = () => {\n if (!this.enabled) {\n return\n }\n const wc = process.env.WEB_CONCURRENCY || ''\n const httpMode = !this.httpMetricsEnabled\n ? 'off'\n : this._httpRedisStore\n ? 'redis'\n : 'local_counters'\n console.warn(\n `${this.prefixLogs} metrics bootstrap WEB_CONCURRENCY=${wc || '(unset)'} host_cpus=${this._bootstrapHostCpuCount} dyno_id=${this.dynoId} process_type=${this.processType} scheduling_id=${process.env.DYNO || 'n/a'} http_metrics=${httpMode} redis_http=${this.httpMetricsRedisAggregation} web_redis_only=${this._webRedisHttpRecordingOnly}`\n )\n }\n\n get isWebRedisHttpRecordingOnly() {\n return Boolean(this._webRedisHttpRecordingOnly)\n }\n\n _initDefaultMetrics = () => {\n if (this.exportRuntimeGauges) {\n this.createGauge({\n name: 'app_process_cpu_usage_percent',\n help: 'Current CPU usage of the Node.js process in percent',\n updateFn: this.getCpuUsagePercent,\n })\n\n this.createGauge({\n name: 'app_available_cpu_count',\n help: 'How many CPU cores are available to this process',\n updateFn: this.getAvailableCPUs,\n })\n\n this.createGauge({\n name: 'app_container_memory_usage_bytes',\n help: 'Current container RAM usage from cgroup',\n updateFn: this.getContainerMemoryUsage,\n })\n\n this.createGauge({\n name: 'app_event_loop_lag_ms',\n help: 'Estimated event loop lag in milliseconds',\n updateFn: this.measureLag,\n })\n\n this.createGauge({\n name: 'app_container_memory_limit_bytes',\n help: 'Max RAM available to container from cgroup (memory.max)',\n updateFn: this.getContainerMemoryLimit,\n })\n\n this.createGauge({\n name: 'app_uptime_seconds',\n help: 'How long the process has been running',\n updateFn: process.uptime,\n })\n\n this.createGauge({\n name: 'app_bootstrap_web_concurrency',\n help: 'WEB_CONCURRENCY at process start (diagnostic; 0 if unset/invalid)',\n updateFn: () => this._bootstrapWebConcurrency,\n })\n\n this.createGauge({\n name: 'app_bootstrap_host_cpu_count',\n help: 'os.cpus().length at process start (diagnostic)',\n updateFn: () => this._bootstrapHostCpuCount,\n })\n }\n\n const registerHttpCounters =\n this.httpMetricsEnabled && !this._webRedisHttpRecordingOnly\n\n if (registerHttpCounters) {\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 getCpuUsagePercent = () => {\n try {\n const stat = fs.readFileSync('/sys/fs/cgroup/cpu.stat', 'utf-8')\n const match = stat.match(/usage_usec (\\d+)/)\n if (!match) return 0\n\n const now = Date.now()\n const currentUsage = parseInt(match[1], 10)\n\n if (this._lastUsageMicros === 0) {\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n return 0\n }\n\n const deltaUsage = currentUsage - this._lastUsageMicros\n const deltaTime = now - this._lastCheckTime\n\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n\n return (deltaUsage / (deltaTime * 1000)) * 100\n } catch {\n return 0\n }\n }\n\n getAvailableCPUs() {\n try {\n const cpuMaxPath = '/sys/fs/cgroup/cpu.max'\n if (fs.existsSync(cpuMaxPath)) {\n const [quotaStr, periodStr] = fs\n .readFileSync(cpuMaxPath, 'utf8')\n .trim()\n .split(' ')\n if (quotaStr === 'max') return os.cpus().length\n return parseInt(quotaStr, 10) / parseInt(periodStr, 10)\n }\n return os.cpus().length\n } catch {\n return 1\n }\n }\n\n getContainerMemoryUsage() {\n try {\n return parseInt(\n fs.readFileSync('/sys/fs/cgroup/memory.current', 'utf-8').trim(),\n 10\n )\n } catch {\n return process.memoryUsage().rss\n }\n }\n\n getContainerMemoryLimit() {\n try {\n const path = '/sys/fs/cgroup/memory.max'\n if (fs.existsSync(path)) {\n const val = fs.readFileSync(path, 'utf-8').trim()\n if (val !== 'max') {\n const parsed = parseInt(val, 10)\n if (parsed && parsed < os.totalmem()) return parsed\n }\n }\n return os.totalmem()\n } catch {\n return os.totalmem()\n }\n }\n\n measureLag() {\n return new Promise(resolve => {\n const start = Date.now()\n setImmediate(() => resolve(Date.now() - start))\n })\n }\n\n trackHttpRequest({\n method,\n route,\n status_code,\n appId = '',\n databaseId = '',\n duration,\n }) {\n if (!this.httpMetricsEnabled) return\n\n if (this._httpRedisStore) {\n this._httpRedisStore.record(\n method,\n route,\n status_code,\n appId,\n databaseId,\n duration\n )\n return\n }\n\n this.countersFunctions?.app_requests_total({\n method,\n route,\n status_code,\n appId,\n databaseId,\n })\n this.countersFunctions?.app_requests_total_duration(\n {\n method,\n route,\n status_code,\n appId,\n databaseId,\n },\n duration\n )\n }\n\n /**\n * Start periodic push to VM-agent (`METRICS_PUSHGATEWAY_URL`). Interval defaults to `intervalSec` from config/env.\n * @param {number} [interval] Seconds between pushes; defaults to `this.intervalSec`\n * @param {() => void | Promise<void>} [customPushMetrics] Optional; replaces default push when provided\n * @returns {void}\n */\n startPush = (interval, customPushMetrics) => {\n if (this._webRedisHttpRecordingOnly) {\n return\n }\n if (!shouldRunMetricsPush(this)) {\n if (\n this.enabled &&\n !this._skippedPushWorkerLogged &&\n process.env.METRICS_SUPPRESS_SKIP_PUSH_LOG !== 'true'\n ) {\n console.warn(\n `${this.prefixLogs} Skipping VM-agent push on this worker. METRICS_PUSH_ALL_WORKERS=true restores per-worker push.`\n )\n this._skippedPushWorkerLogged = true\n }\n return\n }\n this._startPush(interval, customPushMetrics)\n }\n\n async pushMetrics() {\n if (this._webRedisHttpRecordingOnly) {\n return\n }\n if (\n this._httpRedisStore &&\n shouldRunMetricsPush(this) &&\n this.countersFunctions?.app_requests_total &&\n this.countersFunctions?.app_requests_total_duration\n ) {\n await this._httpRedisStore.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 // eslint-disable-next-line consistent-return\n return super.pushMetrics()\n }\n\n trackHttpRequestMiddleware = (req, res, next) => {\n if (!this.enabled || !this.httpMetricsEnabled || req.method === 'OPTIONS') {\n next()\n return\n }\n\n const start = Date.now()\n res.on('finish', () => {\n const route = req.route?.path || req.path || 'unknown'\n const appId =\n req.params?.appId || req.body?.appId || req.query?.appId || ''\n const databaseId =\n req.params?.databaseId ||\n req.body?.databaseId ||\n req.query?.databaseId ||\n req.params?.datasourceId ||\n req.body?.datasourceId ||\n req.query?.datasourceId ||\n ''\n\n this.trackHttpRequest({\n method: req.method,\n route,\n status_code: res.statusCode,\n appId,\n databaseId,\n duration: Date.now() - start,\n })\n })\n\n next()\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"metricsClient.js","names":["fs","require","os","BaseMetricsClient","shouldRunMetricsPush","HttpMetricsRedisStore","isRedisPeerInstalled","isWebServingDynoContext","processType","dyno","process","env","DYNO","test","isMetricsExporterProcessType","clusterWorkerTag","cluster","isWorker","worker","id","_","HTTP_METRICS_LOG_INTERVAL_MS","MetricsClient","constructor","config","processTypeBeforeSuper","BUILD_DYNO_PROCESS_TYPE","redisUrl","httpMetricsRedisUrl","METRICS_HTTP_REDIS_URL","REDIS_URL","httpMetricsEnabled","undefined","METRICS_HTTP_ENABLED","httpMetricsRedisAggregation","Boolean","console","warn","isWebCtx","webRedisRecordingOnly","NODE_ENV","includeNodeDefaultMetrics","redisKeyProcessType","_httpRedisStore","appName","_webRedisHttpRecordingOnly","exportRuntimeGauges","wcParsed","parseInt","WEB_CONCURRENCY","_bootstrapWebConcurrency","Number","isFinite","_bootstrapHostCpuCount","cpus","length","defaultLabelsWithoutDynoId","app","process_type","_skippedPushWorkerLogged","_lastUsageMicros","_lastCheckTime","Date","now","_metricsBootstrapLogged","_httpLogWindowStart","_httpLogBatchCount","_httpLogLastSample","_initDefaultMetrics","_logMetricsBootstrap","enabled","wc","httpMode","pidTag","pid","clusterTag","prefixLogs","dynoId","_maybeLogHttpRecord","method","route","status_code","isWebRedisHttpRecordingOnly","createGauge","name","help","updateFn","getCpuUsagePercent","getAvailableCPUs","getContainerMemoryUsage","measureLag","getContainerMemoryLimit","uptime","registerHttpCounters","createCounter","labelNames","withDefaultLabelsWithoutDynoId","useLabelsWithoutDynoId","stat","readFileSync","match","currentUsage","deltaUsage","deltaTime","cpuMaxPath","existsSync","quotaStr","periodStr","trim","split","memoryUsage","rss","path","val","parsed","totalmem","Promise","resolve","start","setImmediate","trackHttpRequest","appId","databaseId","duration","record","countersFunctions","app_requests_total","app_requests_total_duration","startPush","interval","customPushMetrics","METRICS_SUPPRESS_SKIP_PUSH_LOG","_startPush","pushMetrics","flushed","flushToCounters","labels","value","trackHttpRequestMiddleware","req","res","next","on","params","body","query","datasourceId","statusCode","module","exports"],"sources":["../../src/metrics/metricsClient.js"],"sourcesContent":["const fs = require('fs')\nconst os = require('os')\nconst { BaseMetricsClient } = require('./baseMetricsClient')\nconst { shouldRunMetricsPush } = require('./shouldRunMetricsPush')\nconst {\n HttpMetricsRedisStore,\n isRedisPeerInstalled,\n} = require('./httpMetricsRedisStore')\n\n/**\n * Heroku-style: DYNO=web.1 → web serving; DYNO=metrics.1 → VM-agent exporter (Procfile `metrics:`).\n * Without DYNO (local Docker), falls back to BUILD_DYNO_PROCESS_TYPE === 'web'.\n */\nfunction isWebServingDynoContext(processType) {\n const dyno = process.env.DYNO || ''\n if (dyno) {\n return /^web\\./.test(dyno)\n }\n return processType === 'web'\n}\n\nfunction isMetricsExporterProcessType(processType) {\n const dyno = process.env.DYNO || ''\n if (dyno) {\n return /^metrics\\./.test(dyno)\n }\n return processType === 'metrics'\n}\n\n/** Extra tag when `cluster` workers are used (same pod hostname, different PIDs). */\nfunction clusterWorkerTag() {\n try {\n const cluster = require('cluster')\n if (cluster.isWorker && cluster.worker) {\n return ` cluster_worker_id=${cluster.worker.id}`\n }\n } catch (_) {\n /* ignore */\n }\n return ''\n}\n\nconst HTTP_METRICS_LOG_INTERVAL_MS = 5000\n\n/**\n * MetricsClient handles Prometheus metrics collection and push.\n *\n * **Redis HTTP:** When `METRICS_HTTP_ENABLED` and a Redis URL exist, HTTP counts use Redis\n * (key segment from BUILD_APP_NAME + process type). Production **web.*** dynos only write Redis;\n * run Procfile **`metrics`** + **metrics-exporter.js** to drain and POST. Tests: `httpMetricsRedisAggregation: false`.\n */\nclass MetricsClient extends 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, metrics, etc.)\n * @param {boolean} [config.enabled] Enable metrics collection\n * @param {boolean} [config.httpMetricsEnabled] Enable HTTP request metrics (app_requests_total, app_requests_total_duration); defaults from METRICS_HTTP_ENABLED\n * @param {boolean} [config.logValues] Log metrics values to console\n * @param {string} [config.pushgatewayUrl] Push URL (VM-agent import endpoint)\n * @param {string} [config.pushgatewaySecret] Basic auth secret (Base64 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 VM-agent (use HTTP scraping instead)\n * @param {boolean} [config.includeNodeDefaultMetrics] Register prom-client default process metrics\n * @param {string} [config.httpMetricsRedisUrl] Overrides METRICS_HTTP_REDIS_URL / REDIS_URL for the HTTP Redis store\n * @param {boolean} [config.httpMetricsRedisAggregation] When unset, on if Redis + HTTP metrics; set false to force in-process HTTP counters only\n */\n constructor(config = {}) {\n const processTypeBeforeSuper =\n config.processType || process.env.BUILD_DYNO_PROCESS_TYPE || 'undefined_build_dyno_type'\n\n const redisUrl =\n config.httpMetricsRedisUrl ||\n process.env.METRICS_HTTP_REDIS_URL ||\n process.env.REDIS_URL ||\n ''\n\n let httpMetricsEnabled\n if (config.httpMetricsEnabled !== undefined) {\n httpMetricsEnabled = config.httpMetricsEnabled\n } else if (process.env.METRICS_HTTP_ENABLED === 'true') {\n httpMetricsEnabled = true\n } else if (isMetricsExporterProcessType(processTypeBeforeSuper) && redisUrl) {\n // metrics: dyno must drain Redis HTTP keys; many stacks omit METRICS_HTTP_ENABLED here\n httpMetricsEnabled = true\n } else {\n httpMetricsEnabled = false\n }\n\n let httpMetricsRedisAggregation =\n Boolean(redisUrl) &&\n Boolean(httpMetricsEnabled) &&\n config.httpMetricsRedisAggregation !== false\n\n if (httpMetricsRedisAggregation && !isRedisPeerInstalled()) {\n console.warn(\n '[MetricsClient] METRICS_HTTP_ENABLED with REDIS_URL needs the peer package `redis` in your application (npm install redis@3). Falling back to in-process HTTP counters. @adalo/metrics does not bundle redis.'\n )\n httpMetricsRedisAggregation = false\n }\n\n const isWebCtx = isWebServingDynoContext(processTypeBeforeSuper)\n const webRedisRecordingOnly =\n Boolean(httpMetricsRedisAggregation) &&\n isWebCtx &&\n process.env.NODE_ENV === 'production'\n\n super({\n ...config,\n ...(webRedisRecordingOnly ? { includeNodeDefaultMetrics: false } : {}),\n })\n\n this.httpMetricsEnabled = httpMetricsEnabled\n this.httpMetricsRedisAggregation = httpMetricsRedisAggregation\n\n const redisKeyProcessType = isMetricsExporterProcessType(this.processType)\n ? 'web'\n : this.processType\n\n this._httpRedisStore =\n this.httpMetricsEnabled && this.httpMetricsRedisAggregation\n ? new HttpMetricsRedisStore({\n redisUrl,\n appName: this.appName,\n processType: redisKeyProcessType,\n })\n : null\n\n this._webRedisHttpRecordingOnly = Boolean(\n webRedisRecordingOnly && this._httpRedisStore\n )\n\n this.exportRuntimeGauges = !this._webRedisHttpRecordingOnly\n\n const wcParsed = parseInt(process.env.WEB_CONCURRENCY || '', 10)\n this._bootstrapWebConcurrency = Number.isFinite(wcParsed) ? wcParsed : 0\n this._bootstrapHostCpuCount = os.cpus().length\n\n if (this.httpMetricsRedisAggregation && redisUrl) {\n if (isMetricsExporterProcessType(this.processType)) {\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: 'web',\n }\n } else if (!this._webRedisHttpRecordingOnly) {\n this.defaultLabelsWithoutDynoId = {\n app: this.appName,\n process_type: this.processType,\n }\n }\n }\n\n this._skippedPushWorkerLogged = false\n\n this._lastUsageMicros = 0\n this._lastCheckTime = Date.now()\n\n this._metricsBootstrapLogged = false\n this._httpLogWindowStart = 0\n this._httpLogBatchCount = 0\n this._httpLogLastSample = ''\n\n this._initDefaultMetrics()\n this._logMetricsBootstrap()\n }\n\n _logMetricsBootstrap = () => {\n if (!this.enabled) {\n return\n }\n if (this._metricsBootstrapLogged) {\n return\n }\n this._metricsBootstrapLogged = true\n const wc = process.env.WEB_CONCURRENCY || ''\n const httpMode = !this.httpMetricsEnabled\n ? 'off'\n : this._httpRedisStore\n ? 'redis'\n : 'local_counters'\n const pidTag = `pid=${process.pid}`\n const clusterTag = clusterWorkerTag()\n console.warn(\n `${this.prefixLogs} metrics bootstrap ${pidTag}${clusterTag} WEB_CONCURRENCY=${wc || '(unset)'} host_cpus=${this._bootstrapHostCpuCount} dyno_id=${this.dynoId} process_type=${this.processType} scheduling_id=${process.env.DYNO || 'n/a'} http_metrics=${httpMode} redis_http=${this.httpMetricsRedisAggregation} web_redis_only=${this._webRedisHttpRecordingOnly}`\n )\n }\n\n /**\n * Throttled HTTP recording log (not gated by METRICS_LOG_VALUES). Same pod can run many workers\n * (same dyno_id); pid + cluster_worker_id distinguish processes.\n */\n _maybeLogHttpRecord(method, route, status_code) {\n if (!this.enabled || !this.httpMetricsEnabled) {\n return\n }\n this._httpLogBatchCount += 1\n this._httpLogLastSample = `${method} ${route} ${status_code}`\n const now = Date.now()\n if (!this._httpLogWindowStart) {\n this._httpLogWindowStart = now\n }\n if (now - this._httpLogWindowStart < HTTP_METRICS_LOG_INTERVAL_MS) {\n return\n }\n const clusterTag = clusterWorkerTag()\n console.warn(\n `${this.prefixLogs} http_metrics_record pid=${process.pid}${clusterTag} process_type=${this.processType} dyno_id=${this.dynoId} count=${this._httpLogBatchCount} sample=${this._httpLogLastSample}`\n )\n this._httpLogWindowStart = now\n this._httpLogBatchCount = 0\n }\n\n get isWebRedisHttpRecordingOnly() {\n return Boolean(this._webRedisHttpRecordingOnly)\n }\n\n _initDefaultMetrics = () => {\n if (this.exportRuntimeGauges) {\n this.createGauge({\n name: 'app_process_cpu_usage_percent',\n help: 'Current CPU usage of the Node.js process in percent',\n updateFn: this.getCpuUsagePercent,\n })\n\n this.createGauge({\n name: 'app_available_cpu_count',\n help: 'How many CPU cores are available to this process',\n updateFn: this.getAvailableCPUs,\n })\n\n this.createGauge({\n name: 'app_container_memory_usage_bytes',\n help: 'Current container RAM usage from cgroup',\n updateFn: this.getContainerMemoryUsage,\n })\n\n this.createGauge({\n name: 'app_event_loop_lag_ms',\n help: 'Estimated event loop lag in milliseconds',\n updateFn: this.measureLag,\n })\n\n this.createGauge({\n name: 'app_container_memory_limit_bytes',\n help: 'Max RAM available to container from cgroup (memory.max)',\n updateFn: this.getContainerMemoryLimit,\n })\n\n this.createGauge({\n name: 'app_uptime_seconds',\n help: 'How long the process has been running',\n updateFn: process.uptime,\n })\n\n this.createGauge({\n name: 'app_bootstrap_web_concurrency',\n help: 'WEB_CONCURRENCY at process start (diagnostic; 0 if unset/invalid)',\n updateFn: () => this._bootstrapWebConcurrency,\n })\n\n this.createGauge({\n name: 'app_bootstrap_host_cpu_count',\n help: 'os.cpus().length at process start (diagnostic)',\n updateFn: () => this._bootstrapHostCpuCount,\n })\n }\n\n const registerHttpCounters =\n this.httpMetricsEnabled && !this._webRedisHttpRecordingOnly\n\n if (registerHttpCounters) {\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 getCpuUsagePercent = () => {\n try {\n const stat = fs.readFileSync('/sys/fs/cgroup/cpu.stat', 'utf-8')\n const match = stat.match(/usage_usec (\\d+)/)\n if (!match) return 0\n\n const now = Date.now()\n const currentUsage = parseInt(match[1], 10)\n\n if (this._lastUsageMicros === 0) {\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n return 0\n }\n\n const deltaUsage = currentUsage - this._lastUsageMicros\n const deltaTime = now - this._lastCheckTime\n\n this._lastUsageMicros = currentUsage\n this._lastCheckTime = now\n\n return (deltaUsage / (deltaTime * 1000)) * 100\n } catch {\n return 0\n }\n }\n\n getAvailableCPUs() {\n try {\n const cpuMaxPath = '/sys/fs/cgroup/cpu.max'\n if (fs.existsSync(cpuMaxPath)) {\n const [quotaStr, periodStr] = fs\n .readFileSync(cpuMaxPath, 'utf8')\n .trim()\n .split(' ')\n if (quotaStr === 'max') return os.cpus().length\n return parseInt(quotaStr, 10) / parseInt(periodStr, 10)\n }\n return os.cpus().length\n } catch {\n return 1\n }\n }\n\n getContainerMemoryUsage() {\n try {\n return parseInt(\n fs.readFileSync('/sys/fs/cgroup/memory.current', 'utf-8').trim(),\n 10\n )\n } catch {\n return process.memoryUsage().rss\n }\n }\n\n getContainerMemoryLimit() {\n try {\n const path = '/sys/fs/cgroup/memory.max'\n if (fs.existsSync(path)) {\n const val = fs.readFileSync(path, 'utf-8').trim()\n if (val !== 'max') {\n const parsed = parseInt(val, 10)\n if (parsed && parsed < os.totalmem()) return parsed\n }\n }\n return os.totalmem()\n } catch {\n return os.totalmem()\n }\n }\n\n measureLag() {\n return new Promise(resolve => {\n const start = Date.now()\n setImmediate(() => resolve(Date.now() - start))\n })\n }\n\n trackHttpRequest({\n method,\n route,\n status_code,\n appId = '',\n databaseId = '',\n duration,\n }) {\n if (!this.httpMetricsEnabled) return\n\n if (this._httpRedisStore) {\n this._httpRedisStore.record(\n method,\n route,\n status_code,\n appId,\n databaseId,\n duration\n )\n this._maybeLogHttpRecord(method, route, status_code)\n return\n }\n\n this.countersFunctions?.app_requests_total({\n method,\n route,\n status_code,\n appId,\n databaseId,\n })\n this.countersFunctions?.app_requests_total_duration(\n {\n method,\n route,\n status_code,\n appId,\n databaseId,\n },\n duration\n )\n this._maybeLogHttpRecord(method, route, status_code)\n }\n\n /**\n * Start periodic push to VM-agent (`METRICS_PUSHGATEWAY_URL`). Interval defaults to `intervalSec` from config/env.\n * @param {number} [interval] Seconds between pushes; defaults to `this.intervalSec`\n * @param {() => void | Promise<void>} [customPushMetrics] Optional; replaces default push when provided\n * @returns {void}\n */\n startPush = (interval, customPushMetrics) => {\n if (this._webRedisHttpRecordingOnly) {\n return\n }\n if (!shouldRunMetricsPush(this)) {\n if (\n this.enabled &&\n !this._skippedPushWorkerLogged &&\n process.env.METRICS_SUPPRESS_SKIP_PUSH_LOG !== 'true'\n ) {\n console.warn(\n `${this.prefixLogs} Skipping VM-agent push on this worker. METRICS_PUSH_ALL_WORKERS=true restores per-worker push.`\n )\n this._skippedPushWorkerLogged = true\n }\n return\n }\n this._startPush(interval, customPushMetrics)\n }\n\n async pushMetrics() {\n if (this._webRedisHttpRecordingOnly) {\n return\n }\n if (\n this._httpRedisStore &&\n shouldRunMetricsPush(this) &&\n this.countersFunctions?.app_requests_total &&\n this.countersFunctions?.app_requests_total_duration\n ) {\n const flushed = await this._httpRedisStore.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 if (flushed) {\n console.warn(\n `${this.prefixLogs} http_metrics_redis_flush pid=${process.pid}${clusterWorkerTag()} process_type=${this.processType} dyno_id=${this.dynoId} drained=true`\n )\n }\n }\n // eslint-disable-next-line consistent-return\n return super.pushMetrics()\n }\n\n trackHttpRequestMiddleware = (req, res, next) => {\n if (!this.enabled || !this.httpMetricsEnabled || req.method === 'OPTIONS') {\n next()\n return\n }\n\n const start = Date.now()\n res.on('finish', () => {\n const route = req.route?.path || req.path || 'unknown'\n const appId =\n req.params?.appId || req.body?.appId || req.query?.appId || ''\n const databaseId =\n req.params?.databaseId ||\n req.body?.databaseId ||\n req.query?.databaseId ||\n req.params?.datasourceId ||\n req.body?.datasourceId ||\n req.query?.datasourceId ||\n ''\n\n this.trackHttpRequest({\n method: req.method,\n route,\n status_code: res.statusCode,\n appId,\n databaseId,\n duration: Date.now() - start,\n })\n })\n\n next()\n }\n}\n\nmodule.exports = { MetricsClient }\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -419,6 +419,7 @@ class BaseMetricsClient {
|
|
|
419
419
|
}
|
|
420
420
|
return new Promise((resolve, reject) => {
|
|
421
421
|
const u = new URL(pushUrl)
|
|
422
|
+
let payloadBytes = 0
|
|
422
423
|
const req = (u.protocol === 'https:' ? https : http).request(
|
|
423
424
|
{
|
|
424
425
|
hostname: u.hostname,
|
|
@@ -437,7 +438,11 @@ class BaseMetricsClient {
|
|
|
437
438
|
: undefined,
|
|
438
439
|
},
|
|
439
440
|
res => {
|
|
441
|
+
res.resume()
|
|
440
442
|
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
443
|
+
console.warn(
|
|
444
|
+
`${this.prefixLogs} metrics_pushed pid=${process.pid} bytes=${payloadBytes} status=${res.statusCode}`
|
|
445
|
+
)
|
|
441
446
|
resolve()
|
|
442
447
|
} else {
|
|
443
448
|
let data = ''
|
|
@@ -454,7 +459,8 @@ class BaseMetricsClient {
|
|
|
454
459
|
this._registry
|
|
455
460
|
.metrics()
|
|
456
461
|
.then(metrics => {
|
|
457
|
-
|
|
462
|
+
payloadBytes = Buffer.byteLength(metrics, 'utf8')
|
|
463
|
+
req.setHeader('Content-Length', payloadBytes)
|
|
458
464
|
req.end(metrics, 'utf8')
|
|
459
465
|
})
|
|
460
466
|
.catch(reject)
|
|
@@ -27,6 +27,21 @@ function isMetricsExporterProcessType(processType) {
|
|
|
27
27
|
return processType === 'metrics'
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/** Extra tag when `cluster` workers are used (same pod hostname, different PIDs). */
|
|
31
|
+
function clusterWorkerTag() {
|
|
32
|
+
try {
|
|
33
|
+
const cluster = require('cluster')
|
|
34
|
+
if (cluster.isWorker && cluster.worker) {
|
|
35
|
+
return ` cluster_worker_id=${cluster.worker.id}`
|
|
36
|
+
}
|
|
37
|
+
} catch (_) {
|
|
38
|
+
/* ignore */
|
|
39
|
+
}
|
|
40
|
+
return ''
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const HTTP_METRICS_LOG_INTERVAL_MS = 5000
|
|
44
|
+
|
|
30
45
|
/**
|
|
31
46
|
* MetricsClient handles Prometheus metrics collection and push.
|
|
32
47
|
*
|
|
@@ -143,6 +158,11 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
143
158
|
this._lastUsageMicros = 0
|
|
144
159
|
this._lastCheckTime = Date.now()
|
|
145
160
|
|
|
161
|
+
this._metricsBootstrapLogged = false
|
|
162
|
+
this._httpLogWindowStart = 0
|
|
163
|
+
this._httpLogBatchCount = 0
|
|
164
|
+
this._httpLogLastSample = ''
|
|
165
|
+
|
|
146
166
|
this._initDefaultMetrics()
|
|
147
167
|
this._logMetricsBootstrap()
|
|
148
168
|
}
|
|
@@ -151,15 +171,46 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
151
171
|
if (!this.enabled) {
|
|
152
172
|
return
|
|
153
173
|
}
|
|
174
|
+
if (this._metricsBootstrapLogged) {
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
this._metricsBootstrapLogged = true
|
|
154
178
|
const wc = process.env.WEB_CONCURRENCY || ''
|
|
155
179
|
const httpMode = !this.httpMetricsEnabled
|
|
156
180
|
? 'off'
|
|
157
181
|
: this._httpRedisStore
|
|
158
182
|
? 'redis'
|
|
159
183
|
: 'local_counters'
|
|
184
|
+
const pidTag = `pid=${process.pid}`
|
|
185
|
+
const clusterTag = clusterWorkerTag()
|
|
186
|
+
console.warn(
|
|
187
|
+
`${this.prefixLogs} metrics bootstrap ${pidTag}${clusterTag} WEB_CONCURRENCY=${wc || '(unset)'} host_cpus=${this._bootstrapHostCpuCount} dyno_id=${this.dynoId} process_type=${this.processType} scheduling_id=${process.env.DYNO || 'n/a'} http_metrics=${httpMode} redis_http=${this.httpMetricsRedisAggregation} web_redis_only=${this._webRedisHttpRecordingOnly}`
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Throttled HTTP recording log (not gated by METRICS_LOG_VALUES). Same pod can run many workers
|
|
193
|
+
* (same dyno_id); pid + cluster_worker_id distinguish processes.
|
|
194
|
+
*/
|
|
195
|
+
_maybeLogHttpRecord(method, route, status_code) {
|
|
196
|
+
if (!this.enabled || !this.httpMetricsEnabled) {
|
|
197
|
+
return
|
|
198
|
+
}
|
|
199
|
+
this._httpLogBatchCount += 1
|
|
200
|
+
this._httpLogLastSample = `${method} ${route} ${status_code}`
|
|
201
|
+
const now = Date.now()
|
|
202
|
+
if (!this._httpLogWindowStart) {
|
|
203
|
+
this._httpLogWindowStart = now
|
|
204
|
+
}
|
|
205
|
+
if (now - this._httpLogWindowStart < HTTP_METRICS_LOG_INTERVAL_MS) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
const clusterTag = clusterWorkerTag()
|
|
160
209
|
console.warn(
|
|
161
|
-
`${this.prefixLogs}
|
|
210
|
+
`${this.prefixLogs} http_metrics_record pid=${process.pid}${clusterTag} process_type=${this.processType} dyno_id=${this.dynoId} count=${this._httpLogBatchCount} sample=${this._httpLogLastSample}`
|
|
162
211
|
)
|
|
212
|
+
this._httpLogWindowStart = now
|
|
213
|
+
this._httpLogBatchCount = 0
|
|
163
214
|
}
|
|
164
215
|
|
|
165
216
|
get isWebRedisHttpRecordingOnly() {
|
|
@@ -346,6 +397,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
346
397
|
databaseId,
|
|
347
398
|
duration
|
|
348
399
|
)
|
|
400
|
+
this._maybeLogHttpRecord(method, route, status_code)
|
|
349
401
|
return
|
|
350
402
|
}
|
|
351
403
|
|
|
@@ -366,6 +418,7 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
366
418
|
},
|
|
367
419
|
duration
|
|
368
420
|
)
|
|
421
|
+
this._maybeLogHttpRecord(method, route, status_code)
|
|
369
422
|
}
|
|
370
423
|
|
|
371
424
|
/**
|
|
@@ -404,12 +457,17 @@ class MetricsClient extends BaseMetricsClient {
|
|
|
404
457
|
this.countersFunctions?.app_requests_total &&
|
|
405
458
|
this.countersFunctions?.app_requests_total_duration
|
|
406
459
|
) {
|
|
407
|
-
await this._httpRedisStore.flushToCounters(
|
|
460
|
+
const flushed = await this._httpRedisStore.flushToCounters(
|
|
408
461
|
(labels, value) =>
|
|
409
462
|
this.countersFunctions.app_requests_total(labels, value),
|
|
410
463
|
(labels, value) =>
|
|
411
464
|
this.countersFunctions.app_requests_total_duration(labels, value)
|
|
412
465
|
)
|
|
466
|
+
if (flushed) {
|
|
467
|
+
console.warn(
|
|
468
|
+
`${this.prefixLogs} http_metrics_redis_flush pid=${process.pid}${clusterWorkerTag()} process_type=${this.processType} dyno_id=${this.dynoId} drained=true`
|
|
469
|
+
)
|
|
470
|
+
}
|
|
413
471
|
}
|
|
414
472
|
// eslint-disable-next-line consistent-return
|
|
415
473
|
return super.pushMetrics()
|