After the ARMS Python agent instruments a vLLM or SGLang inference engine, it reports spans, span attributes, span events, and metrics for the inference requests that the engine processes. Use this topic to identify the execution stage that each span in a trace represents, what each attribute measures, and how each metric is calculated. When a request slows down or a metric on your dashboard does not match your expectation, these descriptions help you analyze traces, build metric dashboards, and locate performance issues.
Common span conventions
The SpanKind of every span is INTERNAL. The spans that the agent generates express their business semantics through the gen_ai.span.kind attribute, which takes the value LLM, EMBEDDING, or RERANKER. The spans generated by native engine instrumentation do not carry this attribute, so you tell the stage from the span name.
Field name mapping across engines and versions
Fields that carry the same semantics use different names across engines, engine versions, and collection layers. The following table maps the equivalent field names:
Semantics | Field name | Reported by |
Number of input tokens |
| vLLM entry spans and SGLang entry spans |
Number of input tokens |
| vLLM V0 and V1 |
Number of output tokens |
| vLLM entry spans and SGLang entry spans |
Number of output tokens |
| vLLM V0 and V1 |
Number of candidates |
| vLLM entry spans and SGLang entry spans |
Number of candidates |
| vLLM V0 and V1 |
Model name |
| vLLM entry spans and SGLang entry spans |
Model name |
| vLLM V1 |
Model name |
| vLLM V1 engine-side metrics |
Model name |
| vLLM API-layer token metrics and SGLang token consumption metrics |
Input tokens served from the cache |
| vLLM V1 |
Input tokens served from the cache |
| SGLang native request spans |
Time to first token (metric) |
| vLLM metrics |
Time to first token (metric) |
| SGLang metrics |
vLLM spans
Span list
Span name | Produced at | Description |
| OpenAI-compatible API layer | The entry point of a Chat Completions request, |
| OpenAI-compatible API layer | The entry point of a Completions request, |
| OpenAI-compatible API layer | The entry point of an embedding request. |
| OpenAI-compatible API layer | The entry point of a rerank or score request. |
| Inside the engine | The complete lifecycle of one request inside the engine. Produced by both V0 and V1. |
| Inside the engine | The time a request waits in the queue to be scheduled. V1 only, collection granularity of 1 or higher. |
| Inside the engine | The duration of pulling the KV cache from the remote side. Nested under |
| Inside the engine | The duration of the Prefill stage. V1 only, collection granularity of 1 or higher. |
| Inside the engine | The duration of the Decode stage. V1 only, collection granularity of 1 or higher. |
kv_transfer is nested inside wait instead of being placed alongside it. While vLLM waits for the remote KV cache, the request stays in the WAITING_FOR_REMOTE_KVS state, so the transfer duration falls inside the waiting window.
The real queuing time is the wait duration minus the kv_transfer duration.
In a PD-disaggregated deployment, a Prefill node produces only the prefill child span, and a Decode node produces only the decode child span.
Entry span attributes
The entry spans are generated by the general GenAI instrumentation, and their attribute definitions are consistent with the instrumentation of other large language model frameworks.
Attribute | Description |
| The business semantic type. |
| The operation type. |
| The model name specified in the request. |
| The number of candidates requested, which corresponds to the |
| The sampling temperature. |
| The Top-P parameter. |
| The Top-K parameter. |
| The maximum number of tokens to generate. |
| Whether the request is a streaming request. |
| The |
| The request identifier in streaming scenarios. |
| The response ID. |
| The model name returned in the response. |
| The finish reasons. |
| The number of input tokens. |
| The number of output tokens. |
| The total number of tokens. |
| The input content. Controlled by the content collection switch. |
| The output content. Controlled by the content collection switch. |
llm_request span attributes (V0)
The unit of the duration attributes of a V0 engine is seconds.
Attribute | Description |
| The internal request ID of the engine. |
| The model name. |
| The sampling temperature. |
| The Top-P parameter. |
| The maximum number of tokens to generate. |
| The number of candidates. |
| The number of sequences. |
| The number of input tokens. |
| The number of output tokens. |
| The end-to-end duration of the request. |
| The queuing duration. |
| The time to first token. |
| The scheduling duration. Reported only when the engine provides this data. |
| The duration of the model forward computation. Reported only when the engine provides this data. |
| The model execution duration, including the forward computation, cross-worker synchronization, CPU-GPU synchronization, and sampling. Reported only when the engine provides this data. |
llm_request span attributes (V1)
The unit of the duration attributes of a V1 engine is nanoseconds.
Attribute | Description |
| The internal request ID of the engine. |
| The model name. |
| The sampling temperature. |
| The Top-P parameter. |
| The maximum number of tokens to generate. |
| The number of candidates. |
| The number of input tokens. |
| The number of output tokens. |
| The number of input tokens served from the cache without being prefilled again, including local prefix cache hits and remote KV reuse. Reported even when the value is 0, so that you can calculate the cache hit ratio. |
| The end-to-end duration of the request. |
| The queuing duration. |
| The time to first token. |
| The duration of the Prefill stage. |
| The duration of the Decode stage. |
| The total duration of the inference stages (Prefill + Decode). |
| The prompt tokenization duration, which occurs in the frontend process. |
| The cumulative incremental detokenization duration. |
| The total duration of remote KV cache transfers. Reported only when a transfer occurred. |
| The number of times the request was preempted. Reported only when preemption occurred. |
| The EngineCore instance index, which distinguishes engines in a multi-engine deployment. |
| The PD disaggregation role. |
Under PD disaggregation, only the Prefill duration is accurate on a Prefill node (time_in_model_decode is always 0), and only the Decode duration is accurate on a Decode node (time_in_model_prefill is always 0). vLLM does not reset the scheduling timestamp when it preempts a request, so the Prefill, Decode, and Inference durations already include the pauses caused by preemption. gen_ai.request.preemption_count is the evidence for explaining such duration spikes.
Stage child span attributes
The four child spans wait, kv_transfer, prefill, and decode all carry gen_ai.request.id, gen_ai.request.model_name, gen_ai.engine.index, and gen_ai.pd_role. kv_transfer carries the following additional attributes:
Attribute | Description |
| The transfer direction. The value is |
| The number of tokens covered by this transfer, which is the number of tokens resolved on the remote side of the connector. |
| Whether the connector reported a load failure for this request. |
Span events
When collection granularity is 2, span events are appended to llm_request for each scheduling iteration of the engine, which lets you reconstruct the execution process iteration by iteration.
Event name | Description |
| The request enters the waiting state. |
| One Prefill iteration. |
| One Decode iteration. |
| The request is preempted to release KV cache blocks. |
Event attributes include gen_ai.engine.index and the token-level information gen_ai.token.ids, gen_ai.token.texts, gen_ai.token.count, and gen_ai.token.logprobs.
The number of events is proportional to the number of iterations of the request and can easily exceed the OpenTelemetry default limit of 128 events per span, in which case events are dropped. Increase OTEL_SPAN_EVENT_COUNT_LIMIT when necessary.
vLLM metrics
Metric dimensions
The common dimensions carried by vLLM engine-side metrics:
Dimension | Description |
| Always |
| Always |
| The EngineCore instance index. V1 only. |
| The model name. V1 only. |
gen_ai_vllm_request_success carries the additional finished_reason dimension. The API-layer token metrics carry the following dimensions:
Dimension | Description |
| Always |
| Always |
| Always |
| The model name. |
|
|
|
|
Common metrics
V0 and V1 engines both report the following metrics:
Metric name | Type | Unit | Description |
| Counter | Count | Input and output token consumption, distinguished by |
| Counter | Times | The number of engine scheduling iterations. |
| Counter | Times | The number of successfully completed requests. |
| Counter | Seconds | The cumulative time to first token. |
| Counter | Seconds | The cumulative time per output token. |
| Counter | Seconds | The cumulative end-to-end duration of requests. |
V0 metrics
The system status metrics are gauges and reflect the instantaneous value at the collection moment.
Metric name | Type | Unit | Description |
| Gauge | Ratio | GPU KV cache usage. |
| Gauge | Ratio | CPU KV cache usage. |
| Gauge | Count | The number of running sequences. |
| Gauge | Count | The number of waiting sequences. |
| Gauge | Count | The number of swapped-out sequences. |
| Counter | Count | The number of input tokens processed in the iteration. |
| Counter | Count | The number of output tokens generated in the iteration. |
| Counter | Count | The total number of tokens processed in the iteration. |
| Counter | Times | The number of preemptions in the iteration. |
Gauge metrics are reported only by the processes that actually receive engine scheduling statistics. Processes that do not take part in inference, such as pure frontend processes, do not report 0 values, which avoids meaningless flat zero curves in a multi-process deployment.
V1 metrics
Metric name | Type | Unit | Description |
| Gauge | Count | The number of requests in the running batch. |
| Gauge | Count | The number of requests waiting to be processed. |
| Gauge | Ratio | KV cache usage, in the range of [0,1]. |
| Counter | Count | The number of tokens queried in the prefix cache. |
| Counter | Count | The number of tokens that hit the prefix cache. |
| Counter | Times | The cumulative number of engine preemptions. |
| Counter | Count | The number of tokens processed by Prefill. |
| Counter | Count | The number of generated tokens. |
| Counter | Count | The cumulative value of the request |
| Counter | Count | The cumulative value of the request |
| Counter | Seconds | The cumulative duration of requests in the WAITING stage. |
| Counter | Seconds | The cumulative Prefill stage duration of requests. |
| Counter | Seconds | The cumulative Decode stage duration of requests. |
| Counter | Seconds | The cumulative duration of requests in the RUNNING stage. |
The prefix cache hit ratio is calculated as gen_ai_vllm_prefix_cache_hits divided by gen_ai_vllm_prefix_cache_queries.
SGLang spans
Span composition and hierarchy
A trace in an SGLang scenario consists of two kinds of spans: the entry spans that the agent generates at the OpenAI-compatible API layer, and the spans generated by native SGLang instrumentation. The agent injects the context of the entry span into the request header that it sends to the engine, so the native spans hang under the entry span and form one complete trace:
chat {model name} ← agent entry span
└─ Req {first 8 characters of the request ID} ← native request span, one per request
├─ Tokenizer (host:… | pid:…) ← native thread span, frontend process
│ ├─ tokenize
│ └─ api_server_dispatch
└─ Scheduler [TP 0] (host:… | pid:…) ← native thread span, scheduler process
├─ prefill_waiting
├─ prefill_forward
│ └─ chunked_prefill
└─ decode_forward
└─ decode_loopNative instrumentation uses a three-level structure of request, thread, and stage. A request span represents one complete request. A thread span represents each process or thread that takes part in processing the request. A stage span represents one piece of processing logic inside that thread. In a multi-GPU deployment that uses tensor parallelism (TP), pipeline parallelism (PP), or data parallelism (DP), one request has multiple thread spans, one for each scheduler process. Span links are established between contiguous stage spans inside the same thread and between stage spans that connect across processes, which lets you reconstruct the execution order. A span link is not a parent-child relationship.
Entry span list
The entry instrumentation of the agent produces exactly one span for each request and generates no child spans. The stage breakdown inside a request is provided by native instrumentation.
Span name | Description |
| A Chat Completions request, |
| A Completions request, |
Entry span attributes
Request-side attributes:
Attribute | Description |
| Always |
|
|
| The model name specified in the request. |
| The request ID. Reported for Chat streaming scenarios. |
| Whether the request is a streaming request. |
| The sampling temperature. |
| The Top-P parameter. |
| The Top-K parameter. |
| The maximum number of tokens to generate. |
| The number of candidates. |
Response-side attributes:
Attribute | Description |
| The response ID. |
| The model name returned in the response. Reported for non-streaming scenarios. |
| The finish reasons. |
| The number of input tokens. |
| The number of output tokens. |
| The total number of tokens. |
| The number of input tokens served from the cache. |
| The end-to-end duration of the request, in seconds. |
| The estimated number of output tokens in a streaming scenario, calculated as the number of streaming increments multiplied by the |
| The input content. Controlled by the content collection switch. |
| The output content. Controlled by the content collection switch. |
Tool calling attributes (Chat streaming scenarios):
Attribute | Description |
| Whether the request declares tools. |
| Whether a tool call is detected in the response. |
| The number of detected tool calls. |
| The name of tool call |
| The arguments of that tool call. |
Entry spans produce no custom span events. When the content collection policy is set to event, the input and output content is reported as a gen_ai.client.inference.operation.details log event instead of being written to span attributes.
Native instrumentation enablement and collection levels
The agent turns on the native tracing switch of SGLang when the engine starts, so you do not need to add --enable-trace manually. Native spans are reported through the global TracerProvider registered by the agent, so you also do not need to configure --otlp-traces-endpoint, and native spans belong to the same application as the entry spans.
Native instrumentation defines a collection level for each stage span, controlled by the SGLANG_TRACE_LEVEL environment variable. The default value 3 reports all stage spans at levels 1 to 3. A smaller value keeps only the more critical stages, and 0 turns off native instrumentation. The engine also provides the /set_trace_level?level=N operation for dynamic adjustment at runtime. The number of native spans grows with the deployment scale, and one request produces more than 10 spans in a multi-GPU deployment. When trace data volume is high, lower SGLANG_TRACE_LEVEL first.
Request spans and thread spans
The request span is the root span of native instrumentation. It is created and ended in the frontend process, and its name follows the format {role} Req {first 8 characters of the request ID}. The role is prefill or decode under PD disaggregation and is empty in a non-PD deployment.
Attribute | Description |
| The request ID. |
| Always |
| The request correlation identifier under PD disaggregation. It is a hexadecimal string and is reported only in PD scenarios. |
| The request ID. |
| The sampling temperature. |
| The Top-P parameter. |
| The Top-K parameter. |
| The number of candidates. |
| The maximum number of tokens to generate. |
| The model name configured on the server. |
| The finish reasons, as a JSON array string. |
| The number of input tokens. |
| The number of output tokens. Reported for requests other than embedding requests. |
| The number of input tokens served from the cache. |
| The time to first token. |
| The end-to-end duration of the request. |
| The duration from the completion of request dispatch to the first token. |
| The duration from the first token to the end of the request. |
| The duration from the completion of request dispatch to the end of the request. |
The unit of all duration attributes is seconds. The attributes on a request span are filled in only when the request ends normally.
The duration attributes are time differences measured from the perspective of the frontend process, and they are not exactly equivalent to the actual forward computation durations inside the scheduler. For the latter, see the actual durations of the stage spans.
The name of a thread span follows the format {thread label} [TP n] [PP n] [DP n] (host:{host identifier} | pid:{thread ID}). The rank information is appended only when the corresponding value exists. The thread label is Tokenizer, MultiTokenizer-{number}, DP Controller, or Scheduler, and it carries a Prefill or Decode prefix under PD disaggregation. The Detokenizer process has no native instrumentation, so no corresponding thread span appears.
Attribute | Description |
| The unique identifier of the host, which distinguishes processes that share the same PID on different nodes. |
| The thread ID. |
| The thread label. |
| The tensor parallelism rank. Reported when it exists. |
| The pipeline parallelism rank. Reported when it exists. |
| The data parallelism rank. Reported when it exists. |
When a request terminates abnormally, the error status and the end reason are recorded on the thread span: its status is set to ERROR and the attributes related to the end reason are appended. The request span itself is not marked as an error. When you investigate a failed request, check the status of the thread spans.
Stage span list
In the following tables, the Level column corresponds to SGLANG_TRACE_LEVEL. A span whose level value is larger than the configured value is not produced.
Common stages:
Span name | Level | Producing process | Description |
| 1 | Frontend | The prompt tokenization duration. |
| 2 | Frontend | The duration of dispatching the request from the frontend to the scheduler. |
| 2 | DP Controller | The duration of the data parallelism controller dispatching the request. Produced only when DP is enabled. |
| 2 | Scheduler | The processing duration from the moment the request enters the scheduler to the moment it enters the waiting queue. Only in a non-PD-disaggregated deployment. |
| 1 | Scheduler | The time the request waits in the queue until it is scheduled for Prefill. |
| 1 | Scheduler | The duration of the Prefill forward computation. |
| 3 | Scheduler | The Prefill duration of one chunk. Nested under |
| 1 | Scheduler | The wait between the completion of Prefill and the scheduling of the first Decode. |
| 1 | Scheduler | The overall duration of the Decode stage. |
| 3 | Scheduler | The duration of one Decode iteration. Nested under |
decode_forward has no independent end point. It is closed together with the thread when the request wraps up, so its duration covers the whole interval from the first Decode scheduling to the end of the request.
Speculative decoding stages, produced when speculative decoding is enabled and nested under the forward spans:
Span name | Level | Description |
| 2 | The duration of the draft model generating candidate tokens. |
| 2 | The duration of the target model verifying the draft tokens. |
| 3 | The duration of the extend stage of the draft model. |
Pipeline parallelism stages:
Span name | Level | Description |
| 4 | The duration of CPU-side batch processing under pipeline parallelism. Level 4 is higher than the default value 3, so this span is produced only when you explicitly set |
Additional stages in a PD-disaggregated deployment, Prefill node:
Span name | Level | Description |
| 1 | The preparation duration after the Prefill node receives the request. |
| 1 | The duration of establishing the transfer connection with the Decode node. |
| 1 | The duration of transferring the KV cache to the Decode node. |
Additional stages in a PD-disaggregated deployment, Decode node:
Span name | Level | Description |
| 1 | The preparation duration after the Decode node receives the request. |
| 1 | The duration of establishing the transfer connection with the Prefill node. |
| 1 | The duration of waiting for the KV cache transfer to complete. |
| 3 | The duration of the Decode node completing the output of the Prefill stage. |
Under PD disaggregation, Prefill and Decode each have an independent request span, which forms two independent traces. The two traces are correlated as one request through the bootstrap_room attribute on the request spans. On a Decode node in a PD-disaggregated deployment, decode_waiting changes its meaning to the queuing between the completion of the KV cache transfer and the start of the forward computation, which differs from its meaning in a non-PD deployment.
Stage span attributes and span events
Stage spans carry no custom attributes by default, with the following three exceptions:
Span name | Attribute | Description |
|
| The current Decode iteration number. |
|
| The number of draft tokens that pass this verification. |
|
| The micro-batch number of pipeline parallelism. |
Native instrumentation produces two kinds of span events:
Event name | Level | Attributes | Description |
| 1 | None | Recorded when a request is rolled back and requeued because of insufficient resources. |
| 3 |
| Recorded when a request is placed into a batch. |
An event is attributed by timestamp to the stage span whose interval covers that moment. An event that falls outside every stage interval is attached to the thread span, so events with the same name can be attached at different positions in different requests.
SGLang metrics
Metric dimensions
The dimensions carried by engine-side metrics, which are scheduler and frontend statistics:
Dimension | Description |
| Always |
| Always |
| Always |
Token consumption metrics carry the additional dimensions modelName, spanKind, and usageType (input or output).
Metric list
Metric name | Type | Unit | Description |
| Counter | Count | Input and output token consumption, distinguished by |
| Counter | Count | A snapshot of the number of running requests. |
| Counter | Count | A snapshot of the number of requests in the queue. |
| Counter | Count | A snapshot of the number of tokens currently in use. |
| Counter | Ratio | A snapshot of the KV cache token usage. |
| Counter | Tokens/s | A snapshot of the generation throughput. |
| Counter | Ratio | A snapshot of the cache hit ratio. Reported only when the engine provides this field. |
| Counter | Count | The accept length of speculative decoding. |
| Counter | Times | The number of statistical reports, which is used to calculate the average of the preceding snapshot metrics. |
| Counter | Count | The cumulative number of input tokens. |
| Counter | Count | The cumulative number of output tokens. |
| Counter | Count | The cumulative number of input tokens served from the cache. |
| Counter | Times | The cumulative number of requests. |
| Counter | Seconds | The cumulative time to first token. |
| Counter | Seconds | The cumulative time per output token. |
| Counter | Seconds | The cumulative inter-token latency. |
| Counter | Seconds | The cumulative end-to-end duration of requests. |
The system status metrics of SGLang are reported as counters, but semantically each value is an instantaneous snapshot of one statistical period. On a dashboard, average them within the period together with sglang_log_count instead of reading the cumulative value directly.
gen_ai_server_time_per_output_token is the end-to-end duration divided by the number of output tokens, so it is an average. To observe the real interval between tokens, use sglang_inter_token_latency_seconds.