diff --git a/.changeset/heavy-needles-poke.md b/.changeset/heavy-needles-poke.md index 830533a8fb..91a98a9102 100644 --- a/.changeset/heavy-needles-poke.md +++ b/.changeset/heavy-needles-poke.md @@ -1,5 +1,6 @@ --- '@backstage/backend-defaults': patch +'@backstage/plugin-catalog-backend-module-incremental-ingestion': patch --- -Add task scheduler metrics as two gauges that track the last start and end timestamps as epoch seconds. +Add task metrics as two gauges that track the last start and end timestamps as epoch seconds. diff --git a/plugins/catalog-backend-module-incremental-ingestion/package.json b/plugins/catalog-backend-module-incremental-ingestion/package.json index d57b1c8f3f..a85e621015 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/package.json +++ b/plugins/catalog-backend-module-incremental-ingestion/package.json @@ -61,6 +61,7 @@ "@backstage/plugin-events-node": "workspace:^", "@backstage/plugin-permission-common": "workspace:^", "@backstage/types": "workspace:^", + "@opentelemetry/api": "^1.3.0", "@types/express": "^4.17.6", "express": "^4.17.1", "express-promise-router": "^4.1.0", diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts index 676a175074..e005d29292 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/engine/IncrementalIngestionEngine.ts @@ -15,6 +15,7 @@ */ import type { DeferredEntity } from '@backstage/plugin-catalog-node'; +import { Gauge, metrics } from '@opentelemetry/api'; import { IterationEngine, IterationEngineOptions } from '../types'; import { IncrementalIngestionDatabaseManager } from '../database/IncrementalIngestionDatabaseManager'; import { performance } from 'perf_hooks'; @@ -27,10 +28,14 @@ import { HumanDuration } from '@backstage/types'; export class IncrementalIngestionEngine implements IterationEngine { private readonly restLength: Duration; private readonly backoff: HumanDuration[]; + private readonly lastStarted: Gauge; + private readonly lastCompleted: Gauge; private manager: IncrementalIngestionDatabaseManager; constructor(private options: IterationEngineOptions) { + const meter = metrics.getMeter('default'); + this.manager = options.manager; this.restLength = Duration.fromObject(options.restLength); this.backoff = options.backoff ?? [ @@ -39,6 +44,23 @@ export class IncrementalIngestionEngine implements IterationEngine { { minutes: 30 }, { hours: 3 }, ]; + + this.lastStarted = meter.createGauge( + 'catalog_incremental.ingestions.started', + { + description: + 'Epoch timestamp seconds when the ingestion was last started', + unit: 'seconds', + }, + ); + this.lastCompleted = meter.createGauge( + 'catalog_incremental.ingestions.completed', + { + description: + 'Epoch timestamp seconds when the ingestion was last completed', + unit: 'seconds', + }, + ); } async taskFn(signal: AbortSignal) { @@ -70,6 +92,9 @@ export class IncrementalIngestionEngine implements IterationEngine { `incremental-engine: Ingestion ${ingestionId} rest period complete. Ingestion will start again`, ); + this.lastStarted.record(Date.now() / 1000, { + providerName: this.options.provider.getProviderName(), + }); await this.manager.setProviderComplete(ingestionId); } else { this.options.logger.debug( @@ -85,6 +110,10 @@ export class IncrementalIngestionEngine implements IterationEngine { this.options.logger.info( `incremental-engine: Ingestion '${ingestionId}' complete, transitioning to rest period of ${this.restLength.toHuman()}`, ); + this.lastCompleted.record(Date.now() / 1000, { + providerName: this.options.provider.getProviderName(), + status: 'completed', + }); await this.manager.setProviderResting( ingestionId, this.restLength, @@ -122,6 +151,10 @@ export class IncrementalIngestionEngine implements IterationEngine { this.options.logger.error( `incremental-engine: Ingestion '${ingestionId}' threw an error during ingestion burst. Ingestion will backoff for ${currentBackoff.toHuman()} (${truncatedError})`, ); + this.lastCompleted.record(Date.now() / 1000, { + providerName: this.options.provider.getProviderName(), + status: 'failed', + }); await this.manager.setProviderBackoff( ingestionId, diff --git a/yarn.lock b/yarn.lock index 6e73a22735..4243a246da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5955,6 +5955,7 @@ __metadata: "@backstage/plugin-events-node": "workspace:^" "@backstage/plugin-permission-common": "workspace:^" "@backstage/types": "workspace:^" + "@opentelemetry/api": ^1.3.0 "@types/express": ^4.17.6 "@types/luxon": ^3.0.0 express: ^4.17.1