Skip to content

Commit

Permalink
⚡ - Otel servicegraph (#1506)
Browse files Browse the repository at this point in the history
Co-authored-by: Diego Luisi <[email protected]>
  • Loading branch information
diegoluisi and Diego Luisi authored May 26, 2024
1 parent d024b13 commit 3ec78a2
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
6 changes: 4 additions & 2 deletions app/packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@
"express-promise-router": "^4.1.0",
"node-gyp": "^9.0.0",
"pg": "^8.11.3",
"winston": "^3.2.1"
"winston": "^3.2.1",
"express-prom-bundle": "^7.0.0",
"prom-client": "^15.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.25.0",
Expand All @@ -60,4 +62,4 @@
"files": [
"dist"
]
}
}
4 changes: 3 additions & 1 deletion app/packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import { ServerPermissionClient } from '@backstage/plugin-permission-node';
import { DefaultIdentityClient } from '@backstage/plugin-auth-node';
import kubernetes from './plugins/kubernetes';
import todo from './plugins/todo';
import { metricsHandler } from './metrics';

function makeCreateEnv(config: Config) {
const root = getRootLogger();
Expand Down Expand Up @@ -110,7 +111,8 @@ async function main() {

const service = createServiceBuilder(module)
.loadConfig(config)
.addRouter('', await healthcheck(healthcheckEnv))
.addRouter('', await healthcheck(healthcheckEnv))
.addRouter('', metricsHandler())
.addRouter('/api', apiRouter)
.addRouter('', await app(appEnv));

Expand Down
40 changes: 40 additions & 0 deletions app/packages/backend/src/metrics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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('^/([^/]*)/.*');
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.
*/
export function metricsHandler(): RequestHandler {
// We can only initialize the metrics once and have to clean them up between hot reloads
useHotCleanup(module, () => prom.register.clear());

return promBundle({
includeMethod: true,
includePath: true,
// Using includePath alone is problematic, as it will include path labels with high
// 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,
promClient: { collectDefaultMetrics: {} },
});
}

0 comments on commit 3ec78a2

Please sign in to comment.