Open source · Apache-2.0 · Go

Your API tells you everything. Decide what it repeats.

OpticTrace is a governance gateway for HTTP APIs. One declarative optic.yaml controls which routes are monitored, which payloads are stored, what gets masked, and which request attributes become Prometheus dimensions — reviewed in your repo like any other code.

Get started brew install dwarka-prasad/tap/optictrace
Terminal demo: a payment request is sent with a real card number, the client receives the real bytes back, and the stored telemetry shows the card, CVV, email and bearer token all replaced with [REDACTED].
Real output from a running agent. The client receives the original bytes; the card number, CVV, email and bearer token never reach telemetry.
+0.22 µsadded latency, restricted route
13CLI commands
3framework SDKs
0CGO dependencies

API observability usually forces a bad trade

Log everything and credit card numbers end up in your log pipeline, replicated to three vendors and retained for a year. Log nothing and you are debugging production from status codes alone.

Option A

Capture everything

Fast to set up, and now every downstream system is in PCI scope. The decision was never written down, so nobody can tell you what is being stored.

Option B

Capture nothing

Safe and useless. When something breaks at 3am you have a status code, a duration, and no idea what the client actually sent.

OpticTrace

Declare the difference

Everything is captured unless a rule says otherwise. The rules live in your repo, get code-reviewed, and are testable in CI — so the trade-off is explicit and auditable.

How it works

Two lanes, one tee point

A request travels one path while its telemetry travels another. The traffic lane is a plain reverse proxy. The telemetry lane branches off a bounded copy and is where every governance decision happens.

This is the invariant everything else rests on: live traffic is never modified. A rule that masks $.credit_card.number does not strip the card from the payment request — the payment still works. It strips it from what gets logged, stored and exported.

Stage 2 is where the performance story lives: the policy resolves before any capture machinery attaches, so a route you have told OpticTrace to leave alone allocates nothing.

The whole interface

One file, reviewed like code

Parsing is strict — an unknown key is rejected at load, so a typo like restirct: fails immediately instead of quietly disabling your governance.

optic.yaml
# Everything is captured unless a rule subtracts from it.
rules:
  # Credentials never reach telemetry.
  - name: no-capture-on-auth
    match: { path: "/api/v1/auth/**" }
    restrict: [request_body, response_body, headers]

  - name: redact-payment-secrets
    match: { path: "/api/v1/payments/**" }
    redact:
      headers: [Authorization, X-Api-Key]
      query_params: [api_key]
      json_fields:
        - "$.credit_card.number"   # exact path
        - "$.*.ssn"                # any single key
        - "$.**.card_token"        # any depth
    labels:
      tenant: "header:X-Tenant-ID"  # a Prometheus dimension
    sample: 0.25                # bodies for 25%…
    keep_errors: true          # …but always keep 5xx

  # Prompts stay private; tokens are still counted and billed.
  - name: meter-ai-tokens
    match: { path: "/api/v1/ai/**" }
    restrict: [request_body, response_body]
    meter: { tokens: "$.usage.total_tokens" }
what gets stored
{
  "request_body": {
    "amount": 4200,
    "credit_card": {
      "cvv": "[REDACTED]",
      "number": "[REDACTED]"
    },
    "customer": {
      "email": "[REDACTED]",
      "name": "Ada Lovelace"
    }
  },
  "headers": {
    "Authorization": "[REDACTED]",
    "X-Tenant-Id": "acme"
  },
  "labels": { "tenant": "acme" },
  "matched_rules": ["redact-payment-secrets"]
}

Non-sensitive fields survive, so the record is still worth debugging with. Rules merge top-to-bottom: restrictions only narrow capture, while redactions and labels accumulate.

Built in

A dashboard the binary serves itself

No separate frontend to deploy. The agent compiles the UI in and serves it from its control plane, on a port you can firewall independently of the API it proxies.

Request Inspector with a payment selected: the card number, CVV, email and Authorization header are highlighted as [REDACTED], the matched rule is named, and tenant and region labels are shown.

Request Inspector

Redacted values are highlighted so you can see governance working, the rule responsible is named, and every non-sensitive field is still there.
Overview page with request volume, error rate, P95 and P99 latency, live charts and a top-routes table.

Overview

Golden signals and per-route latency.
Usage page showing per-tenant requests, data transferred, compute time, token meters and estimated cost.

Usage & cost

Per-tenant consumption, meters and billing export.
The provisioned Grafana dashboard showing request rate, error rate, latency percentiles, per-route table and agent health panels.

Grafana, provisioned

docker compose up brings the agent, Prometheus and Grafana up together with this dashboard and seven alert rules already loaded — including alerts on the agent's own health, because a monitor that silently stops recording is worse than none.
Because it owns your traffic history

Things a static tool cannot do

OpticTrace holds a governed record of what your API actually did. That turns several hard questions into simple ones.

optictrace scan

Find what your rules missed

Redaction masks what you name. This catches the field you forgot, using checksums and issuer prefixes rather than guesswork — and prints the rule that fixes it. Samples are always masked.

optictrace check

Break nothing

Answers "is any live client actually using the field I am about to remove?" with usage counts and last-seen times. Exits non-zero in CI.

optictrace spec / sdk

Docs that write themselves

Infers an OpenAPI document from what clients really send, then emits typed TypeScript, Python or Go clients. Redacted fields still contribute their name and type.

optictrace mock

A mock with state

POST /cart then GET /cart returns the item you added. Other routes return schema-conforming data, optionally generated by Claude.

optictrace test

Testable governance

Assert that a route redacts what it should, with no server and no network, so CI proves a refactor did not quietly stop masking.

optictrace replay

Replay, honestly

Re-issues captured traffic against staging and diffs status codes — skipping what governance made unreplayable rather than pretending.

In your workflow

It reviews your pull requests

Every other command is one you have to remember to run. This one runs itself and answers the question a reviewer actually has: does this change make governance weaker?

It evaluates the same captured traffic under the base branch's rules and the pull request's, then reports where they disagree. A rule reordering that silently stops masking a card number is invisible in a text diff and obvious here.

optictrace commented on this pull request
✗ This change weakens governance on 4 points

Each one below was verified by replaying real traffic. If it is deliberate, say so in the PR.

RouteChangeRequests affected
POST /api/v1/payments/**stops redacting $.**.credit_card.cvv34
POST /api/v1/payments/**stops redacting query param api_key34
POST /api/v1/auth/**now captures request bodies (was restricted)34
POST /api/v1/payments/**drops label region34

By default a pull request fails only for what it changed. Pre-existing findings are reported for context but do not block — failing every PR for a problem someone else introduced is how a bot gets muted, and a muted bot protects nothing.

Measured, not asserted

What it costs

"Low overhead" deserves numbers. These come from go test -bench comparing a bare handler against the same handler wrapped by the interceptor.

Read the absolute numbers

Against a typical API call of 1–100 ms, full capture is 0.005–0.5% of the request. It is not free — the cost is dominated by JSON parse and re-serialise — which is why sample with keep_errors exists for very hot routes.

The design claim holds

Restricting a route really is near-free. The policy resolves before any buffer is attached, so a route you have excluded costs 0.22 µs — and Prometheus observation, even with a custom label dimension, is noise at 0.13 µs.

12th Gen Intel i5-1235U, Go 1.25, -benchtime=2s, parallel. Reproduce with make bench.

Deploy it

Sidecar, middleware, or SDK

All three share one interception code path, so governance behaves identically however you run it.

standalone gateway
# proxies to service.upstream, dashboard on :9095
optictrace run -config optic.yaml
embedded in Go
agent, _ := optictrace.New("optic.yaml")
defer agent.Close()
http.ListenAndServe(":8080", agent.Middleware(mux))
Express
app.use(optictrace({
  configPath: 'optic.yaml',
  agentUrl: 'http://localhost:9095',
}));
FastAPI
app.add_middleware(
    OpticTraceMiddleware,
    config_path="optic.yaml",
    agent_url="http://localhost:9095",
)
  • SDKs apply governance in-process — raw payloads never cross a process boundary
  • SQLite for a sidecar, Postgres when several agents share history
  • Export to files, webhooks, OpenTelemetry, or your own executable

Try it in about a minute

The Compose stack brings up the agent, a demo API, Prometheus and Grafana with dashboards and alerts already provisioned — and deliberately leaves one route ungoverned so scan has something to find.

git clone https://github.com/dwarka-prasad/optictrace && cd optictrace
docker compose up --build

# http://localhost:9095  dashboard · metrics · APIs
# http://localhost:3000  Grafana
# http://localhost:9090  Prometheus

Prefer just the binary? brew install dwarka-prasad/tap/optictrace covers macOS and Linux on Intel and ARM, go install builds from source, and every release ships checksummed, cosign-signed archives with an SBOM.