checkrd

Debug logging

How to turn debug logging on for the SDK, what gets logged, and why you must turn it off in production.

Debug logging

The SDK has a debug log mode that prints every policy decision, every batched telemetry post, and every control-plane interaction to stderr. It's useful while you're tuning a policy or chasing an intermittent deny — and it's a footgun in production.

This page covers how to enable it, what it actually shows, and the guard rails that keep it off prod by default.

Turning it on

Both SDKs honor the CHECKRD_DEBUG=1 environment variable. This is the recommended switch because it works identically on both runtimes and you don't have to change application code:

bash
export CHECKRD_DEBUG=1

The JavaScript SDK additionally accepts debug: true as a constructor option for cases where you want debug enabled per- client rather than process-wide:

typescript
import { Checkrd } from "checkrd";

const client = new Checkrd({
  agentId: "my-agent",
  apiKey: "ck_live_...",
  debug: true,
});

The Python SDK does not expose a constructor debug flag — production deployments routinely audit application code for hot- path opt-ins, and a process-level env var is the unambiguous single source of truth. Either path emits a one-time stderr banner on the first request that flags the PII risk and links here.

What gets logged

With debug=True, every request the SDK touches produces a structured log record. Approximately:

[checkrd] decision request_id=01HKZ... agent=sales-agent
          method=POST url=https://api.openai.com/v1/chat/completions
          rule=allow-openai-chat outcome=allow latency_us=187
[checkrd] telemetry batch_id=01HKZ... events=12 signed=true
          ingestion=https://api.checkrd.io/v1/telemetry status=204
[checkrd] control sse_event=policy_updated version=42
          dsse_verify=ok install_latency_ms=4

What's not logged at any level:

  • Request bodies, response bodies, prompt content, completion content.
  • API keys, agent private keys, OAuth tokens.
  • Headers other than :method, :authority, :path, and the Checkrd signature headers.

The deny-or-allow decision and the metadata that the dashboard already shows are everything that's printed. There is no "verbose" level that ever logs the body.

The PII banner

When debug is enabled, the SDK writes one banner to stderr before the first request:

[checkrd] DEBUG LOGGING IS ON.
  Decision metadata, request URLs, and policy reasons will be printed
  to stderr. Bodies and prompts are NOT logged.

  This is fine for local dev. In production, the URL and matched-rule
  fields can still leak operational signal that you may not want in
  shared log aggregators.

  turn it off. See https://checkrd.io/docs/debug-logging

The banner is one-shot per process so it doesn't spam your logs. There is no way to silence the banner while keeping debug on — that is intentional. If you want a quiet production deploy, turn debug off.

Why this matters in production

Even though the SDK doesn't log bodies, the structured fields it does log are operational signal:

  • URLs can identify which third-party APIs your agent depends on, which is sometimes confidential.
  • Rule names can leak the shape of your security posture.
  • request_id is correlatable across SDK, ingestion, and ClickHouse — useful for triage, useful for log scrapers too.

In a shared log aggregator (Datadog, Splunk, CloudWatch) accessible to a wide audience, that's worth thinking about. The dashboard already gives you the same data with proper RBAC; the debug log is strictly for cases where you can't reach the dashboard.

Production guard

The SDK looks for production signals on init: NODE_ENV=production, PYTHON_ENV=production, the standard PaaS markers (KUBERNETES_SERVICE_HOST, LAMBDA_RUNTIME_DIR, AWS_EXECUTION_ENV, RAILWAY_ENVIRONMENT, RENDER, FLY_APP_NAME, VERCEL). If any of these are set and debug is on, the banner escalates to a WARN-level log and the request_id is suppressed from the structured fields — so debug remains useful for one-off production triage but won't quietly leak request correlations.

There is no hard refusal in production. The judgment call is yours; the SDK just makes sure you've seen the warning.

Turning it off

bash
unset CHECKRD_DEBUG

JS callers who explicitly opted in via the constructor flip it back:

typescript
const client = new Checkrd({
  agentId: "my-agent",
  apiKey: "ck_live_...",
  debug: false,
});

debug is off by default. If you set it explicitly somewhere and forgot, grep for CHECKRD_DEBUG and debug: / debug=.

See also