refactor: use MetricsService

Signed-off-by: Kurt King <kurtaking@gmail.com>
This commit is contained in:
Kurt King
2026-03-23 23:37:58 -06:00
parent 6bfcd9967b
commit 961e274548
11 changed files with 51 additions and 16 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder-backend': patch
---
Migrated OpenTelemetry metrics to use the `MetricsService` from `@backstage/backend-plugin-api/alpha` instead of the raw `@opentelemetry/api` meter.
-1
View File
@@ -78,7 +78,6 @@
"@backstage/plugin-scaffolder-common": "workspace:^",
"@backstage/plugin-scaffolder-node": "workspace:^",
"@backstage/types": "workspace:^",
"@opentelemetry/api": "^1.9.0",
"@types/luxon": "^3.0.0",
"express": "^4.22.0",
"fs-extra": "^11.2.0",
@@ -63,6 +63,7 @@ import {
import {
actionsServiceRef,
actionsRegistryServiceRef,
metricsServiceRef,
} from '@backstage/backend-plugin-api/alpha';
import { createScaffolderActions } from './actions';
@@ -151,6 +152,7 @@ export const scaffolderPlugin = createBackendPlugin({
actionsRegistry: actionsServiceRef,
actionsRegistryService: actionsRegistryServiceRef,
scaffolderService: scaffolderServiceRef,
metrics: metricsServiceRef,
},
async init({
logger,
@@ -168,6 +170,7 @@ export const scaffolderPlugin = createBackendPlugin({
actionsRegistry,
actionsRegistryService,
scaffolderService,
metrics,
}) {
const log = loggerToWinstonLogger(logger);
const integrations = ScmIntegrations.fromConfig(config);
@@ -244,6 +247,7 @@ export const scaffolderPlugin = createBackendPlugin({
events,
auditor,
actionsRegistry,
metrics,
});
httpRouter.use(router);
},
@@ -19,6 +19,7 @@ import {
BackstageCredentials,
LoggerService,
} from '@backstage/backend-plugin-api';
import type { MetricsService } from '@backstage/backend-plugin-api/alpha';
import type { UserEntity } from '@backstage/catalog-model';
import { Config } from '@backstage/config';
import { ScmIntegrations } from '@backstage/integration';
@@ -81,6 +82,7 @@ export type TemplateTesterCreateOptions = {
additionalTemplateGlobals?: Record<string, TemplateGlobal>;
permissions?: PermissionEvaluator;
config?: Config;
metrics: MetricsService;
};
/**
@@ -39,7 +39,10 @@ import {
mockCredentials,
mockServices,
} from '@backstage/backend-test-utils';
import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha';
import {
actionsRegistryServiceMock,
metricsServiceMock,
} from '@backstage/backend-test-utils/alpha';
describe('NunjucksWorkflowRunner', () => {
let actionRegistry: TemplateActionRegistry;
@@ -249,6 +252,7 @@ describe('NunjucksWorkflowRunner', () => {
logger,
permissions: mockedPermissionApi,
config,
metrics: metricsServiceMock.mock(),
});
});
@@ -23,7 +23,6 @@ import {
TaskStep,
} from '@backstage/plugin-scaffolder-common';
import { JsonArray, JsonObject, JsonValue } from '@backstage/types';
import { metrics } from '@opentelemetry/api';
import fs from 'fs-extra';
import { validate as validateJsonSchema } from 'jsonschema';
import nunjucks from 'nunjucks';
@@ -42,6 +41,7 @@ import type {
LoggerService,
PermissionsService,
} from '@backstage/backend-plugin-api';
import type { MetricsService } from '@backstage/backend-plugin-api/alpha';
import { UserEntity } from '@backstage/catalog-model';
import {
AuthorizeResult,
@@ -78,6 +78,7 @@ type NunjucksWorkflowRunnerOptions = {
additionalTemplateGlobals?: Record<string, TemplateGlobal>;
permissions?: PermissionsService;
config?: Config;
metrics: MetricsService;
};
type TemplateContext = {
@@ -188,6 +189,8 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
secrets?: Record<string, string>;
} = { parameters: {}, secrets: {} };
private readonly tracker;
constructor(options: NunjucksWorkflowRunnerOptions) {
this.options = options;
this.defaultTemplateFilters = convertFiltersToRecord(
@@ -195,10 +198,9 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
integrations: this.options.integrations,
}),
);
this.tracker = scaffoldingTracker(options.metrics);
}
private readonly tracker = scaffoldingTracker();
async getEnvironmentConfig(): Promise<{
parameters: JsonObject;
secrets?: TaskSecrets;
@@ -700,7 +702,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner {
}
}
function scaffoldingTracker() {
function scaffoldingTracker(metrics: MetricsService) {
// prom-client metrics are deprecated in favour of OpenTelemetry metrics.
const promTaskCount = createCounterMetric({
name: 'scaffolder_task_count',
@@ -723,23 +725,22 @@ function scaffoldingTracker() {
labelNames: ['template', 'step', 'result'],
});
const meter = metrics.getMeter('default');
const taskCount = meter.createCounter('scaffolder.task.count', {
const taskCount = metrics.createCounter('scaffolder.task.count', {
description: 'Count of task runs',
});
const taskDuration = meter.createHistogram('scaffolder.task.duration', {
const taskDuration = metrics.createHistogram('scaffolder.task.duration', {
description: 'Duration of a task run',
unit: 'seconds',
unit: 's',
});
const stepCount = meter.createCounter('scaffolder.step.count', {
const stepCount = metrics.createCounter('scaffolder.step.count', {
description: 'Count of step runs',
});
const stepDuration = meter.createHistogram('scaffolder.step.duration', {
const stepDuration = metrics.createHistogram('scaffolder.step.duration', {
description: 'Duration of a step runs',
unit: 'seconds',
unit: 's',
});
async function taskStart(task: TaskContext) {
@@ -36,6 +36,7 @@ import { WorkflowRunner } from './types';
import ObservableImpl from 'zen-observable';
import waitForExpect from 'wait-for-expect';
import { mockServices } from '@backstage/backend-test-utils';
import { metricsServiceMock } from '@backstage/backend-test-utils/alpha';
import { loggerToWinstonLogger } from '../../util/loggerToWinstonLogger';
jest.mock('./NunjucksWorkflowRunner');
@@ -93,6 +94,7 @@ describe('TaskWorker', () => {
integrations,
taskBroker: broker,
actionRegistry,
metrics: metricsServiceMock.mock(),
});
await broker.dispatch({
@@ -124,6 +126,7 @@ describe('TaskWorker', () => {
integrations,
taskBroker: broker,
actionRegistry,
metrics: metricsServiceMock.mock(),
});
const { taskId } = await broker.dispatch({
@@ -174,6 +177,7 @@ describe('TaskWorker', () => {
},
},
}),
metrics: metricsServiceMock.mock(),
});
await taskWorker.runOneTask({
@@ -261,6 +265,7 @@ describe('Concurrent TaskWorker', () => {
taskBroker: broker,
actionRegistry,
concurrentTasksLimit: expectedConcurrentTasks,
metrics: metricsServiceMock.mock(),
});
taskWorker.start();
@@ -307,6 +312,7 @@ describe('Cancellable TaskWorker', () => {
integrations,
taskBroker,
actionRegistry,
metrics: metricsServiceMock.mock(),
});
const steps = [...Array(10)].map(n => ({
@@ -15,6 +15,7 @@
*/
import { AuditorService, LoggerService } from '@backstage/backend-plugin-api';
import type { MetricsService } from '@backstage/backend-plugin-api/alpha';
import { assertError, InputError, stringifyError } from '@backstage/errors';
import { ScmIntegrations } from '@backstage/integration';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
@@ -78,6 +79,7 @@ export type CreateWorkerOptions = {
additionalTemplateGlobals?: Record<string, TemplateGlobal>;
permissions?: PermissionEvaluator;
gracefulShutdown?: boolean;
metrics: MetricsService;
};
/**
@@ -123,6 +125,7 @@ export class TaskWorker {
additionalTemplateGlobals,
permissions,
gracefulShutdown,
metrics,
} = options;
const workflowRunner = new NunjucksWorkflowRunner({
@@ -135,6 +138,7 @@ export class TaskWorker {
additionalTemplateGlobals,
permissions,
config,
metrics,
});
return new TaskWorker({
@@ -58,7 +58,10 @@ import {
import { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters';
import { createRouter } from './router';
import { DatabaseTaskStore } from '../scaffolder/tasks/DatabaseTaskStore';
import { actionsRegistryServiceMock } from '@backstage/backend-test-utils/alpha';
import {
actionsRegistryServiceMock,
metricsServiceMock,
} from '@backstage/backend-test-utils/alpha';
import { ActionsService } from '@backstage/backend-plugin-api/alpha';
function createDatabase(): DatabaseService {
@@ -229,6 +232,7 @@ const createTestRouter = async (
createDebugLogAction(),
],
actionsRegistry: overrides.actionsRegistry ?? actionsRegistryServiceMock(),
metrics: metricsServiceMock.mock(),
});
router.use(mockErrorHandler());
@@ -131,7 +131,10 @@ import {
scaffolderTaskRules,
scaffolderTemplateRules,
} from './rules';
import { ActionsService } from '@backstage/backend-plugin-api/alpha';
import {
ActionsService,
MetricsService,
} from '@backstage/backend-plugin-api/alpha';
/**
* RouterOptions
@@ -165,6 +168,7 @@ export interface RouterOptions {
auditor?: AuditorService;
autocompleteHandlers?: Record<string, AutocompleteHandler>;
actionsRegistry: ActionsService;
metrics: MetricsService;
}
function isSupportedTemplate(entity: TemplateEntityV1beta3) {
@@ -256,6 +260,7 @@ export async function createRouter(
httpAuth,
auditor,
actionsRegistry,
metrics,
} = options;
const concurrentTasksLimit =
@@ -344,6 +349,7 @@ export async function createRouter(
concurrentTasksLimit,
permissions,
gracefulShutdown,
metrics,
...templateExtensions,
});
@@ -375,6 +381,7 @@ export async function createRouter(
workingDirectory,
permissions,
config,
metrics,
...templateExtensions,
});
-1
View File
@@ -6813,7 +6813,6 @@ __metadata:
"@backstage/plugin-scaffolder-node-test-utils": "workspace:^"
"@backstage/repo-tools": "workspace:^"
"@backstage/types": "workspace:^"
"@opentelemetry/api": "npm:^1.9.0"
"@types/express": "npm:^4.17.6"
"@types/fs-extra": "npm:^11.0.0"
"@types/luxon": "npm:^3.0.0"