Grafana logo

Backstage Grafana Plugin

Created by K-Phoen

Grafana is an open source tool for dashboards and alerts. Teams use it to explore metrics, logs, and traces from many data sources.

The Grafana plugin brings that context into Backstage. It shows dashboards related to a service. It lists recent alerts for that service. You can embed an overview dashboard on the entity page. The plugin maps dashboards and alerts to entities through simple annotations. You can match by tags or alert labels. The result is less tab switching and faster triage.

Common use cases are clear. Give service owners a quick health view during standups. Help on call engineers jump to the right panels. Share a standard overview across teams. Keep context while you debug and review incidents.

Grafana Labs also maintains a Backstage integration for Grafana Cloud Service Center. It reads your Backstage catalog to link services with incident and SLO data. As they describe it, “Users of Backstage can continuously import their Backstage catalog to populate Service Center data in Grafana Cloud.”

If you run a self hosted Backstage, this plugin puts Grafana where your engineers already work. It keeps the catalog and your operational reality in sync.

Installation Instructions

These instructions apply to self-hosted Backstage only. To use this plugin on Roadie, visit the docs.

Install the frontend package

Copy
cd packages/app
yarn add @k-phoen/backstage-plugin-grafana

Expose the plugin in your frontend

Copy
// packages/app/src/plugins.ts

export { grafanaPlugin } from '@k-phoen/backstage-plugin-grafana';

Configure the proxy and plugin settings

Add a proxy route and Grafana settings in app-config.yaml. Use an API token with Viewer access.

Copy
# app-config.yaml
proxy:
  '/grafana/api':
    target: https://grafana.host/
    headers:
      Authorization: Bearer ${GRAFANA_TOKEN}

grafana:
  domain: https://monitoring.company.com
  unifiedAlerting: false

Set GRAFANA_TOKEN in your runtime environment.

Enable the backend proxy on the old backend system

Install the backend proxy plugin

Copy
yarn workspace backend add @backstage/plugin-proxy-backend

Create the proxy plugin file

Copy
// packages/backend/src/plugins/proxy.ts

import { createRouter } from '@backstage/plugin-proxy-backend';
import { PluginEnvironment } from '../types';

export default async function createPlugin(env: PluginEnvironment) {
  return await createRouter({
    logger: env.logger,
    config: env.config,
    discovery: env.discovery,
    tokenManager: env.tokenManager,
    httpAuth: env.httpAuth,
  });
}

Wire it in the backend

Copy
// packages/backend/src/index.ts

import proxy from './plugins/proxy';
// other imports...

async function main() {
  // existing setup...
  const apiRouter = Router();

  const env = useHotMemoize(module, () => createEnv('proxy'));
  apiRouter.use('/proxy', await proxy(env));

  app.use('/api', apiRouter);
  // existing startup...
}

main().catch(err => {
  process.exit(1);
});

Enable the backend proxy on the new backend system

Install the backend proxy plugin

Copy
yarn workspace backend add @backstage/plugin-proxy-backend

Register the proxy plugin

Copy
// packages/backend/src/index.ts

import { createBackend } from '@backstage/backend-defaults';
import { proxyPlugin } from '@backstage/plugin-proxy-backend';

const backend = createBackend();

backend.add(proxyPlugin());

backend.start();

Show dashboards on the entity page

Import the dashboards card and add it to the entity page

Copy
// packages/app/src/components/catalog/EntityPage.tsx

import React from 'react';
import Grid from '@material-ui/core/Grid';
import {
  EntityAboutCard,
  EntityLinksCard,
  EntityHasSubcomponentsCard,
} from '@backstage/plugin-catalog';
import {
  EntityGrafanaDashboardsCard,
} from '@k-phoen/backstage-plugin-grafana';

export const overviewContent = (
  <Grid container spacing={3} alignItems="stretch">
    <Grid item md={6}>
      <EntityAboutCard variant="gridItem" />
    </Grid>

    <Grid item md={6}>
      <EntityGrafanaDashboardsCard />
    </Grid>

    <Grid item md={4} xs={12}>
      <EntityLinksCard />
    </Grid>
    <Grid item md={8} xs={12}>
      <EntityHasSubcomponentsCard variant="gridItem" />
    </Grid>
  </Grid>
);

Add a selector to your entity to link dashboards

Copy
# catalog-info.yaml
metadata:
  annotations:
    grafana/dashboard-selector: "(tags @> 'my-service' || tags @> 'my-service-slo') && tags @> 'generated'"

You can also use a short selector

Copy
metadata:
  annotations:
    grafana/dashboard-selector: my-service

Supported variables

  • title
  • tags
  • url
  • folderTitle
  • folderUrl

Supported binary operators

  • ||
  • &&
  • ==
  • !=
  • @>

Supported unary operators

  • !

Show alerts on the entity page

Import the alerts card and add it to the entity page

Copy
// packages/app/src/components/catalog/EntityPage.tsx

import React from 'react';
import Grid from '@material-ui/core/Grid';
import {
  EntityAboutCard,
  EntityLinksCard,
  EntityHasSubcomponentsCard,
} from '@backstage/plugin-catalog';
import {
  EntityGrafanaAlertsCard,
} from '@k-phoen/backstage-plugin-grafana';

export const overviewContent = (
  <Grid container spacing={3} alignItems="stretch">
    <Grid item md={6}>
      <EntityAboutCard variant="gridItem" />
    </Grid>

    <Grid item md={6}>
      <EntityGrafanaAlertsCard />
    </Grid>

    <Grid item md={4} xs={12}>
      <EntityLinksCard />
    </Grid>
    <Grid item md={8} xs={12}>
      <EntityHasSubcomponentsCard variant="gridItem" />
    </Grid>
  </Grid>
);

If Grafana unified alerting is enabled

Copy
# catalog-info.yaml
metadata:
  annotations:
    grafana/alert-label-selector: "service=awesome-service"

If Grafana legacy alerting is used

Copy
# catalog-info.yaml
metadata:
  annotations:
    grafana/tag-selector: "my-tag"

Embed an overview dashboard on the entity page

Import the viewer and add it to the entity page

Copy
// packages/app/src/components/catalog/EntityPage.tsx

import React from 'react';
import Grid from '@material-ui/core/Grid';
import {
  EntityAboutCard,
  EntityLinksCard,
  EntityHasSubcomponentsCard,
} from '@backstage/plugin-catalog';
import {
  EntityOverviewDashboardViewer,
} from '@k-phoen/backstage-plugin-grafana';

export const overviewContent = (
  <Grid container spacing={3} alignItems="stretch">
    <Grid item md={6}>
      <EntityAboutCard variant="gridItem" />
    </Grid>

    <Grid item md={6}>
      <EntityOverviewDashboardViewer />
    </Grid>

    <Grid item md={4} xs={12}>
      <EntityLinksCard />
    </Grid>
    <Grid item md={8} xs={12}>
      <EntityHasSubcomponentsCard variant="gridItem" />
    </Grid>
  </Grid>
);

Add the dashboard URL to the entity

Copy
# catalog-info.yaml
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: my-entity
  annotations:
    grafana/overview-dashboard: 'http://grafana/d/qSfS51a4z/some-dashboard?orgId=1&kiosk'
spec: {}

Grafana must allow embedding. Update grafana.ini if needed.

Copy
# grafana.ini
[security]
allow_embedding = true

[session]
cookie_samesite = none

Only change these settings if you understand the impact.

Use the generic dashboard viewer

You can embed any dashboard with a fixed URL. Add this where you want it to render.

Copy
// packages/app/src/components/somewhere/GrafanaDashboardSection.tsx

import React from 'react';
import { DashboardViewer } from '@k-phoen/backstage-plugin-grafana';

export const GrafanaDashboardSection = () => (
  <DashboardViewer
    height={800}
    url="https://monitoring.company.com/d/abc123/my-dashboard?orgId=1&kiosk"
  />
);

Set up Backstage in minutes with Roadie