catalog: register OpenTelemetry metrics, deprecate prom-client

Signed-off-by: Johan Haals <johan.haals@gmail.com>
This commit is contained in:
Johan Haals
2022-12-09 16:25:44 +01:00
parent 4890518e25
commit 273ba3a77f
4 changed files with 152 additions and 23 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': minor
---
Deprecated Prometheus metrics in favour of OpenTelemtry metrics.
+1
View File
@@ -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);
}
+65 -5
View File
@@ -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