# Prometheus

> [!NOTE]
> The Prometheus metrics have been marked as deprecated and will be removed at a later point. The recommendation is to use the OpenTelemetry metrics by following the [Setup OpenTelemetry](https://backstage.io/docs/tutorials/setup-opentelemetry) documentation

## Overview

This is a small tutorial that goes over how to setup your Backstage instance to output metrics in a format that can be pulled in by Prometheus.

## How to Setup Prometheus Metrics

1. First we need to add the needed dependencies to the `package.json` in the `\packages\backend`:

   ```diff
   // packages/backend/package.json
       "dependencies": {
   +   "express-prom-bundle": "^7.0.0",
   +   "prom-client": "^15.0.0",
   ```

2. Now we want to run `yarn install` from the root of the project to get those dependencies in place
3. Then we need to add a handler for the metrics by creating a file called `metrics.ts` in the `\packages\backend\src` folder
4. Next we add the following content to the `metrics.ts` file:

   ```ts
   // 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: {} },
     });
   }
   ```

5. Now we will extend the 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);
   ```

6. You now have everything setup, from the `\packages\backend` folder run `yarn start` this will start up the backend
7. Now in a browser load up `http://localhost:7007/metrics`, if everything went smoothly you should see metrics in your browser something like this:

   ![Prometheus Metrics Example Output](prometheus-metrics-output.png)

## Metrics

The following sections goes over the included and experimental metrics available once you have completed this tutorial

## Included

This tutorials uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) and the [`prom-client`](https://github.com/siimon/prom-client) to make this all work. They both come with some built in metrics:

- `express-prom-bundle` comes with 2 metrics:
  - `up`: this normally will be just 1
  - `http_request_duration_seconds`: http latency histogram/summary labeled with `status_code`, `method` and `path`
- `prom-client` comes with a collection of metrics around memory, CPU, processes, etc. You can see the supported metrics in the `prom-client's` [`lib/metrics`](https://github.com/siimon/prom-client/tree/master/lib/metrics) folder.

### Experimental

There are some custom metrics that have been added to Backstage will be output for you, these are currently deemed experimental and may be changed or removed in a future release. Here is a rough list, again subject to changes:

- `catalog_entities_count`: Total amount of entities in the catalog
- `catalog_registered_locations_count`: Total amount of registered locations in the catalog
- `catalog_relations_count`: Total amount of relations between entities
- `catalog_stitched_entities_count`: Amount of entities stitched
- `catalog_processed_entities_count`: Amount of entities processed
- `catalog_processing_duration_seconds`: Time spent executing the full processing flow
- `catalog_processors_duration_seconds`: Time spent executing catalog processors
- `catalog_processing_queue_delay_seconds`: The amount of delay between being scheduled for processing, and the start of actually being processed
- `scaffolder_task_count`: Tracks successful task runs.
- `scaffolder_task_duration`: a histogram which tracks the duration of a task run
- `scaffolder_step_count`: a count that tracks each step run
- `scaffolder_step_duration`: a histogram which tracks the duration of each step run
