Jaeger Tracing logo

Backstage Jaeger Tracing Plugin

Created by Deepankumar

Jaeger is an open source system for distributed tracing. It helps you follow a request across services, measure latency, and spot failures. If you run microservices, Jaeger gives you a clear view of how calls flow through your stack.

The Jaeger Tracing Backstage plugin brings that view into your developer portal. It adds a Traces page to each service so engineers can search recent traces, open a trace, and scan spans in a table. You can filter by time range or operation to zero in on the path you care about. The trace detail shows timing, parent child relationships, and durations. This keeps people in one place during incidents and cuts the time from finding a problem to understanding it.

Typical use cases include on call triage, verifying a deploy, and exploring how a new dependency affects latency. It also helps new teammates learn how a service talks to its neighbors without leaving Backstage.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the frontend package

  1. From your Backstage root
    Copy
    yarn add --cwd packages/app @backstage-community/plugin-jaeger

Configure the proxy endpoint

  1. Add a proxy entry in app config
    Copy
    # app-config.yaml
    proxy:
      endpoints:
        '/jaeger-api':
          target: ${JAEGAR_API_URL}
          pathRewrite:
            '^/api/proxy/jaeger-api': ''
  2. Set the environment variable when you run Backstage
    Copy
    export JAEGAR_API_URL="https://your-jaeger-query-url"

Enable the proxy in the legacy backend

If your backend already includes the proxy plugin you can skip this section.

  1. Add the backend dependency
    Copy
    yarn add --cwd packages/backend @backstage/plugin-proxy-backend
  2. Create the proxy router
    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,
        cache: env.cache,
        urlReader: env.reader,
      });
    }
  3. Mount the proxy under the api router
    Copy
    // packages/backend/src/index.ts
    import proxy from './plugins/proxy';
    
    // inside the main bootstrap function where apiRouter is created
    // apiRouter is mounted at /api elsewhere in this file
    const proxyEnv = useHotMemoize(module, () => createEnv('proxy'));
    apiRouter.use('/proxy', await proxy(proxyEnv));

Enable the proxy in the new backend system

If your backend already adds the proxy plugin you can skip this section.

  1. Add the backend dependency
    Copy
    yarn add --cwd packages/backend @backstage/plugin-proxy-backend
  2. Add the plugin in the backend entry point
    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();

Add the Jaeger card to the service page

  1. Import the component in your entity page
    Copy
    // packages/app/src/components/catalog/EntityPage.tsx
    import React from 'react';
    import { EntityLayout } from '@backstage/plugin-catalog';
    import { JaegerCard } from '@backstage-community/plugin-jaeger';
    
    const serviceEntityPage = (
      <EntityLayout>
        <EntityLayout.Route path="/" title="Overview">
          {overviewContent}
        </EntityLayout.Route>
    
        <EntityLayout.Route path="/ci-cd" title="CI/CD">
          {cicdContent}
        </EntityLayout.Route>
    
        <EntityLayout.Route path="/jaeger" title="Traces">
          <JaegerCard />
        </EntityLayout.Route>
      </EntityLayout>
    );
    
    export default serviceEntityPage;
  2. Optional hide the tab when the entity lacks annotations
    Copy
    // packages/app/src/components/catalog/EntityPage.tsx
    import {
      JaegerCard,
      isJaegerAvailable,
    } from '@backstage-community/plugin-jaeger';
    
    const serviceEntityPage = (
      <EntityLayout>
        {/* other routes */}
        <EntityLayout.Route if={isJaegerAvailable} path="/jaeger" title="Traces">
          <JaegerCard />
        </EntityLayout.Route>
      </EntityLayout>
    );

Annotate your entities

Add annotations to each service that you want to show traces for.

Copy
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: petstore
  annotations:
    jaegertracing.io/service: petstore
    jaegertracing.io/lookback: 30m
    jaegertracing.io/limit: 20
    jaegertracing.io/operation: /
spec:
  type: service
  lifecycle: experimental
  owner: guests

What this plugin exports

  1. Import these in your app where needed
    Copy
    // component for the service page
    import { JaegerCard } from '@backstage-community/plugin-jaeger';
    
    // helper to conditionally show the route
    import { isJaegerAvailable } from '@backstage-community/plugin-jaeger';
    
    // the plugin object for advanced use
    import { jaegerPlugin } from '@backstage-community/plugin-jaeger';

Changelog

The Jaeger Tracing plugin has not seen any significant changes since 6 months ago.

Set up Backstage in minutes with Roadie