catalog: register OpenTelemetry metrics, deprecate prom-client
Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend': minor
|
||||
---
|
||||
|
||||
Deprecated Prometheus metrics in favour of OpenTelemtry metrics.
|
||||
@@ -47,6 +47,7 @@
|
||||
"@backstage/plugin-scaffolder-common": "workspace:^",
|
||||
"@backstage/plugin-search-common": "workspace:^",
|
||||
"@backstage/types": "workspace:^",
|
||||
"@opentelemetry/api": "^1.3.0",
|
||||
"@types/express": "^4.17.6",
|
||||
"codeowners-utils": "^1.0.2",
|
||||
"core-js": "^3.6.5",
|
||||
|
||||
@@ -23,6 +23,7 @@ import { assertError, serializeError, stringifyError } from '@backstage/errors';
|
||||
import { Hash } from 'crypto';
|
||||
import stableStringify from 'fast-json-stable-stringify';
|
||||
import { Logger } from 'winston';
|
||||
import { metrics } from '@opentelemetry/api';
|
||||
import { ProcessingDatabase, RefreshStateItem } from '../database/types';
|
||||
import { createCounterMetric, createSummaryMetric } from '../util/metrics';
|
||||
import {
|
||||
@@ -257,62 +258,124 @@ export class DefaultCatalogProcessingEngine implements CatalogProcessingEngine {
|
||||
|
||||
// Helps wrap the timing and logging behaviors
|
||||
function progressTracker() {
|
||||
const stitchedEntities = createCounterMetric({
|
||||
// prom-client metrics are deprecated in favour of OpenTelemetry metrics.
|
||||
const promStitchedEntities = createCounterMetric({
|
||||
name: 'catalog_stitched_entities_count',
|
||||
help: 'Amount of entities stitched',
|
||||
help: 'Amount of entities stitched. DEPRECATED, use OpenTelemetry metrics instead',
|
||||
});
|
||||
const processedEntities = createCounterMetric({
|
||||
const promProcessedEntities = createCounterMetric({
|
||||
name: 'catalog_processed_entities_count',
|
||||
help: 'Amount of entities processed',
|
||||
help: 'Amount of entities processed, DEPRECATED, use OpenTelemetry metrics instead',
|
||||
labelNames: ['result'],
|
||||
});
|
||||
const processingDuration = createSummaryMetric({
|
||||
const promProcessingDuration = createSummaryMetric({
|
||||
name: 'catalog_processing_duration_seconds',
|
||||
help: 'Time spent executing the full processing flow',
|
||||
help: 'Time spent executing the full processing flow, DEPRECATED, use OpenTelemetry metrics instead',
|
||||
labelNames: ['result'],
|
||||
});
|
||||
const processorsDuration = createSummaryMetric({
|
||||
const promProcessorsDuration = createSummaryMetric({
|
||||
name: 'catalog_processors_duration_seconds',
|
||||
help: 'Time spent executing catalog processors',
|
||||
help: 'Time spent executing catalog processors, DEPRECATED, use OpenTelemetry metrics instead',
|
||||
labelNames: ['result'],
|
||||
});
|
||||
const processingQueueDelay = createSummaryMetric({
|
||||
const promProcessingQueueDelay = createSummaryMetric({
|
||||
name: 'catalog_processing_queue_delay_seconds',
|
||||
help: 'The amount of delay between being scheduled for processing, and the start of actually being processed',
|
||||
help: 'The amount of delay between being scheduled for processing, and the start of actually being processed, DEPRECATED, use OpenTelemetry metrics instead',
|
||||
});
|
||||
|
||||
const meter = metrics.getMeter('default');
|
||||
const stitchedEntities = meter.createCounter(
|
||||
'catalog.stitched.entities.count',
|
||||
{
|
||||
description: 'Amount of entities stitched',
|
||||
},
|
||||
);
|
||||
|
||||
const processedEntities = meter.createCounter(
|
||||
'catalog.stitched.entities.count',
|
||||
{ description: 'Amount of entities processed' },
|
||||
);
|
||||
|
||||
const processingDuration = meter.createHistogram(
|
||||
'catalog.processing.duration',
|
||||
{
|
||||
description: 'Time spent executing the full processing flow',
|
||||
unit: 'seconds',
|
||||
},
|
||||
);
|
||||
|
||||
const processorsDuration = meter.createHistogram(
|
||||
'catalog.processors.duration',
|
||||
{
|
||||
description: 'Time spent executing catalog processors',
|
||||
unit: 'seconds',
|
||||
},
|
||||
);
|
||||
|
||||
const processingQueueDelay = meter.createHistogram(
|
||||
'catalog.processing.queue.delay',
|
||||
{
|
||||
description:
|
||||
'The amount of delay between being scheduled for processing, and the start of actually being processed',
|
||||
unit: 'seconds',
|
||||
},
|
||||
);
|
||||
|
||||
function processStart(item: RefreshStateItem, logger: Logger) {
|
||||
const startTime = process.hrtime();
|
||||
const endOverallTimer = promProcessingDuration.startTimer();
|
||||
const endProcessorsTimer = promProcessorsDuration.startTimer();
|
||||
|
||||
logger.debug(`Processing ${item.entityRef}`);
|
||||
|
||||
if (item.nextUpdateAt) {
|
||||
processingQueueDelay.observe(-item.nextUpdateAt.diffNow().as('seconds'));
|
||||
promProcessingQueueDelay.observe(
|
||||
-item.nextUpdateAt.diffNow().as('seconds'),
|
||||
);
|
||||
processingQueueDelay.record(-item.nextUpdateAt.diffNow().as('seconds'));
|
||||
}
|
||||
|
||||
const endOverallTimer = processingDuration.startTimer();
|
||||
const endProcessorsTimer = processorsDuration.startTimer();
|
||||
function endTime() {
|
||||
const delta = process.hrtime(startTime);
|
||||
return delta[0] + delta[1] / 1e9;
|
||||
}
|
||||
|
||||
function markProcessorsCompleted(result: EntityProcessingResult) {
|
||||
endProcessorsTimer({ result: result.ok ? 'ok' : 'failed' });
|
||||
processorsDuration.record(endTime(), {
|
||||
result: result.ok ? 'ok' : 'failed',
|
||||
});
|
||||
}
|
||||
|
||||
function markSuccessfulWithNoChanges() {
|
||||
endOverallTimer({ result: 'unchanged' });
|
||||
processedEntities.inc({ result: 'unchanged' }, 1);
|
||||
promProcessedEntities.inc({ result: 'unchanged' }, 1);
|
||||
|
||||
processingDuration.record(endTime(), { result: 'unchanged' });
|
||||
processedEntities.add(1, { result: 'unchanged' });
|
||||
}
|
||||
|
||||
function markSuccessfulWithErrors() {
|
||||
endOverallTimer({ result: 'errors' });
|
||||
processedEntities.inc({ result: 'errors' }, 1);
|
||||
promProcessedEntities.inc({ result: 'errors' }, 1);
|
||||
|
||||
processingDuration.record(endTime(), { result: 'errors' });
|
||||
processedEntities.add(1, { result: 'errors' });
|
||||
}
|
||||
|
||||
function markSuccessfulWithChanges(stitchedCount: number) {
|
||||
endOverallTimer({ result: 'changed' });
|
||||
stitchedEntities.inc(stitchedCount);
|
||||
processedEntities.inc({ result: 'changed' }, 1);
|
||||
promStitchedEntities.inc(stitchedCount);
|
||||
promProcessedEntities.inc({ result: 'changed' }, 1);
|
||||
|
||||
processingDuration.record(endTime(), { result: 'changed' });
|
||||
stitchedEntities.add(stitchedCount);
|
||||
processedEntities.add(1, { result: 'changed' });
|
||||
}
|
||||
|
||||
function markFailed(error: Error) {
|
||||
processedEntities.inc({ result: 'failed' }, 1);
|
||||
promProcessedEntities.inc({ result: 'failed' }, 1);
|
||||
processedEntities.add(1, { result: 'failed' });
|
||||
logger.warn(`Processing of ${item.entityRef} failed`, error);
|
||||
}
|
||||
|
||||
|
||||
@@ -5215,6 +5215,7 @@ __metadata:
|
||||
"@backstage/plugin-search-backend-node": "workspace:^"
|
||||
"@backstage/plugin-search-common": "workspace:^"
|
||||
"@backstage/types": "workspace:^"
|
||||
"@opentelemetry/api": ^1.3.0
|
||||
"@types/core-js": ^2.5.4
|
||||
"@types/express": ^4.17.6
|
||||
"@types/git-url-parse": ^9.0.0
|
||||
@@ -12218,10 +12219,66 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/api@npm:^1.0.1":
|
||||
version: 1.0.4
|
||||
resolution: "@opentelemetry/api@npm:1.0.4"
|
||||
checksum: 793e9b5c21666b647a60c58c46c3e00ad1dac38505102b026ad0ef617571d637aca54a18533a73c1e288c95b5ac77e2db17f96467f11833ac1165338e1184260
|
||||
"@opentelemetry/api@npm:^1.0.1, @opentelemetry/api@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "@opentelemetry/api@npm:1.3.0"
|
||||
checksum: 33d284b67b6fab20ff72961d289c6487d3cb27caf7489f0231d7030551f82871e081e744b0390751d8aef3bf1614bd79f854788901a354e15274f552581fb374
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/core@npm:1.8.0":
|
||||
version: 1.8.0
|
||||
resolution: "@opentelemetry/core@npm:1.8.0"
|
||||
dependencies:
|
||||
"@opentelemetry/semantic-conventions": 1.8.0
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ">=1.0.0 <1.4.0"
|
||||
checksum: 09cd58ec764f97b175af47fbaff335f06a31914fcb59b30c4f96f6ba69391ce4e59e3da46a95fd15a7d0e8fc5c638195aba95ca1a916127207481f1283991c97
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/exporter-prometheus@npm:^0.34.0":
|
||||
version: 0.34.0
|
||||
resolution: "@opentelemetry/exporter-prometheus@npm:0.34.0"
|
||||
dependencies:
|
||||
"@opentelemetry/core": 1.8.0
|
||||
"@opentelemetry/resources": 1.8.0
|
||||
"@opentelemetry/sdk-metrics": 1.8.0
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ^1.3.0
|
||||
checksum: 6c17d5ec1c638fb5f561230f706d84866d504aa2805ed74ab2174dae9a1c9d39ce909b61ba9796d38fbcdef85f76805e23d5c80d762231e08384e032beb38b65
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/resources@npm:1.8.0":
|
||||
version: 1.8.0
|
||||
resolution: "@opentelemetry/resources@npm:1.8.0"
|
||||
dependencies:
|
||||
"@opentelemetry/core": 1.8.0
|
||||
"@opentelemetry/semantic-conventions": 1.8.0
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ">=1.0.0 <1.4.0"
|
||||
checksum: eeea7864c486d31679dbae3c31e9badf277ece24ba8bd063e2bcc34b2d7240f543678b8106743aff30c6b0f028f2bed286d64cfd7b5cde6f9a0f6a9271a3fce1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/sdk-metrics@npm:1.8.0, @opentelemetry/sdk-metrics@npm:^1.8.0":
|
||||
version: 1.8.0
|
||||
resolution: "@opentelemetry/sdk-metrics@npm:1.8.0"
|
||||
dependencies:
|
||||
"@opentelemetry/core": 1.8.0
|
||||
"@opentelemetry/resources": 1.8.0
|
||||
lodash.merge: 4.6.2
|
||||
peerDependencies:
|
||||
"@opentelemetry/api": ">=1.3.0 <1.4.0"
|
||||
checksum: 8dfb82e70b14fe2e95ce3f3d0b18e42981bfabe64c63b7f8c429aed197815356836a0350ad5cf38696f561c616ff5572f2ca63f4f968ae1367ed7180f730cad7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@opentelemetry/semantic-conventions@npm:1.8.0":
|
||||
version: 1.8.0
|
||||
resolution: "@opentelemetry/semantic-conventions@npm:1.8.0"
|
||||
checksum: df30ad9486b6c611c4110fab80815301a7cc9cb320983d6c5792a1b411dc4e4f04c489b2abfdea0da7f7bbb27b9f3c456764ba07f23432900a9bbcbc5f98ff58
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -22007,6 +22064,9 @@ __metadata:
|
||||
"@backstage/plugin-todo-backend": "workspace:^"
|
||||
"@gitbeaker/node": ^35.1.0
|
||||
"@octokit/rest": ^19.0.3
|
||||
"@opentelemetry/api": ^1.3.0
|
||||
"@opentelemetry/exporter-prometheus": ^0.34.0
|
||||
"@opentelemetry/sdk-metrics": ^1.8.0
|
||||
"@types/dockerode": ^3.3.0
|
||||
"@types/express": ^4.17.6
|
||||
"@types/express-serve-static-core": ^4.17.5
|
||||
@@ -27627,7 +27687,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"lodash.merge@npm:^4.6.2":
|
||||
"lodash.merge@npm:4.6.2, lodash.merge@npm:^4.6.2":
|
||||
version: 4.6.2
|
||||
resolution: "lodash.merge@npm:4.6.2"
|
||||
checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005
|
||||
|
||||
Reference in New Issue
Block a user