From 12bbd748c58e1f783d30f2b1dd6f2c30b63e6dca Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Fri, 4 Dec 2020 17:00:39 +0100 Subject: [PATCH] Remove prometheus depenedency from backend-common --- .../rare-lemons-hug.md | 66 ++++++++++++++----- packages/backend-common/package.json | 2 - .../src/service/lib/ServiceBuilderImpl.ts | 8 --- .../src/service/lib/metrics.test.ts | 37 ----------- yarn.lock | 34 +--------- 5 files changed, 49 insertions(+), 98 deletions(-) rename packages/backend-common/src/service/lib/metrics.ts => .changeset/rare-lemons-hug.md (50%) delete mode 100644 packages/backend-common/src/service/lib/metrics.test.ts diff --git a/packages/backend-common/src/service/lib/metrics.ts b/.changeset/rare-lemons-hug.md similarity index 50% rename from packages/backend-common/src/service/lib/metrics.ts rename to .changeset/rare-lemons-hug.md index 37d441f53c..22933bf1c4 100644 --- a/packages/backend-common/src/service/lib/metrics.ts +++ b/.changeset/rare-lemons-hug.md @@ -1,21 +1,34 @@ -/* - * 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 prom from 'prom-client'; -import promBundle from 'express-prom-bundle'; +--- +'@backstage/backend-common': minor +--- + +Removes the Prometheus integration from `backend-common`. + +Rational behind this change is to keep the metrics integration of Backstage +generic. Instead of directly relying on Prometheus, Backstage will expose +metrics in a generic way. Integrators can then export the metrics in their +desired format. For example using Prometheus. + +To keep the existing behavior, you need to integrate Prometheus in your +backend: + +First, add a dependency on `express-prom-bundle` and `prom-client` to your backend. + +```diff +// packages/backend/package.json + "dependencies": { ++ "express-prom-bundle": "^6.1.0", ++ "prom-client": "^12.0.0", +``` + +Then, add a handler for metrics and a simple instrumentation for the endpoints. + +```typescript +// packages/backend/src/metrics.ts +import { useHotCleanup } from '@backstage/backend-common'; import { RequestHandler } from 'express'; +import promBundle from 'express-prom-bundle'; +import prom from 'prom-client'; import * as url from 'url'; const rootRegEx = new RegExp('^/([^/]*)/.*'); @@ -38,7 +51,7 @@ export function normalizePath(req: any): string { */ export function metricsHandler(): RequestHandler { // We can only initialize the metrics once and have to clean them up between hot reloads - prom.register.clear(); + useHotCleanup(module, () => prom.register.clear()); return promBundle({ includeMethod: true, @@ -51,3 +64,20 @@ export function metricsHandler(): RequestHandler { promClient: { collectDefaultMetrics: {} }, }); } +``` + +Last, extend your router configuration with the `metricsHandler`: + +```diff ++import { metricsHandler } from './metrics'; + +... + + const service = createServiceBuilder(module) + .loadConfig(config) + .addRouter('', await healthcheck(healthcheckEnv)) ++ .addRouter('', metricsHandler()) + .addRouter('/api', apiRouter); +``` + +Your Prometheus metrics will be available at the `/metrics` endpoint. diff --git a/packages/backend-common/package.json b/packages/backend-common/package.json index 04e189abca..13b827762c 100644 --- a/packages/backend-common/package.json +++ b/packages/backend-common/package.json @@ -41,7 +41,6 @@ "cors": "^2.8.5", "cross-fetch": "^3.0.6", "express": "^4.17.1", - "express-prom-bundle": "^6.1.0", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.1", "git-url-parse": "^11.4.0", @@ -51,7 +50,6 @@ "logform": "^2.1.1", "minimist": "^1.2.5", "morgan": "^1.10.0", - "prom-client": "^12.0.0", "selfsigned": "^1.10.7", "stoppable": "^1.1.0", "tar": "^6.0.5", diff --git a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts index b47f4ef7e5..778e25f71c 100644 --- a/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts +++ b/packages/backend-common/src/service/lib/ServiceBuilderImpl.ts @@ -39,7 +39,6 @@ import { readHttpsSettings, } from './config'; import { createHttpServer, createHttpsServer } from './hostFactory'; -import { metricsHandler } from './metrics'; export const DEFAULT_PORT = 7000; // '' is express default, which listens to all interfaces @@ -66,7 +65,6 @@ export class ServiceBuilderImpl implements ServiceBuilder { private corsOptions: cors.CorsOptions | undefined; private cspOptions: Record | undefined; private httpsSettings: HttpsSettings | undefined; - private enableMetrics: boolean = true; private routers: [string, Router][]; // Reference to the module where builder is created - needed for hot module // reloading @@ -109,9 +107,6 @@ export class ServiceBuilderImpl implements ServiceBuilder { this.httpsSettings = httpsSettings; } - // For now, configuration of metrics is a simple boolean and active by default - this.enableMetrics = backendConfig.getOptionalBoolean('metrics') !== false; - return this; } @@ -166,9 +161,6 @@ export class ServiceBuilderImpl implements ServiceBuilder { app.use(cors(corsOptions)); } app.use(compression()); - if (this.enableMetrics) { - app.use(metricsHandler()); - } app.use(requestLoggingHandler()); for (const [root, route] of this.routers) { app.use(root, route); diff --git a/packages/backend-common/src/service/lib/metrics.test.ts b/packages/backend-common/src/service/lib/metrics.test.ts deleted file mode 100644 index 9126423b7e..0000000000 --- a/packages/backend-common/src/service/lib/metrics.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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/yarn.lock b/yarn.lock index 44024b5952..71eccec1a8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7922,11 +7922,6 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bintrees@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/bintrees/-/bintrees-1.0.1.tgz#0e655c9b9c2435eaab68bf4027226d2b55a34524" - integrity sha1-DmVcm5wkNeqraL9AJyJtK1WjRSQ= - bl@^1.0.0: version "1.2.2" resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -11724,14 +11719,6 @@ expect@^26.5.3: jest-message-util "^26.5.2" jest-regex-util "^26.0.0" -express-prom-bundle@^6.1.0: - version "6.1.0" - resolved "https://registry.npmjs.org/express-prom-bundle/-/express-prom-bundle-6.1.0.tgz#8fd72e5bedbbd686b8e7c49e0aecbc1b14b28743" - integrity sha512-krlvp5r6sgJ1IwL6M6/coMrNbAlwtpk+uyivfeyRMCupTK4HzIEQHH0gwrNhLiKyPmSbtZcSmtO6s+PRumRp5g== - dependencies: - on-finished "^2.3.0" - url-value-parser "^2.0.0" - express-promise-router@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/express-promise-router/-/express-promise-router-3.0.3.tgz#5e6d22a5a3f013d71833172fe8d7ab780c3f6b70" @@ -17917,7 +17904,7 @@ oidc-token-hash@^5.0.0: resolved "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.0.tgz#acdfb1f4310f58e64d5d74a4e8671a426986e888" integrity sha512-8Yr4CZSv+Tn8ZkN3iN2i2w2G92mUKClp4z7EGUfdsERiYSbj7P4i/NHm72ft+aUdsiFx9UdIPSTwbyzQ6C4URg== -on-finished@^2.3.0, on-finished@~2.3.0: +on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= @@ -19514,13 +19501,6 @@ progress@^2.0.0: resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@^12.0.0: - version "12.0.0" - resolved "https://registry.npmjs.org/prom-client/-/prom-client-12.0.0.tgz#9689379b19bd3f6ab88a9866124db9da3d76c6ed" - integrity sha512-JbzzHnw0VDwCvoqf8y1WDtq4wSBAbthMB1pcVI/0lzdqHGJI3KBJDXle70XK+c7Iv93Gihqo0a5LlOn+g8+DrQ== - dependencies: - tdigest "^0.1.1" - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -22950,13 +22930,6 @@ tarn@^3.0.1: resolved "https://registry.npmjs.org/tarn/-/tarn-3.0.1.tgz#ebac2c6dbc6977d34d4526e0a7814200386a8aec" integrity sha512-6usSlV9KyHsspvwu2duKH+FMUhqJnAh6J5J/4MITl8s94iSUQTLkJggdiewKv4RyARQccnigV48Z+khiuVZDJw== -tdigest@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/tdigest/-/tdigest-0.1.1.tgz#2e3cb2c39ea449e55d1e6cd91117accca4588021" - integrity sha1-Ljyyw56kSeVdHmzZEReszKRYgCE= - dependencies: - bintrees "1.0.1" - telejson@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/telejson/-/telejson-5.0.2.tgz#ed1e64be250cc1c757a53c19e1740b49832b3d51" @@ -23961,11 +23934,6 @@ url-parse@^1.4.3, url-parse@^1.4.7: querystringify "^2.1.1" requires-port "^1.0.0" -url-value-parser@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/url-value-parser/-/url-value-parser-2.0.1.tgz#c8179a095ab9ec1f5aa17ca36af5af396b4e95ed" - integrity sha512-bexECeREBIueboLGM3Y1WaAzQkIn+Tca/Xjmjmfd0S/hFHSCEoFkNh0/D0l9G4K74MkEP/lLFRlYnxX3d68Qgw== - url@^0.11.0, url@~0.11.0: version "0.11.0" resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"