Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic prometheus #1127

Merged
merged 6 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/curvy-stingrays-exist.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@roadiehq/backstage-plugin-prometheus': minor
---

Prometheus service name will now be sent to the backstage backend proxy as a request header to support advanced proxying configs
59 changes: 54 additions & 5 deletions plugins/frontend/backstage-plugin-prometheus/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,6 @@ Backstage plugin exposing graphs and alerts from Prometheus

![Prometheus Entity Content Page Screenshot](./docs/prom_entity_content.png)

## Features

- List Pull Requests for your repository, with filtering and search.
- Show basic statistics widget about pull requests for your repository.

### The plugin provides an entity content page and two additional widgets:

1. Alert table widget
Expand Down Expand Up @@ -191,6 +186,60 @@ prometheus:
proxyPath: /prometheusTeamB/api
```

## Advanced Dynamic Prometheus Proxying

If you have a very large amount of prometheus servers, the above statically configured "Multiple Prometheus instances" proxy config may become verbose and difficult to maintain. You can take full control over Backstage's backend proxying behavior for prometheus by writing your own proxy middleware.

All prometheus requests from the frontend will send the entities `prometheus.io/service-name` annotation in the `x-prometheus-service-name` request header.

Step 1: Update app-config to use a special path if it can't find the `prometheus.io/service-name` config in the `prometheus.instances` config array
**app-config.yaml**

```yaml
prometheus:
proxyPath: '/dynamic-prometheus'
```

Step 2: Hijack this path by writing your own proxy middleware extension.
**packages/backend/src/plugins/proxy.ts**

```diff
import { createRouter } from '@backstage/plugin-proxy-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
+ import { createProxyMiddleware } from 'http-proxy-middleware';

export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const proxyRouter = await createRouter({
logger: env.logger,
config: env.config,
discovery: env.discovery,
});
+ const externalUrl = await env.discovery.getExternalBaseUrl('proxy');
+ const { pathname: pathPrefix } = new URL(externalUrl);
+ proxyRouter.use(
+ '/dynamic-prometheus',
+ createProxyMiddleware({
+ logProvider: () => env.logger,
+ logLevel: 'debug',
+ changeOrigin: true,
+ pathRewrite: {
+ [`^${pathPrefix}/dynamic-prometheus/?`]: '/',
+ },
+ // Some code that does something with the x-prometheus-service-name header.
+ // Here you can just do URL manipulation, or even make requests out to other services
+ // or caches to pull down lookup info.
+ router: async (req) => {
+ const prometheusServiceName = req.headers['x-prometheus-service-name'];
+ return `https://${prometheusServiceName}.company.com`;
+ },
+ }),
+ );
+ return proxyRouter;
```

## Using callback with `EntityPrometheusAlertCard`

You can add callbacks that will be executed when the user clicks on a row in the table of the `EntityPrometheusAlertCard` component. This callback is optional, and the rows become clickable only when the callback is supplied. The callback function is also provided with data of type JSON. It contains the information from the row of the table.
Expand Down
12 changes: 11 additions & 1 deletion plugins/frontend/backstage-plugin-prometheus/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { DateTime, Duration } from 'luxon';

const DEFAULT_PROXY_PATH = '/prometheus/api';
const SERVICE_NAME_HEADER = 'x-prometheus-service-name';

export const prometheusApiRef = createApiRef<PrometheusApi>({
id: 'plugin.prometheus.service',
Expand Down Expand Up @@ -87,6 +88,11 @@ export class PrometheusApi {
const start = DateTime.now().minus(Duration.fromObject(range)).toSeconds();
const response = await fetch(
`${apiUrl}/query_range?query=${query}&start=${start}&end=${end}&step=${step}`,
{
headers: {
[SERVICE_NAME_HEADER]: serviceName || '',
},
},
);
if (!response.ok) {
throw new Error(
Expand All @@ -98,7 +104,11 @@ export class PrometheusApi {

async getAlerts({ serviceName }: { serviceName?: string }) {
const apiUrl = await this.getApiUrl({ serviceName });
const response = await fetch(`${apiUrl}/rules?type=alert`);
const response = await fetch(`${apiUrl}/rules?type=alert`, {
headers: {
[SERVICE_NAME_HEADER]: serviceName || '',
},
});

if (!response.ok) {
throw new Error(
Expand Down
Loading