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

Qwen Code Observability and Monitoring with OpenTelemetry

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

What is Qwen Code Observability?

Qwen Code is Alibaba's open-source terminal coding agent. It ships its own OpenTelemetry exporter, so instrumenting it is a matter of configuration: there is no library to install and no collector to run. Once enabled it emits all three signals, with traces covering every agent turn, model call, and tool execution, metrics covering token usage and runtime health, and structured log events for each session.

With full Qwen Code observability in SigNoz, you can see how many tokens your team is spending and on which models, how much of each prompt is served from cache, how many round trips a single request actually takes, which tools the agent reaches for, and how much you are paying for background work nobody asked for.

Prerequisites

  • SigNoz setup (choose one):
  • Qwen Code 0.21.15 or later, installed with npm install -g @qwen-code/qwen-code
  • Node.js 20 or later
  • A configured model provider, such as a DashScope API key or any OpenAI-compatible endpoint

Monitor Qwen Code with OpenTelemetry

Telemetry is built into the CLI and turned off by default. Enabling it takes one settings block and one environment variable.

Step 1: Enable telemetry in .qwen/settings.json

Create the file in your project directory, or in ~/.qwen/settings.json to apply it to every project.

{
  "telemetry": {
    "enabled": true,
    "otlpProtocol": "http",
    "otlpEndpoint": "https://ingest.<region>.signoz.cloud:443",
    "metrics": { "includeSessionId": true }
  }
}

Step 2: Set the ingestion key and service name

export OTEL_EXPORTER_OTLP_HEADERS="signoz-ingestion-key=<your-ingestion-key>"
export OTEL_SERVICE_NAME=qwen-code

Verify these values:

Step 3: Run the agent

qwen "list the files in this directory and summarise the project"

Spans are batched, so allow a few seconds after the turn finishes before looking in SigNoz.

View Qwen Code Traces in SigNoz

Open the Traces explorer and filter on service.name = 'qwen-code'. Each turn arrives as its own trace.

Qwen Code traces in the SigNoz traces explorer
Interaction, model call, tool, and hook spans in the traces explorer

Open any qwen-code.interaction span to see the full turn. The waterfall shows each model call with the raw HTTP request underneath it, and each tool alongside the hook that fired for it.

A Qwen Code turn expanded in the SigNoz trace detail view
One turn: 16 spans across model calls and tool executions, with the interaction attributes on the right

Note that the trace above reports three errors even though the root span status is Ok. All three are hook spans, and the warning below explains why that is expected.

Qwen Code emits six span names, and the hierarchy matters when you write queries:

qwen-code.interaction                 root, one per user turn
├── qwen-code.llm_request             the model call
│   └── POST                (CLIENT)  auto-instrumented HTTP to the provider
└── qwen-code.tool
    ├── qwen-code.tool.execution      child of qwen-code.tool, not a sibling
    └── qwen-code.hook                fires per tool call
SpanWhat it covers
qwen-code.interactionOne user turn, the root span
qwen-code.llm_requestOne model call, with tokens, finish reason, and time to first chunk
POSTThe raw HTTP request to the provider, with status code
qwen-code.toolOne tool call, with the tool name and outcome
qwen-code.tool.executionThe execution phase of that same tool call
qwen-code.hookThe hook runner, invoked per tool call

Attributes Worth Knowing

qwen-code.llm_request carries the token counts and model metadata. A few names differ from what you may expect from other agents:

  • There is no gen_ai.usage.total_tokens. Sum gen_ai.usage.input_tokens and gen_ai.usage.output_tokens instead.
  • gen_ai.usage.cache_read.input_tokens holds cached input tokens, and the segment is dotted rather than underscored.
  • gen_ai.response.finish_reasons is a real array, so values render as ["stop"] and ["tool_calls"] rather than as plain strings.
  • Reasoning tokens are thoughts_token_count, not a gen_ai.* name. On current builds it reports zero.
  • success on qwen-code.tool filters correctly when you quote the value (success = 'false') but does not group reliably, so build success-versus-failure breakdowns from two filtered queries rather than a groupBy.

session.id, gen_ai.conversation.id, and qwen-code.prompt_id correlate spans across a whole session.

Background Subagents Spend Tokens You Did Not Ask For

Qwen Code runs background subagents, such as the auto-memory extractor and the dreamer, that make their own model calls. On a measured sample of 80 model calls, 18 of them, or 22%, came from background subagents rather than from a user prompt. A single "What is 2+2?" prompt triggered a subagent that consumed 7,004 input tokens on its own.

None of this is visible in the terminal. llm_request.context separates the two cleanly: interaction for calls made for a user turn, standalone for background work. subagent_name names the subagent on the calls that have one. Group token sums by llm_request.context to see what background work actually costs you.

Metrics and Logs

Alongside traces, Qwen Code exports a full metric set including qwen-code.token.usage, qwen-code.api.request.count, qwen-code.api.request.latency, qwen-code.tool.call.count, qwen-code.session.count, qwen-code.file.operation.count, qwen-code.cpu.usage, and qwen-code.memory.usage. Histograms arrive split into .bucket, .count, .sum, .min, and .max series.

It also emits structured log events per session, including session.start, qwen-code.user_prompt, qwen-code.api_request, qwen-code.api_response, qwen-code.subagent_execution, and session.end.

Qwen Code Observability Dashboard

The Qwen Code dashboard gives you token spend and cache efficiency, turn and session volume, model latency and time to first chunk, tool activity, and the user-driven versus background split out of the box.

Qwen Code dashboard in SigNoz
The Qwen Code dashboard template

Troubleshooting Qwen Code Observability

No data in SigNoz

An expired or wrong ingestion key fails silently. The CLI answers normally and exits successfully while the exporter receives a 401, so nothing in the terminal tells you anything is wrong. Test the key directly:

curl -i -X POST "https://ingest.<region>.signoz.cloud/v1/traces" \
  -H "content-type: application/json" \
  -H "signoz-ingestion-key: <your-ingestion-key>" \
  -d '{"resourceSpans":[]}'

A working key returns 200 with {"partialSuccess":{}}. An expired one returns 401 with Expired key.

Telemetry is not being sent at all

Confirm the settings file the CLI actually loaded. A .qwen/settings.json in a different project directory has no effect on the run you are debugging. Check that telemetry.enabled is true and that otlpEndpoint carries no path: the exporter appends /v1/traces itself.

Everything looks like it is failing

Check whether the errors are qwen-code.hook spans. Those report an error by design with no hooks configured and are usually the large majority of error spans. Filter them out with name != 'qwen-code.hook'.

Tool call counts look twice as high as expected

qwen-code.tool.execution is a child of qwen-code.tool and both carry gen_ai.tool.name. Scope tool queries to name = 'qwen-code.tool'.

Token totals come out empty

There is no gen_ai.usage.total_tokens attribute on Qwen Code spans. Sum gen_ai.usage.input_tokens and gen_ai.usage.output_tokens instead.

Grouping by success returns nothing

Filter it with a quoted value instead, and use two filtered queries for a success-versus-failure split.

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

Looking for the Qwen model API rather than the CLI agent? See Qwen observability.

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

Is this page helpful

Last updatedAugust 24, 2026

Edit on GitHub