Periskop logo

Backstage Periskop Plugin

Created by Periskop

Periskop is an open source service for collecting and browsing exceptions in microservice systems. It uses a pull based model. Clients group exceptions by type and expose them on HTTP. A server scrapes many instances and builds an aggregated view. It scales with fleets and stays language agnostic.

The Periskop Backstage plugin brings this view into your developer portal. It adds a card on each service page that lists recent exception groups, severity, and counts. Each entry links to details in your Periskop UI. It can target more than one Periskop instance to match zones or a federated setup.

Periskop was created at SoundCloud. Their team says “Periskop is an exception monitoring service that we built here at SoundCloud.” Read the post on the SoundCloud Backstage Blog at Periskop Exception Monitoring Service.

Use the plugin to triage incidents faster. Spot regressions after a deploy. Give owners a clear view of errors next to docs, runbooks, and on call info. Start from a Backstage entity, scan top exceptions, then jump to full context in Periskop when needed. This keeps context switching low for everyday work.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Install the frontend plugin

  1. Add the package to your app
Copy
yarn --cwd packages/app add @backstage-community/plugin-periskop
  1. Add the Periskop card to the entity page
Copy
// packages/app/src/components/catalog/EntityPage.tsx
import React from 'react';
import Grid from '@mui/material/Grid';
import { EntityLayout } from '@backstage/plugin-catalog-react';
import {
  EntityPeriskopErrorsCard,
  isPeriskopAvailable,
} from '@backstage-community/plugin-periskop';
import { EntitySwitch } from '@backstage/plugin-catalog-react';

const periskopContent = (
  <EntitySwitch>
    <EntitySwitch.Case if={isPeriskopAvailable}>
      <Grid container spacing={3} alignItems="stretch">
        <Grid item xs={12} sm={12} md={12}>
          <EntityPeriskopErrorsCard />
        </Grid>
      </Grid>
    </EntitySwitch.Case>
  </EntitySwitch>
);

const componentPage = (
  <EntityLayout>
    {/* other routes */}
    <EntityLayout.Route path="/periskop" title="Periskop">
      {periskopContent}
    </EntityLayout.Route>
  </EntityLayout>
);

export default componentPage;

Configure instances in app config

Add at least one Periskop API location. Add this to app config

Copy
# app-config.yaml
periskop:
  instances:
    - name: production
      url: https://periskop.example.com
    - name: staging
      url: https://periskop.staging.example.com

You can configure one or many instances. The plugin UI shows a dropdown to switch instances.

Annotate your catalog entities

Add the service name annotation to any entity that should show Periskop errors

Copy
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
  name: my-service
  annotations:
    periskop.io/service-name: my-service-name-in-periskop
spec:
  type: service
  owner: team-a
  lifecycle: production

Install the backend plugin using the new backend system

  1. Add the package to your backend
Copy
yarn --cwd packages/backend add @backstage-community/plugin-periskop-backend
  1. Register the backend feature
Copy
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

backend.add(import('@backstage-community/plugin-periskop-backend'));

// add your other backend features here

backend.start();

The plugin registers under the periskop plugin ID. The frontend discovers it at the periskop backend path.

Install the backend plugin using the old backend system

  1. Add the package to your backend
Copy
yarn --cwd packages/backend add @backstage-community/plugin-periskop-backend
  1. Create the plugin router
Copy
// packages/backend/src/plugins/periskop.ts
import { createRouter } from '@backstage-community/plugin-periskop-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';

export default async function createPlugin(
  env: PluginEnvironment,
): Promise<Router> {
  return await createRouter({
    logger: env.logger,
    config: env.config,
  });
}
  1. Mount the router
Copy
// packages/backend/src/index.ts
import periskop from './plugins/periskop';

// inside the main bootstrap function after creating apiRouter and env
apiRouter.use('/periskop', await periskop(env));

The frontend discovers the backend at the periskop path under api.

What the plugin exports and how you use it

  • EntityPeriskopErrorsCard shows the aggregated errors table in the entity page
  • isPeriskopAvailable helps hide the tab when the entity is not annotated

Example imports shown earlier

Copy
import {
  EntityPeriskopErrorsCard,
  isPeriskopAvailable,
} from '@backstage-community/plugin-periskop';

Changelog

This changelog is produced from commits made to the Periskop plugin since a year ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Documentation

  • Fix README links to point to the community plugins repository for Periskop plugin #3931 merged 5 months ago

Maintenance

  • Remove unused dev dependency canvas from Periskop plugin #3565 merged 6 months ago
  • Clean up knip config to reduce false positives for the workspace that includes Periskop #3018 merged 7 months ago
  • Remove use of @backstage/backend-common in Periskop backend #1959 merged 11 months ago

Set up Backstage in minutes with Roadie