Skip to content

Getting Started

This walks through one dashboard with a Prometheus datasource, a variable and two panels, then loads it into Grafana.

To start from a scaffold instead, chant init --lexicon grafana <dir> writes a datasource and a job overview dashboard. --template picks one of three others:

TemplateWhat it writes
redA RedDashboard over the collector’s span metrics, counting server and consumer spans, on an ExternalDatasource, in a Folder with a pinned uid
k8s-podsCPU, memory, restarts and pod phase per namespace, delivered as ConfigMaps for the Grafana sidecar with GrafanaConfigMaps from @intentius/chant-lexicon-grafana/k8s. Builds with the k8s lexicon
sloAn Slo’s recording rules, its SloDashboard, and its burn-rate alerts as SloAlertRules. Builds with the prometheus lexicon

Each one builds clean and passes the GRAF checks.

Terminal window
npm install --save-dev @intentius/chant @intentius/chant-lexicon-grafana
chant.config.ts
import type { ChantConfig } from "@intentius/chant";
export default { lexicons: ["grafana"] } satisfies ChantConfig;

A datasource is declared once. Panels and queries hold the entity, so there is no uid string to get wrong.

src/datasources.ts
import { Datasource } from "@intentius/chant-lexicon-grafana";
const prometheus = new Datasource({ name: "Prometheus", type: "prometheus", url: "http://prometheus:9090", isDefault: true });
export { prometheus };

Its uid defaults to the name as a uid, prometheus.

src/queries.ts
import { PromQuery, QueryVariable } from "@intentius/chant-lexicon-grafana";
import { prometheus } from "./datasources";
const job = new QueryVariable({ name: "job", datasource: prometheus, query: "label_values(up, job)" });
const up = new PromQuery({ expr: 'sum(up{job="$job"})', instant: true });
const scrapeDuration = new PromQuery({ expr: 'scrape_duration_seconds{job="$job"}', legendFormat: "{{instance}}" });
export { job, up, scrapeDuration };

PromQuery fields come from Grafana’s Prometheus query schema. Its datasource accepts only a prometheus datasource.

src/dashboard.ts
import { Dashboard, StatPanel, TimeSeriesPanel } from "@intentius/chant-lexicon-grafana";
import { prometheus } from "./datasources";
import { job, up, scrapeDuration } from "./queries";
const seconds = { defaults: { unit: "s" } };
const targetsUp = new StatPanel({ title: "Targets up", datasource: prometheus, targets: [up] });
const scrapes = new TimeSeriesPanel({ title: "Scrape duration", datasource: prometheus, targets: [scrapeDuration], fieldConfig: seconds });
const scrapeHealth = new Dashboard({ title: "Scrape health", variables: [job], panels: [targetsUp, scrapes] });
export { targetsUp, scrapes, scrapeHealth };

Neither panel has a gridPos, so the dashboard places them: the stat panel at its default 6×4, the time series next to it at 12×8. The dashboard’s uid defaults to its export name, scrape-health.

Terminal window
npx chant build src --lexicon grafana -o dist/grafana/index.json
dist/grafana/
├── index.json what was built
├── dashboards/scrape-health.json the dashboard, as Grafana imports it
└── provisioning/
├── dashboards/chant.yaml a provider for the dashboards directory
└── datasources/chant.yaml the Prometheus datasource

chant build also runs the GRAF1xx checks on the output. A query pointing at a datasource nobody declared, a $variable the dashboard doesn’t have, overlapping panels, a value Grafana’s dashboard schema doesn’t allow, PromQL with a missing bracket, or a provider that ignores a dashboard’s folder fails here instead of in Grafana. A key the schema doesn’t know is a warning, and so is a unit Grafana doesn’t know, such as "byte" for "bytes".

Terminal window
docker run --rm -p 3000:3000 \
-v "$PWD/dist/grafana/provisioning:/etc/grafana/provisioning:ro" \
-v "$PWD/dist/grafana/dashboards:/var/lib/grafana/dashboards:ro" \
grafana/grafana:12.4.11

Open http://localhost:3000/d/scrape-health. To import by hand instead, paste dashboards/scrape-health.json into Dashboards → New → Import.

Next: Dashboards and panels for layout, rows and panel options, and Provisioning for Kubernetes.