Merge pull request #15145 from backstage/jhaals/catalog-openTelemetry

catalog: register OpenTelemetry metrics, deprecate prom-client
This commit is contained in:
Johan Haals
2022-12-16 14:32:01 +01:00
committed by GitHub
4 changed files with 91 additions and 22 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,123 @@ 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.processed.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'));
const seconds = -item.nextUpdateAt.diffNow().as('seconds');
promProcessingQueueDelay.observe(seconds);
processingQueueDelay.record(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);
}
+5 -4
View File
@@ -5245,6 +5245,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
@@ -12458,10 +12459,10 @@ __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