Dashboard Exists + Grafana Collector
Enforce Dashboard Exists using data collected by Grafana Collector. Automatically check operational readiness standards on every PR.
How Grafana Collector Powers This Guardrail
The Grafana Collector gathers metadata from your service catalog systems. This data flows into Lunar's Component JSON, where the Dashboard Exists guardrail evaluates it against your standards.
When enabled, this check runs automatically on every PR and in AI coding workflows, providing real-time enforcement with actionable feedback.
Quick Start Configuration
Add both the collector and policy to your lunar-config.yml to enable this guardrail.
# Step 1: Enable the Grafana Collector
collectors:
- uses: github://earthly/lunar-lib/collectors/grafana@v1.0.5
# with: ...
# Step 2: Enable the Observability Guardrails
policies:
- uses: github://earthly/lunar-lib/policies/observability@v1.0.5
include: [dashboard-exists]
# with: ...
What Grafana Collector Collects
This collector gathers the following data that the Dashboard Exists guardrail evaluates.
dashboard
Queries the Grafana REST API for the component's linked dashboard and
alert rules. Discovers the dashboard UID from the component's
grafana/dashboard-uid meta annotation (typically set by a
company-specific cataloger via
lunar catalog component --meta grafana/dashboard-uid <uid>), or
falls back to the explicit dashboard_uid input for static cases.
If no UID is found, the collector exits cleanly with no data written.
Writes
the resolved UID to .observability.dashboard.id (normalized,
tool-agnostic) so the full link is visible in the component JSON
even when the dashboard is missing. If
the UID is set but the dashboard does not exist in Grafana, writes
.observability.dashboard.exists=false and also writes
.observability.alerts.configured=false and
.observability.alerts.count=0 without querying the alerts API —
the alerts block is always present when the dashboard sub-collector
runs, so policies see a consistent shape regardless of whether the
dashboard resolved. When the dashboard does exist: fetches the
dashboard's folder UID from meta.folderUid on the dashboard API
response, then lists alert rules via Grafana's alerting API
(/api/v1/provisioning/alert-rules) and filters to rules whose
folderUID matches. .observability.alerts.count is the count of
matching rules; .observability.alerts.configured is true when
count > 0. Writes normalized data to .observability.dashboard,
.observability.alerts, .observability.source, and the raw Grafana API
responses to .observability.native.grafana.api.
repo-dashboards
Walks the component repository looking for Grafana dashboard JSON files
by content fingerprint (top-level schemaVersion and panels fields).
Users can narrow the scan by setting the find_command input (e.g. to
restrict to a dashboards/ directory); by default the full repo is
walked. Writes each matching file's raw JSON (plus its repo path) into
.observability.native.grafana.repo_dashboards for users to build
custom policies against. This sub-collector does not write to
normalized .observability.dashboard paths — the API sub-collector owns
those.
Example Data Flow
Here's an example of the data that Grafana Collector writes to the Component JSON, which Dashboard Exists then evaluates.
{
"observability": {
"source": {
"tool": "grafana",
"integration": "api"
},
"dashboard": {
"id": "abc123",
"exists": true,
"url": "https://grafana.example.com/d/abc123/payment-api"
},
"alerts": {
"configured": true,
"count": 5
},
"native": {
"grafana": {
"api": {
"dashboard": { "...full Grafana dashboard API response..." },
"alert_rules": [ "...list of alert rule objects..." ]
},
"repo_dashboards": [
{
"path": "dashboards/payment-api.json",
"dashboard": { "schemaVersion": 39, "title": "Payment API", "panels": [] }
}
]
}
}
}
}
Configuration Options
Grafana Collector Inputs
| Input | Required | Default | Description |
|---|---|---|---|
grafana_base_url |
Required | — | Grafana API base URL (e.g. `https://grafana.example.com`). Required for the `dashboard` sub-collector. If empty, the sub-collector exits cleanly with no data written. |
dashboard_uid |
Required | — | Grafana dashboard UID to query (e.g. `payment-api`). Optional if the component has a `grafana/dashboard-uid` meta annotation set by a cataloger. |
find_command |
Optional |
find . -type f -name '*.json'
|
Command used by the `repo-dashboards` sub-collector to enumerate candidate JSON files (must output one path per line). Narrow this to restrict the scan to a subdirectory, e.g. `find ./dashboards -type f -name '*.json'`. |
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 100+ built-in guardrails.