For the complete documentation index, see llms.txt. Markdown versions are available by appending .md to documentation URLs.

Cursor IDE Observability & Monitoring with OpenTelemetry

SigNoz Cloud - This page applies to SigNoz Cloud editions.
Self-Host - This page applies to self-hosted SigNoz editions.

What is Cursor IDE Observability?

Cursor is an AI-native code editor whose agent plans and executes multi-step work: it reads files, runs shell commands, calls MCP servers, and edits code on your behalf. Cursor's own usage console shows what your team spent. What it does not show is what the agent actually did to spend it: which tools ran, how long each took, and which ones failed.

This guide closes that gap using OpenTelemetry. Cursor's agent hooks fire on every step of the agent loop, and a hook runner turns those events into OTLP traces. The result is one trace per agent turn carrying both token counts and the full tool sequence, on any Cursor plan.

With Cursor IDE observability in SigNoz, you can see how many tokens your team is spending and on which models, how long a turn actually takes end to end, which tools the agent reaches for most, which ones fail and why, and how all of that breaks down per repository and branch.

Prerequisites

  • SigNoz setup (choose one):
  • Cursor IDE on macOS or Linux
  • Python 3.11 or later

Monitor Cursor IDE with OpenTelemetry

Cursor has no built-in OTLP exporter outside its Enterprise plan, and that path emits metrics and logs only, with no traces. Instead, this setup uses Cursor's agent hooks with opentelemetry-hooks, an MIT-licensed runner that converts hook events into OTLP spans.

Step 1: Install the hook runner in its own environment so it does not touch your system Python.

python3 -m venv ~/.local/opt/otel-hook
~/.local/opt/otel-hook/bin/pip install opentelemetry-hooks

Step 2: Register it with Cursor. This writes ~/.cursor/hooks.json.

~/.local/opt/otel-hook/bin/otel-hook setup --agent cursor

Step 3: Add the event that carries token counts.

python3 - <<'EOF'
import json, os
p = os.path.expanduser("~/.cursor/hooks.json")
d = json.load(open(p))
h = d.get("hooks", d)
h["afterAgentResponse"] = json.loads(json.dumps(h["stop"]))
json.dump(d, open(p, "w"), indent=2)
print("events registered:", len(h))
EOF

You should see events registered: 16. If otel-hook is not on your PATH, rewrite the commands in ~/.cursor/hooks.json to the absolute path of the binary, otherwise Cursor silently fails to run the hook.

Step 4: Point the exporter at SigNoz. Edit ~/.local/share/opentelemetry-hooks/otel_config.json, keeping the other keys already in the file.

{
  "OTEL_EXPORTER_OTLP_ENDPOINT": "https://ingest.<region>.signoz.cloud:443",
  "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
  "OTEL_EXPORTER_OTLP_HEADERS": "signoz-ingestion-key=<your-ingestion-key>",
  "OTEL_EXPORTER_OTLP_INSECURE": "false",
  "IDE_OTEL_BATCH_ON_STOP": "true"
}

Verify these values:

The file holds your ingestion key, so restrict it with chmod 600 ~/.local/share/opentelemetry-hooks/otel_config.json.

Step 5: Quit Cursor completely and reopen it. Cursor reads ~/.cursor/hooks.json only at startup, so a running instance will not pick up the change. Confirm the hooks are active under Customize > Hooks, then send a prompt that uses a tool.

View Cursor IDE Traces in SigNoz

Allow a few minutes after your first prompt, then open the Traces explorer and filter on service.name = 'ide-agent'.

Cursor IDE agent spans in the SigNoz Traces explorer
Every hook event arrives as its own span under the ide-agent service.

Opening a turn shows the full waterfall, with the agent's tool sequence nested under the turn and the gen_ai.* attributes on the right.

A single Cursor IDE agent turn expanded in the SigNoz trace detail view
One turn: the prompt, each tool call, and the response, with token counts on the afterAgentResponse span.

Attributes Worth Knowing

A turn produces a gen_ai.client.generation span with one gen_ai.client.hook.* child per hook event. Four details decide whether your queries are correct.

  • Token counts arrive twice. afterAgentResponse and Stop both carry identical gen_ai.usage.input_tokens and gen_ai.usage.output_tokens. Filter to one of them or every token figure doubles.
  • Turn duration is on gen_ai.client.generation. The Stop span measures 1 ms on every turn and is a marker, not a measurement.
  • Tool failures are PostToolUseFailure. A single failed tool call also sets error status on its PreToolUse and PostToolUse spans, so counting error status roughly doubles the failure rate.
  • service.name is always ide-agent. The runner hardcodes it for every agent it supports, so group by gen_ai.client.name (cursor) when you run more than one agent.

Every span also carries gen_ai.request.model, gen_ai.client.session_id, gen_ai.client.generation_id, and, when the runner resolves it, vcs.repository.name and vcs.ref.head.name.

View Cursor IDE Logs in SigNoz

The runner emits logs alongside the traces, one record per tool call, shell execution, and MCP call. Open the Logs Explorer and filter with service.name = 'ide-agent' to see the event stream.

Cursor IDE agent logs in the SigNoz Logs Explorer
Each tool call and shell execution produces a log record, with the command inline in the body.

Logs carry detail the spans do not. Open a record to see it in the attributes.

An expanded Cursor IDE shell execution log record showing its attributes
A shell log record: gen_ai.client.command holds the full command and gen_ai.client.shell.stdout holds its output.

Useful attributes include gen_ai.client.command and gen_ai.client.shell.stdout for shell executions, gen_ai.client.tool_name and gen_ai.client.duration_ms for tool calls, and gen_ai.client.hook.event to separate the event types. Every record also carries trace_id and span_id, so a log line links back to the exact span in the turn's waterfall.

Cursor IDE Observability Dashboard

The Cursor IDE dashboard turns these spans into token spend by model, turn and tool latency, tool mix, and failure tracking.

Cursor IDE agent observability dashboard in SigNoz
The Cursor IDE dashboard template, showing token spend, latency, tool activity, and failures.

Troubleshooting Cursor IDE Observability

No spans arrive at all

Check delivery locally before assuming the export is broken:

cat ~/.local/share/opentelemetry-hooks/.state/delivery_health.json

A last_success_at_ns newer than last_failure_at_ns means export is working and you are looking at ingestion delay. Allow 2 to 4 minutes before re-checking SigNoz.

If there is no success timestamp, confirm Cursor was fully restarted after Step 2, and that Customize > Hooks lists the registered events.

Spans arrive but every token panel is empty

afterAgentResponse is not registered. Re-run Step 3 and confirm it prints events registered: 16, then restart Cursor. A restart is required whenever the registered event set changes.

Traces show a "missing span" placeholder

This is expected. The runner parents each turn to a session span that it never emits, so SigNoz shows the turn under a missing parent. The turn and its children are complete and every query works normally.

Repository shows as N/A on some spans

The runner resolves repository context once per session and does not always succeed, so vcs.repository.name can be absent even when the workspace is a git repository. Those spans are missing attribution rather than running outside a repository, which matters if you group token spend by repository.

Nothing is emitted from the Cursor CLI

This cannot be fixed by configuration. The Cursor CLI omits the beforeSubmitPrompt, afterAgentResponse, and stop hooks in non-interactive mode, and the runner builds a turn's spans only when Stop arrives. Use the Cursor IDE, or query Cursor's Admin API for team-level token and cost totals without per-tool detail.

Instrument the other AI coding agents your team runs, using the same OpenTelemetry pipeline:

Browse all LLM observability integrations to instrument the rest of your stack.

Is this page helpful

Last updated—August 27, 2026

Edit on GitHub