diff --git a/.changeset/weak-rice-beam.md b/.changeset/weak-rice-beam.md new file mode 100644 index 0000000000..c507e350a9 --- /dev/null +++ b/.changeset/weak-rice-beam.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Capture plugin name under the /api/ prefix for http metrics diff --git a/packages/backend-common/src/service/lib/metrics.test.ts b/packages/backend-common/src/service/lib/metrics.test.ts new file mode 100644 index 0000000000..9126423b7e --- /dev/null +++ b/packages/backend-common/src/service/lib/metrics.test.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { normalizePath } from './metrics'; + +describe('normalizePath', () => { + it('should normalize /path to /path', async () => { + const path = normalizePath({ url: 'http://server/path' }); + + expect(path).toBe('/path'); + }); + + it('should normalize /path/test to /path', async () => { + const path = normalizePath({ url: 'http://server/path/test' }); + + expect(path).toBe('/path'); + }); + + it('should normalize /api/plugin-name/test to /api/plugin-name', async () => { + const path = normalizePath({ url: 'http://server/api/plugin-name/test' }); + + expect(path).toBe('/api/plugin-name'); + }); +}); diff --git a/packages/backend-common/src/service/lib/metrics.ts b/packages/backend-common/src/service/lib/metrics.ts index d7b544765b..37d441f53c 100644 --- a/packages/backend-common/src/service/lib/metrics.ts +++ b/packages/backend-common/src/service/lib/metrics.ts @@ -16,6 +16,22 @@ import prom from 'prom-client'; import promBundle from 'express-prom-bundle'; import { RequestHandler } from 'express'; +import * as url from 'url'; + +const rootRegEx = new RegExp('^/([^/]*)/.*'); +const apiRegEx = new RegExp('^/api/([^/]*)/.*'); + +export function normalizePath(req: any): string { + const path = url.parse(req.originalUrl || req.url).pathname || '/'; + + // Capture /api/ and the plugin name + if (apiRegEx.test(path)) { + return path.replace(apiRegEx, '/api/$1'); + } + + // Only the first path segment at root level + return path.replace(rootRegEx, '/$1'); +} /** * Adds a /metrics endpoint, register default runtime metrics and instrument the router. @@ -31,7 +47,7 @@ export function metricsHandler(): RequestHandler { // cardinality (e.g. path params). Instead we would have to template them. However, this // is difficult, as every backend plugin might use different routes. Instead we only take // the first directory of the path, to have at least an idea how each plugin performs: - normalizePath: [['^/([^/]*)/.*', '/$1']], + normalizePath, promClient: { collectDefaultMetrics: {} }, }); }