SigNoz & OpenTelemetry
Connect DriftWatch to SigNoz Cloud or self-hosted, and read the traces, metrics, and logs it emits.
DriftWatch instruments every agent decision as OpenTelemetry — traces, metrics, and logs. It exports over standard OTLP/HTTP, so any OTel-compatible backend can receive it. SigNoz is the recommended one: the drift detector reads its data back out through SigNoz's query API to compute drift, so SigNoz is both your dashboard and part of the control loop.
This guide connects DriftWatch to SigNoz and shows what to look at once data flows.
Two endpoints, two credentials
This is the one thing to get right. DriftWatch talks to SigNoz in two directions, and they use different hosts and different keys. Mixing them up is the most common reason "nothing shows up."
| Direction | What | Env vars |
|---|---|---|
| Push telemetry in | Traces/metrics/logs → SigNoz's OTLP collector | OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS |
| Pull data back out | Drift detector queries the SigNoz query API | SIGNOZ_URL, SIGNOZ_API_KEY |
The ingestion key (push) and the API key (pull) are two different credentials. Don't reuse one for the other.
Connecting to SigNoz Cloud
-
Ingestion (push). In SigNoz Cloud → Settings → Ingestion Settings, copy your region's ingestion endpoint and ingestion key:
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.<region>.signoz.cloud:443 OTEL_EXPORTER_OTLP_HEADERS=signoz-ingestion-key=<your-ingestion-key><region>isus,eu, orin. -
Query API (pull). In SigNoz Cloud → Settings → API Keys (create a key with at least the Viewer role), and use your dashboard URL — the one in your browser's address bar when viewing SigNoz — as the base:
SIGNOZ_URL=https://<your-team>.<region>.signoz.cloud SIGNOZ_API_KEY=<your-api-key>SIGNOZ_URL is the dashboard host, not the ingest host
The ingest host has no query API; pointing
SIGNOZ_URLat it will make/driftfail. If the query API returns403 forbidden, the key's service account is missing the Viewer role.
Connecting to self-hosted SigNoz
Self-hosted SigNoz bundles the collector and query service, and needs no ingestion header:
git clone https://github.com/SigNoz/signoz && cd signoz/deploy/docker
docker compose up -d # UI + query service on :8080, OTLP collector on :4318OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 # collector (HTTP/proto)
OTEL_EXPORTER_OTLP_HEADERS= # none for self-hosted
SIGNOZ_URL=http://localhost:8080 # query service / UI
SIGNOZ_API_KEY=<key from Settings → API Keys>Running DriftWatch as a container next to self-hosted SigNoz? Put them on the
same Docker network and use service names instead of localhost — see
deployment.md.
Verify it's flowing
Send some traffic (quickstart step 3), generate ~15–20 requests, wait 2–3 minutes, then in SigNoz:
- Services tab → a service named
driftwatchappears, with request rate, p95/p99 latency, and error rate. - Traces tab → filter
service.name = driftwatchto see individual/runcalls.
If the service doesn't appear after a few minutes, it's almost always the
endpoint/key: confirm the push endpoint is the ingest.* host with the
ingestion key, not the query host.
What DriftWatch emits
Traces — the full decision chain
Every /run opens one root span, agent.run, with child spans for each model
step and tool call:
agent.run task id, skills used, token spend, provider, model
├─ gen_ai.step one per LLM call — model, tokens, finish reason
├─ tool.get_weather tool latency + outcome (ok/error)
└─ gen_ai.stepOpen any agent.run span and read agent.task_id to pull that exact task's
whole trace — every tool it invoked and every token it spent. This is your
answer to "why did this one request behave this way?"
Metrics — aggregate behavior over time
Three custom metrics drive drift detection and make good dashboard panels. They are low-cardinality by design (labels are bounded sets — tool name, outcome, provider, model — never a request or task id), so they chart cleanly over time.
| Metric | Type | Labels | Answers |
|---|---|---|---|
agent.tool.calls | counter | tool, outcome | how often each tool is called, split ok/error |
agent.tool.duration | histogram | tool | per-tool latency, incl. p95 regressions |
agent.tokens | counter | model, provider, function_id, type | token spend by provider/model/task-type (agent-run vs drift-judge), input vs output |
Metrics export with delta temporality (SigNoz's recommendation) — each export carries the activity since the last one, so summing over a window gives "activity during that window," which is exactly what the drift detector needs.
Histogram naming
SigNoz stores an OTLP histogram as several series:
agent.tool.duration.bucket, .count, .sum, .min, .max. Percentiles
(p95) read the .bucket series; an average latency panel is
.sum / .count. The base name agent.tool.duration is not itself queryable.
Building dashboard panels
Fastest path: import
observability/signoz-dashboard.json
via SigNoz Dashboards → New dashboard → Import JSON — it contains all three
panels below, pre-built.
To build them yourself instead, in the SigNoz Dashboards → new panel → Metrics query builder:
- Calls per tool — metric
agent.tool.calls, aggregation Sum, group bytool. Addoutcometo split success vs error. - Token spend by model — metric
agent.tokens, Sum, group bymodel(orfunction_idto separate agent work from drift-judge cost). - Tool latency p95 — metric
agent.tool.duration.bucket, aggregation p95, group bytool.
These are the same signals detectBehavioralDrift reads — the dashboard shows
you what changed; the drift verdict tells you whether it matters.
Ask your agent's telemetry in plain English (SigNoz MCP)
SigNoz has an MCP server that lets an AI assistant (Claude, Cursor, Copilot, …) query your observability data in natural language. Because DriftWatch already emits standard OTel to SigNoz, this works over a DriftWatch-instrumented agent with zero extra code and no extra service to run — it's the same data you see in the Services and Traces tabs, now conversational. If you installed SigNoz with Foundry, the MCP server was installed in the same step.
Point your assistant's MCP config at the SigNoz MCP server, then ask things like:
- "How often is the
search_docstool erroring on thedriftwatchservice?" - "What's the p95 latency of
get_weatherover the last hour?" - "Which model drove the most token spend today?"
- "Show me the slowest
agent.runtraces and where they spent their time."
A minimal Claude Desktop / Cursor MCP entry pointed at SigNoz Cloud:
{
"mcpServers": {
"signoz": {
"command": "npx",
"args": ["-y", "@signoz/mcp-server"],
"env": {
"SIGNOZ_URL": "https://<your-team>.<region>.signoz.cloud",
"SIGNOZ_API_KEY": "<your-api-key>"
}
}
}
}(Use the same SIGNOZ_URL / SIGNOZ_API_KEY as the drift detector — the query
host and a Viewer-role key, not the ingest host. Check SigNoz's
MCP docs for the exact package
name and any self-hosted transport options.)
Division of labor
DriftWatch's own drift detector is the automated, deterministic trigger — it runs every cycle, compares two windows, and decides whether to alert or act. The SigNoz MCP server is the interactive layer — a human (or their assistant) exploring why, on demand, with the full richness of traces/metrics/logs. They answer different questions. DriftWatch therefore does not ship an MCP server of its own: SigNoz's MCP already queries the telemetry, at no extra cost.
Other OpenTelemetry backends
Because export is plain OTLP/HTTP, DriftWatch's traces, metrics, and logs
work with any OTel backend — Grafana (Tempo/Mimir/Loki via the OTel Collector),
Honeycomb, Datadog's OTLP intake, Jaeger (traces only), or a raw OpenTelemetry
Collector you fan out from. Point OTEL_EXPORTER_OTLP_ENDPOINT (and any auth
header via OTEL_EXPORTER_OTLP_HEADERS) at that backend and you'll get the full
trace/metric/log experience there.
The one SigNoz-specific piece is drift detection: detectBehavioralDrift
uses SigNoz's query API (/api/v4/query_range). With a different backend you
still get all the telemetry and dashboards — you'd just point the drift
detector at a SigNoz instance, or run it in dry-run mode, if you don't run
SigNoz for querying.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Service never appears in SigNoz | Push endpoint is the query host, or ingestion key missing | Use ingest.<region>.signoz.cloud:443 + signoz-ingestion-key=… |
Traces show up but no agent.* metrics | Metrics take a few minutes to become queryable | Wait 2–3 min after traffic; confirm on the Dashboards metric builder |
/drift returns 403 forbidden | Query API key lacks a role | Give the key's service account the Viewer role in SigNoz |
/drift returns connection errors | SIGNOZ_URL points at the ingest.* host | Point it at your dashboard URL instead |