Skip to content

CodeYogiCo/grafgen

Repository files navigation

grafgen — YAML-driven Grafana dashboard generator

Define dashboards, alerts and notification routing as YAML. grafgen compiles them into modern Grafana JSON using pluggable modifiers, then writes files for GitOps or publishes straight to Grafana over the API.

grafgen replaces hand-maintained dashboard DSLs with a low-code framework. It's a Kotlin/JVM tool shipped as a single fat JAR, with the common integrations (HTTP, Kafka, Redis, Slack) built in, and stays extensible: add a new integration by dropping in a YAML bundle — no recompilation.


Why

  • Dashboards as code, reviewable — a small YAML spec instead of thousands of lines of generated JSON.
  • Runtime knobs as config, not code — thresholds, notification UIDs, SLAs, env settings, proxy/frontend maps live in layered YAML (the job Gradle tasks used to do) and flow into templates.
  • Pluggable modifiershttp, kafka, redis, … each contribute panels/alerts/variables/contacts. Teams add their own without touching the core.
  • One spec, every environment--env prod overlays tighter SLOs; --env dev loosens them.
  • Files and API — emit artifacts for GitOps, or apply directly to Grafana.

Requirements

  • JDK 21+ (to run the JAR and to build).

Build & install

./gradlew shadowJar          # -> build/libs/grafgen-all.jar
alias grafgen='java -jar build/libs/grafgen-all.jar'

(Release builds attach grafgen-all.jar to the GitHub release.)

Quick start

# 1. Render the example spec for prod into ./out
grafgen --env prod generate -o out examples/featurestoreapi/spec.yaml

# 2. See it live in Grafana (file-provisioned)
docker compose up -d          #  http://localhost:3000  (anonymous viewer, or admin/admin)

# 3. Or publish straight to a Grafana instance
export GRAFANA_URL=https://grafana.example.com GRAFANA_TOKEN=...
grafgen --env prod apply examples/featurestoreapi/spec.yaml

During development you can also run via Gradle: ./gradlew run --args="--env prod generate examples/featurestoreapi/spec.yaml".

How it works

spec.yaml + layered config (defaults/thresholds/notifications/proxies/frontends)
                       │            + env/<env>.yaml overlay
                       ▼
            ┌──────────────────────┐
            │  GenerationContext   │   thresholds, notification UIDs, SLA,
            └──────────┬───────────┘   meta, datasource, proxy/frontend maps
                       ▼
          resolve & run modifiers ──►  Contributions { panels, variables,
            (bundles + providers)        alerts, links, contact points }
                       ▼
              assemble IR (dashboard)
                       ▼
   render: dashboard JSON (schemaVersion 39) │ alert rules │ contact points
                       ▼
      deliver: write files (GitOps)  AND/OR  publish via Grafana HTTP API

A single Modifier interface backs three interchangeable sources, so the core never changes to gain an integration:

  1. No-code template bundles — a directory of templated YAML (how the built-ins ship).
  2. External gRPC providers — separate binaries in any language for custom runtime logic (see proto/grafgen/v1/provider.proto; transport wiring is the next milestone).
  3. Compiled-in built-ins — registered in Kotlin.

The spec

apiVersion: grafgen/v1
kind: Dashboard
metadata:
  team: search-tech
  app: featurestoreapi
  title: "[[ meta.team ]]/[[ meta.app ]] - Overview"
  folder: search-tech
  tags: [search-tech, featurestoreapi, http, redis, kafka]
spec:
  datasource: prometheus
  variables:
    - { name: app, type: constant, value: featurestoreapi, hide: 2 }
  modifiers:
    - use: http        # rate / latency / error panels + SLO alert
      with: { alerts: true }
    - use: kafka
      with: { topics: [feature-updates] }
    - use: redis
    - use: slack       # team contact point + routing

Templating

grafgen uses Pebble with square-bracket delimiters so Grafana's own {{ legendFormat }} / ${variable} syntax passes through untouched:

Syntax Purpose Example
[[ … ]] print / interpolate [[ meta.app ]]
[% … %] control flow [% if params.alerts %] … [% endif %]
[# … #] comment

Values come from the generation context, e.g. [[ thresholds.http.errorRatio | default(0.05) ]]. Note: no leading dot (meta.app, not .meta.app), and filters use parentheses (default(0.05)).

Layered config (the ex-Gradle knobs)

Everything under src/main/resources/config/ (overridable with --config-dir) merges into the context with this precedence:

defaults.yaml           → context root
thresholds.yaml         → context.thresholds
notifications.yaml      → context.notifications
proxies.yaml            → context.proxies
frontends.yaml          → context.frontends
env/<env>.yaml          → deep-merged at the root (overrides any of the above)

So --env prod tightening thresholds.http.errorRatio to 0.02 updates both the dashboard panel threshold and the generated alert rule — from one place.

Modifiers

grafgen providers          # list available bundles

NAME       VERSION   DESCRIPTION
http       0.1.0     HTTP service panels (rate, latency, errors) and an SLO error-rate alert
kafka      0.1.0     Kafka consumer-lag and throughput panels
redis      0.1.0     Redis throughput, memory and hit-rate panels
slack      0.1.0     Slack contact point for the dashboard's team (notification routing)

A bundle is just a directory:

src/main/resources/modifiers/http/
├── modifier.yaml          # name, version, params (with defaults)
├── panels/http.yaml.tmpl  # contributed panels (templated YAML list)
└── alerts/slo.yaml.tmpl   # contributed alert rules

Scaffold a new one and overlay external bundles with --modifiers-dir:

grafgen new modifier mything          # creates modifiers/mything/...
grafgen --modifiers-dir ./modifiers generate ...

Contribution directories: variables/, panels/, rows/, alerts/, links/, contacts/. Each *.yaml.tmpl renders to a YAML list of the matching IR type.

CLI

Command What it does
grafgen validate [path] Validate specs + config; confirm every modifier resolves and renders
grafgen generate [path] -o out Render dashboards / alerts / contacts to files
grafgen plan [path] Diff against a live Grafana (create vs update)
grafgen apply [path] Ensure folders + upsert dashboards via the API
grafgen providers List available modifier bundles
grafgen new spec|modifier Scaffold a starter spec or bundle

Global flags: --env (default dev), --config-dir (default config), --modifiers-dir (overlay extra bundles).

Output layout: out/<env>/<team>/<app>/{dashboard.json, alerts.yaml, contactpoints.yaml}.

Testing

Unit tests (incl. a mock-Grafana publish path) run with no dependencies:

./gradlew test

The integration test publishes to a real Grafana and verifies the dashboard lands (excluded from test, tagged integration):

docker compose up -d grafana
./gradlew integrationTest        # GRAFANA_URL / GRAFANA_USER / GRAFANA_PASS (default admin/admin)

CI (.github/workflows/ci.yml) runs ./gradlew build plus the integration test against a Grafana service container on every push/PR. Tagged releases (v*) publish the fat JAR.

Project layout

src/main/kotlin/com/codeyogico/grafgen/
  Main.kt               entrypoint
  cli/                  clikt commands
  spec/                 YAML spec types + validation
  config/               layered config load + merge -> GenerationContext
  ir/                   intermediate representation (shared model)
  template/             Pebble [[ ]] template engine
  modifier/             Modifier interface, registry, bundle loader
  render/               IR -> Grafana JSON / alert / notification provisioning
  deliver/              file writer + Grafana HTTP API client
  pipeline/             spec + config + modifiers -> IR
  provider/             external gRPC provider seam
  vfs/                  classpath + filesystem resource access
src/main/resources/
  modifiers/            built-in no-code bundles (embedded in the JAR)
  config/               default layered config (embedded)
src/test/kotlin/        unit + tagged integration tests
examples/               sample specs
deploy/provisioning/    Grafana datasource + dashboard provisioning for compose
proto/                  provider gRPC protocol

Roadmap

  • Wire the external gRPC provider transport.
  • JSON-Schema validation for specs and modifier manifests.
  • plan diffing of alert rules and contact points (not just dashboards).
  • More built-in bundles (JVM, gRPC, Aerospike, …).

License

TODO — choose a license (e.g. Apache-2.0) and add a LICENSE file.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors