See the Tech Insights Backstage plugin in action
Request a Roadie demoInstallation steps
Install the plugin backend packages Backstage backend app
cd packages/backend
yarn add @backstage/plugin-tech-insights-backend @backstage/plugin-tech-insights-node
Install the plugin frontend package in your Backstage app
cd packages/app
yarn add @backstage/plugin-tech-insights
Configure your Backstage backend to run the Tech Insights plugin
// packages/backend/src/plugins/techInsights.ts
import {
createRouter,
buildTechInsightsContext,
} from '@backstage/plugin-tech-insights-backend';
import { Router } from 'express';
import { PluginEnvironment } from '../types';
export default async function createPlugin(
env: PluginEnvironment,
): Promise<Router> {
const builder = buildTechInsightsContext({
logger: env.logger,
config: env.config,
database: env.database,
discovery: env.discovery,
factRetrievers: [], // Fact retrievers registrations you want tech insights to use, we'll add these in the next step
factCheckerFactory: myFactCheckerFactory // Fact checker, we'll add this in the next steps
});
return await createRouter({
...(await builder),
logger: env.logger,
config: env.config,
});
}
Create Fact Retrievers to fetch fact data for you
// packages/backend/src/plugins/techInsights.ts
import { FactRetriever } from '@backstage/plugin-tech-insights-node';
const myFactRetriever: FactRetriever = {
id: 'documentation-number-factretriever', // unique identifier of the fact retriever
version: '0.1.1', // SemVer version number of this fact retriever schema. This should be incremented if the implementation changes
entityFilter: [{ kind: 'component' }], // EntityFilter to be used in the future (creating checks, graphs etc.) to figure out which entities this fact retrieves data for.
schema: {
// Name/identifier of an individual fact that this retriever returns
examplenumberfact: {
type: 'integer', // Type of the fact
description: 'A fact of a number', // Description of the fact
},
},
handler: async ctx => {
// Handler function that retrieves the fact
const { discovery, config, logger } = ctx;
const catalogClient = new CatalogClient({
discoveryApi: discovery,
});
const entities = await catalogClient.getEntities({
filter: [{ kind: 'component' }],
});
/**
* snip: Do complex logic to retrieve facts from external system or calculate fact values
*/
// Respond with an array of entity/fact values
return entities.items.map(it => {
return {
// Entity information that this fact relates to
entity: {
namespace: it.metadata.namespace,
kind: it.kind,
name: it.metadata.name,
},
// All facts that this retriever returns
facts: {
examplenumberfact: 2, //
},
// (optional) timestamp to use as a Luxon DateTime object
};
});
},
};
const myFactRetrieverRegistration = createFactRetrieverRegistration({
cadence: '1 * 2 * * ', // On the first minute of the second day of the month
factRetriever: myFactRetriever,
});
Create Fact Checker checks to determine results of the facts.
// packages/backend/src/plugins/techInsights.ts
import { JsonRulesEngineFactCheckerFactory } from '@backstage/plugin-tech-insights-backend-module-jsonfc';
const myFactCheckerFactory = new JsonRulesEngineFactCheckerFactory({
logger: env.logger,
checks: [
{
id: 'exampleNumberCheck',
type: JSON_RULE_ENGINE_CHECK_TYPE,
name: 'Example Number Check',
description: 'Verifies that the example number is larger is equal to 3.',
factIds: ['documentation-number-factretriever'],
rule: {
conditions: {
all: [
{
fact: 'examplenumberfact',
operator: 'equal',
value: 3,
},
],
},
},
},
],
}),
Import the plugin.
// packages/backend/src/index.ts
import techInsights from './plugins/techInsights';
const techInsightsEnv = useHotMemoize(module, () => createEnv('tech_insights'));
apiRouter.use('/tech-insights', await techInsights(techInsightsEnv));
Set up the plugin frontend.
// packages/app/src/components/catalog/EntityPage.tsx
import { EntityTechInsightsScorecardContent } from '@backstage/plugin-tech-insights';
const serviceEntityPage = (
<EntityLayoutWrapper>
<EntityLayout.Route path="/" title="Overview">
{overviewContent}
</EntityLayout.Route>
<EntityLayout.Route path="/ci-cd" title="CI/CD">
{cicdContent}
</EntityLayout.Route>
...
<EntityLayout.Route path="/tech-insights" title="Scorecards">
<EntityTechInsightsScorecardContent
title="Customized title for the scorecard"
description="Small description about scorecards"
/>
</EntityLayout.Route>
...
</EntityLayoutWrapper>
);
Found a mistake? Update these instructions.
Things to know
How do I fetch facts for my own data?
Tech Insights uses Fact Retrievers to retrieve data from external sources. Any external service or API can be used as the service providing fact data that is tied to your Backstage entities.
How do I create non-boolean checks?
The default implementation of FactChecker uses JSON rules engine. To create checks using other types of logic, you can implement the FactCheckerFactory
interface and provide your own implementation.
How do I retrieve and construct graphs from the facts I have in the database?
Tech Insights backend exposes an API endpoint that can be queried for fact data based on datetime range and entity reference. You can construct an XHR call like the following to query individual values of graphable data:
curl <backstage-backend>/api/tech-insights/facts/range?entity=<entity-kind>:<entity-namespace>/<entity-name>?ids[]=documentation-number-factretriever&startDatetime=2021-09-12T06:46:30&endDatetime=2021-10-21T06:46:30
How do I make sure my database doesn’t get overwhelmed with fact data?
You can defined a lifecycle configuration value to the factRetrieverRegistration
you create. The possible values for this are either a number of items to keep or a duration for how long the item should be kept in the database before it is cleaned up. Example values are:
const maxItems = { maxItems: 7 }; // Deletes all but 7 latest facts for each id/entity pair
const ttl = { timeToLive: 1209600000 }; // (2 weeks) Deletes items older than 2 weeks
const ttlWithAHumanReadableValue = { timeToLive: { weeks: 2 } }; // Deletes items older than 2 weeks
More information
Prefer a no-code Backstage setup?
Request a Roadie demoBecome a Backstage expert
To get the latest news, deep dives into Backstage features, and a roundup of recent open-source action, sign up for Roadie's Backstage Weekly. See recent editions.