Skip to content

synthkit

synthkit gives you a Grafana-visible synthetic environment: run a bundled blueprint and see realistic metrics, traces, and logs arrive in your stack. It models the infrastructure and applications you declare; it does not deploy them. From that YAML blueprint, synthkit emits structurally-correct synthetic metrics (Prometheus Remote-Write v2), traces (OTLP), logs (Loki), and optional RUM (Faro) using the real technology-native metric/label/field names of each technology it models. No invented names, no placeholder shapes. Every signal is sourced from production-validated contracts in the signals/ catalogue.

Use synthkit to build and validate dashboards and alerts against realistic data, generate demo environments, or run observability training without touching a production system.

  • Getting started


    Mental model, vocabulary, and concepts before you install.

    Getting started

  • Writing blueprints


    Declare environments, clusters, databases, workloads, and incident scenarios.

    Blueprints overview

  • Signal catalogue


    Every metric family, label set, and field name — sourced from real stacks.

    Reading the catalogue

  • Architecture


    Three-tier design, frozen seams, invariants, and composition model.

    Architecture

Quickstart

The dry run needs no credentials at all — it prints the full series and label inventory it would emit, and pushes nothing:

go build ./cmd/synthkit

DRY_RUN=true BLUEPRINT_NAMES=otlp-native ./synthkit -once -dump

To push for real, create a private environment file, select a blueprint, fill in GC_TOKEN and the endpoints, and explicitly change DRY_RUN=false before starting:

if test -e .env; then
  printf '%s\n' '.env already exists; review it before changing live-mode settings.' >&2
else
  install -m 600 .env.example .env
  ./plugins/synthkit/skills/initial-setup/scripts/set-env.sh BLUEPRINT_NAMES otlp-native .env
  ./plugins/synthkit/skills/initial-setup/scripts/set-env.sh DRY_RUN false .env
fi
# Edit .env and fill in the required Grafana Cloud values without printing them.
./synthkit

For an existing .env, review its credentials first, then run the same set-env.sh DRY_RUN false .env command when you are ready to opt into live delivery.

From another terminal, confirm the status endpoint reports dry_run=false:

The -u control form prompts for CONTROL_TOKEN without echoing it; press Enter only for an intentionally token-free loopback run.

curl -fsS -u control http://localhost:8088/control/status | jq -e '.dry_run == false'

The command prints true; it exits nonzero if live mode is not active. jq is optional: without it, inspect the same JSON with curl -fsS -u control http://localhost:8088/control/status and look for "dry_run":false.

What synthkit emits

Signal typeProtocolDestination
MetricsPrometheus Remote-Write v2Grafana Cloud Mimir
TracesOTLP (hand-encoded ResourceSpans)Grafana Cloud Tempo
LogsLoki pushGrafana Cloud Loki
RUM (optional)Faro collectorGrafana Cloud Frontend Observability
Profiles (optional)PyroscopeGrafana Cloud Profiles

Each signal type uses its own credential triplet. A single Cloud Access Policy token with metrics:write, logs:write, traces:write, and profiles:write scopes covers all four synthetic sinks — see Credentials.

The blueprint model

A blueprint is a single YAML file that wires together construct and workload instances with config. Constructs are isolated modules — each emits the real signal names of one technology (EKS, RDS, Cloudflare, Fleet Management, and so on). Workloads generate correlated request traffic: web_service models a single service with a browser→backend→DB hop tree; app models a multi-service graph whose nodes emit custom telemetry via a DSL. They model traffic and telemetry only; synthkit does not deploy a real app. Constructs know nothing about blueprints or each other; deleting a blueprint file removes its telemetry and affects nothing else.

DRY_RUN defaults to true, and empty BLUEPRINT_NAMES selects nothing. Live pushing and the blueprint set are both explicit opt-ins; use BLUEPRINT_NAMES=* only for the complete catalog.

Principles

  • No invented names. Every metric, label, and field name is sourced from the signals/ catalogue, which is lifted from production-validated stacks with provenance citations.
  • Isolated constructs. Constructs and workloads never import each other, the blueprint package, or any OTel SDK. Zero coupling flows backward.
  • One blueprint = one file. Config lives in the blueprint; constructs are unconditional. Add a scenario, remove an environment, or delete the whole blueprint — nothing else changes.
  • Deterministic. The same blueprint produces the same identities (pod names, node IDs, instance keys) on every run. Fixtures are seeded from the blueprint name and path, not from process time.
  • Cumulative correctness. Counters and histograms accumulate across ticks; the sink receives running totals, not deltas, matching how real exporters work.

License

synthkit is licensed under the GNU Affero General Public License v3.0 only (AGPL-3.0-only). Every Go source file carries an SPDX-License-Identifier: AGPL-3.0-only header.