Grafana Collector
Query the Grafana API for dashboards and alerts linked to each component, and scan the component repo for Grafana dashboard JSON files. Normalizes to .observability for tool-agnostic policies; raw data at .observability.native.grafana.
grafana to your lunar-config.yml:uses: github://earthly/lunar-lib/collectors/grafana@v1.0.5
What This Integration Collects
This integration includes 2 collectors that gather metadata from your systems.
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.
How Collectors Fit into Lunar
Lunar watches your code and CI/CD systems to collect SDLC data from config files, test results, IaC, deployment configurations, security scans, and more.
Collectors are the automatic data-gathering layer. They extract structured metadata from your repositories and pipelines, feeding it into Lunar's centralized database where guardrails evaluate it to enforce your engineering standards.
Learn How Lunar Works →Example Collected Data
This collector writes structured metadata to the Component JSON. Here's an example of the data it produces:
{
"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
Configure this collector in your lunar-config.yml.
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'`. |
Secrets
This collector requires the following secrets to be configured in Lunar:
| Secret | Description |
|---|---|
GRAFANA_API_KEY
|
Grafana API token with `dashboards:read` and `alerting.rules:read` scopes. Used by the `dashboard` sub-collector only. |
Documentation
View on GitHubGrafana Collector
Collect dashboard and alert rule data from Grafana via the API, and discover Grafana dashboard JSON files committed in the component repository.
Overview
This plugin provides two sub-collectors. The dashboard sub-collector queries the Grafana REST API on every code event for the dashboard and alert rules linked to each component via the component's grafana/dashboard-uid meta annotation (typically set by a cataloger). The repo-dashboards sub-collector walks the component repo looking for Grafana dashboard JSON files by content fingerprint and stashes their raw contents for custom policies. Both write under the tool-agnostic .observability category, so the shared observability policy works regardless of whether the data comes from Grafana, Datadog, or another provider.
Collected Data
This collector writes to the following Component JSON paths:
| Path | Type | Description |
|---|---|---|
.observability.source |
object | Tool and integration metadata |
.observability.dashboard.id |
string | Tool-agnostic dashboard identifier (for Grafana, this is the dashboard UID; set even when the dashboard no longer exists) |
.observability.dashboard.exists |
boolean | Whether the linked Grafana dashboard exists |
.observability.dashboard.url |
string | Direct URL to the dashboard |
.observability.alerts.configured |
boolean | Whether any alert rules are configured for the dashboard's folder |
.observability.alerts.count |
number | Number of alert rules scoped to the dashboard's folder |
.observability.native.grafana.api |
object | Raw Grafana API responses (dashboard + alert rules) |
.observability.native.grafana.repo_dashboards |
array | Raw JSON of each Grafana dashboard file discovered in the repo, with its path |
Collectors
This plugin provides the following sub-collectors:
| Collector | Description |
|---|---|
dashboard |
Queries Grafana API for the dashboard and alert rules linked via the grafana/dashboard-uid meta annotation (code hook) |
repo-dashboards |
Discovers Grafana dashboard JSON files in the repo by content fingerprint (code hook) |
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/grafana@v1.0.0
on: ["domain:your-domain"]
with:
grafana_base_url: "https://grafana.example.com"
# find_command: "find ./dashboards -type f -name '*.json'" # Optional, narrows repo scan
Required secrets:
GRAFANA_API_KEY— Grafana API token withdashboards:readandalerting.rules:readscopes
Dashboard discovery (the dashboard sub-collector)
The dashboard sub-collector resolves the component's Grafana dashboard UID in this order:
- Catalog meta annotation — reads
grafana/dashboard-uidfrom the component's lunar catalog meta. Set vialunar catalog component --meta grafana/dashboard-uid <uid>, typically by a company-specific cataloger that knows which components map to which dashboards. This is the recommended approach for orgs where each component has its own dashboard. dashboard_uidinput — explicit value passed viawith: dashboard_uid: <uid>inlunar-config.yml. Useful for static cases or for orgs that don't run a cataloger.- If neither is set, the sub-collector exits cleanly with no data written.
If the UID resolves but the dashboard does not exist in Grafana, the collector writes .observability.dashboard.exists=false so policies can flag the stale link. In that case it also writes .observability.alerts.configured=false and .observability.alerts.count=0 without querying the alerts API — the alerts block is always populated when the sub-collector runs, so policies see a consistent shape.
Alerts detection. Alert rules in Grafana live in folders (not on dashboards directly), so the sub-collector reads the dashboard's folder UID from meta.folderUid on the /api/dashboards/uid/<uid> response, then lists alert rules via /api/v1/provisioning/alert-rules and filters to rules whose folderUID matches. .observability.alerts.count is the number of matching rules; .observability.alerts.configured is true when count > 0. This folder-scoped model reflects how Grafana teams typically organize alerting around dashboards.
Repo dashboard discovery (the repo-dashboards sub-collector)
The repo-dashboards sub-collector walks the cloned component repo and identifies Grafana dashboard JSON files by content fingerprint: any .json file whose top-level object contains both a schemaVersion (integer) and a panels (array) field is treated as a dashboard and its raw contents are captured.
By default the full repo is walked. Set the find_command input to narrow the search to a specific directory (for example find ./dashboards -type f -name '*.json'). This mirrors the pattern used by the k8s collector for YAML manifest discovery. Files that do not match the fingerprint are silently skipped. If no dashboards are found, nothing is written.
Notes on behavior
- Both sub-collectors run on the
codehook, so they fire on each push rather than a schedule. Thedashboardsub-collector does not actually read from the repo, but the clone is cheap and keeps the hook model consistent across the plugin. .observability.native.grafana.repo_dashboardsis intentionally raw — users write their own policies against the dashboard JSON if they care about panel shapes, datasource usage, etc.- Example Component JSON is defined in
lunar-collector.ymlunderexample_component_json.
Open Source
This collector is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore guardrails that use data from Grafana Collector.
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.