SGLang Tracing: Improve root span attributes (#17008)

Signed-off-by: zhanghaotong <zhanghaotong.zht@antgroup.com>
This commit is contained in:
Haotong Zhang
2026-01-30 16:02:05 +08:00
committed by GitHub
parent a16aba8340
commit c8dc543dc5
2 changed files with 121 additions and 1 deletions

View File

@@ -16,6 +16,7 @@
import asyncio
import copy
import dataclasses
import json
import logging
import os
import pickle
@@ -90,6 +91,7 @@ from sglang.srt.server_args import (
)
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
from sglang.srt.tracing.trace import (
SpanAttributes,
extract_trace_headers,
trace_get_proc_propagate_context,
trace_req_finish,
@@ -1593,7 +1595,11 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
if self.enable_metrics:
self._calculate_timing_metrics(meta_info, state, recv_obj, i)
trace_req_finish(rid, ts=int(state.finished_time * 1e9))
trace_req_finish(
rid,
ts=int(state.finished_time * 1e9),
attrs=self.convert_to_span_attrs(state, recv_obj, i),
)
del self.rid_to_state[rid]
@@ -2284,6 +2290,98 @@ class TokenizerManager(TokenizerCommunicatorMixin, TokenizerManagerMultiItemMixi
):
self.mm_receiver.send_encode_request(obj)
def convert_to_span_attrs(
self,
state: ReqState,
recv_obj: Union[
BatchStrOutput,
BatchEmbeddingOutput,
BatchMultimodalOutput,
BatchTokenIDOutput,
],
i: int,
) -> Dict[str, Any]:
"""Convert attributes to span attributes."""
span_attrs = {}
if not self.enable_trace:
return span_attrs
# Token usage attributes
span_attrs[SpanAttributes.GEN_AI_USAGE_COMPLETION_TOKENS] = (
recv_obj.completion_tokens[i]
)
span_attrs[SpanAttributes.GEN_AI_USAGE_PROMPT_TOKENS] = recv_obj.prompt_tokens[
i
]
span_attrs[SpanAttributes.GEN_AI_USAGE_CACHED_TOKENS] = recv_obj.cached_tokens[
i
]
# Request identifiers
span_attrs[SpanAttributes.GEN_AI_REQUEST_ID] = (
str(state.obj.rid) if state.obj.rid else None
)
# Sampling parameters
sampling_params = state.obj.sampling_params or {}
if max_new_tokens := sampling_params.get("max_new_tokens"):
span_attrs[SpanAttributes.GEN_AI_REQUEST_MAX_TOKENS] = max_new_tokens
if top_p := sampling_params.get("top_p"):
span_attrs[SpanAttributes.GEN_AI_REQUEST_TOP_P] = top_p
if temperature := sampling_params.get("temperature"):
span_attrs[SpanAttributes.GEN_AI_REQUEST_TEMPERATURE] = temperature
if top_k := sampling_params.get("top_k"):
span_attrs[SpanAttributes.GEN_AI_REQUEST_TOP_K] = top_k
if n := sampling_params.get("n"):
span_attrs[SpanAttributes.GEN_AI_REQUEST_N] = n
# Response attributes
span_attrs[SpanAttributes.GEN_AI_RESPONSE_MODEL] = self.served_model_name
finish_reason = (
recv_obj.finished_reasons[i].get("type")
if recv_obj.finished_reasons[i]
else None
)
if finish_reason:
span_attrs[SpanAttributes.GEN_AI_RESPONSE_FINISH_REASONS] = json.dumps(
[finish_reason]
)
# Latency attributes
if state.first_token_time and state.created_time:
span_attrs[SpanAttributes.GEN_AI_LATENCY_TIME_TO_FIRST_TOKEN] = (
state.first_token_time - state.created_time
)
if state.finished_time and state.created_time:
span_attrs[SpanAttributes.GEN_AI_LATENCY_E2E] = (
state.finished_time - state.created_time
)
if state.first_token_time_perf and state.finished_time_perf:
span_attrs[SpanAttributes.GEN_AI_LATENCY_TIME_IN_MODEL_DECODE] = (
state.finished_time_perf - state.first_token_time_perf
)
if state.request_sent_to_scheduler_ts and state.finished_time:
span_attrs[SpanAttributes.GEN_AI_LATENCY_TIME_IN_MODEL_INFERENCE] = (
state.finished_time - state.request_sent_to_scheduler_ts
)
if state.request_sent_to_scheduler_ts and state.first_token_time:
span_attrs[SpanAttributes.GEN_AI_LATENCY_TIME_IN_MODEL_PREFILL] = (
state.first_token_time - state.request_sent_to_scheduler_ts
)
return span_attrs
class ServerStatus(Enum):
Up = "Up"

View File

@@ -737,3 +737,25 @@ def trace_event_batch(
for req in reqs:
trace_event(name, req.rid, ts=ts, attrs=_attrs)
class SpanAttributes:
# Attribute names copied from here to avoid version conflicts:
# https://github.com/open-telemetry/semantic-conventions/blob/main/docs/gen-ai/gen-ai-spans.md
GEN_AI_USAGE_COMPLETION_TOKENS = "gen_ai.usage.completion_tokens"
GEN_AI_USAGE_PROMPT_TOKENS = "gen_ai.usage.prompt_tokens"
GEN_AI_USAGE_CACHED_TOKENS = "gen_ai.usage.cached_tokens"
GEN_AI_REQUEST_MAX_TOKENS = "gen_ai.request.max_tokens"
GEN_AI_REQUEST_TOP_P = "gen_ai.request.top_p"
GEN_AI_REQUEST_TOP_K = "gen_ai.request.top_k"
GEN_AI_REQUEST_TEMPERATURE = "gen_ai.request.temperature"
GEN_AI_RESPONSE_MODEL = "gen_ai.response.model"
GEN_AI_RESPONSE_FINISH_REASONS = "gen_ai.response.finish_reasons"
GEN_AI_REQUEST_ID = "gen_ai.request.id"
GEN_AI_REQUEST_N = "gen_ai.request.n"
GEN_AI_LATENCY_TIME_IN_QUEUE = "gen_ai.latency.time_in_queue"
GEN_AI_LATENCY_TIME_TO_FIRST_TOKEN = "gen_ai.latency.time_to_first_token"
GEN_AI_LATENCY_E2E = "gen_ai.latency.e2e"
GEN_AI_LATENCY_TIME_IN_MODEL_PREFILL = "gen_ai.latency.time_in_model_prefill"
GEN_AI_LATENCY_TIME_IN_MODEL_DECODE = "gen_ai.latency.time_in_model_decode"
GEN_AI_LATENCY_TIME_IN_MODEL_INFERENCE = "gen_ai.latency.time_in_model_inference"