feat: support custom OTLP trace service name (#35802)

This commit is contained in:
ymren
2026-09-16 22:37:42 +08:00
committed by GitHub
parent 00a9a81b67
commit cc171fbad0
10 changed files with 74 additions and 8 deletions
@@ -589,6 +589,7 @@ class ServerArgs(DisaggServerArgsMixin):
# Tracing
enable_trace: bool = False
otlp_traces_endpoint: str = "localhost:4317"
otlp_service_name: str | None = None
# SGLang backend for encoder stage
srt_encoder_url: str | None = None
@@ -2893,6 +2894,13 @@ class ServerArgs(DisaggServerArgsMixin):
default=ServerArgs.otlp_traces_endpoint,
help="OTLP collector endpoint when --enable-trace is set. Format: <host>:<port>",
)
parser.add_argument(
"--otlp-service-name",
type=str,
default=ServerArgs.otlp_service_name,
help="Service name for OTLP traces (displayed as 'service.name' in trace backends). "
"If unset, falls back to the OTEL_SERVICE_NAME env var, then to 'sglang-diffusion'.",
)
parser.add_argument(
"--log-requests",
action="store_true",
@@ -7,6 +7,7 @@ start/end bookkeeping.
from __future__ import annotations
import os
from contextlib import contextmanager
from dataclasses import dataclass
@@ -37,10 +38,17 @@ def init_diffusion_tracing(server_args, thread_label: str):
trace_set_thread_info,
)
# Priority: --otlp-service-name > OTEL_SERVICE_NAME > "sglang-diffusion"
service_name = (
server_args.otlp_service_name
or os.getenv("OTEL_SERVICE_NAME")
or "sglang-diffusion"
)
# srt owns TraceReqContext and filters spans through its trace_modules list
process_tracing_init(
server_args.otlp_traces_endpoint,
"sglang-diffusion",
service_name,
trace_modules=DIFFUSION_TRACE_MODULE,
)
trace_set_thread_info(thread_label)
@@ -177,6 +177,11 @@ class Observability(msgspec.Struct):
str,
"Config opentelemetry collector endpoint if --enable-trace is set. format: <ip>:<port>",
] = "localhost:4317"
otlp_service_name: A[
Optional[str],
"Service name for OTLP traces (displayed as 'service.name' in trace backends). "
"If unset, falls back to the OTEL_SERVICE_NAME env var, then to 'sglang'.",
] = None
# RequestMetricsExporter configuration
export_metrics_to_file: A[
bool,
@@ -1775,7 +1775,7 @@ def launch_local_runtime(server_args: ServerArgs) -> EncoderRuntime:
if get_observability().enable_trace:
process_tracing_init(
get_observability().otlp_traces_endpoint,
"sglang",
get_observability().otlp_service_name,
trace_modules=get_observability().trace_modules,
)
trace_set_thread_info("Encoder")
+1 -1
View File
@@ -329,7 +329,7 @@ class Engine(EngineScoreMixin, EngineBase):
if get_observability().enable_trace:
process_tracing_init(
get_observability().otlp_traces_endpoint,
"sglang",
get_observability().otlp_service_name,
trace_modules=get_observability().trace_modules,
)
thread_label = "Tokenizer"
+1 -1
View File
@@ -293,7 +293,7 @@ async def lifespan(fast_api_app: FastAPI):
if get_observability().enable_trace:
process_tracing_init(
get_observability().otlp_traces_endpoint,
"sglang",
get_observability().otlp_service_name,
trace_modules=get_observability().trace_modules,
)
if get_disagg().disaggregation_mode == "prefill":
@@ -839,7 +839,7 @@ def run_data_parallel_controller_process(
if get_observability().enable_trace:
process_tracing_init(
get_observability().otlp_traces_endpoint,
"sglang",
get_observability().otlp_service_name,
trace_modules=get_observability().trace_modules,
)
thread_label = "DP Controller"
+1 -1
View File
@@ -5852,7 +5852,7 @@ def run_scheduler_process(
if get_observability().enable_trace:
process_tracing_init(
get_observability().otlp_traces_endpoint,
"sglang",
get_observability().otlp_service_name,
trace_modules=get_observability().trace_modules,
)
thread_label = "Scheduler"
+5 -2
View File
@@ -227,9 +227,12 @@ def process_tracing_init(
)
try:
# Priority: explicit server_name > OTEL_SERVICE_NAME > "sglang"
service_name = server_name or os.getenv("OTEL_SERVICE_NAME", "sglang")
resource = Resource.create(
attributes={
SERVICE_NAME: server_name,
SERVICE_NAME: service_name,
}
)
tracer_provider = TracerProvider(
@@ -259,7 +262,7 @@ def process_tracing_init(
if envs.SGLANG_TRACE_ASYNC.get():
from sglang.srt.observability.trace_async import start_trace_exporter
start_trace_exporter(otlp_endpoint, server_name, trace_modules=trace_modules)
start_trace_exporter(otlp_endpoint, service_name, trace_modules=trace_modules)
def get_global_tracing_enabled():
@@ -175,6 +175,48 @@ class TestProcessTracingInit(unittest.TestCase):
finally:
mod.opentelemetry_imported = orig
@unittest.skipIf(not _has_otel, "OpenTelemetry not installed")
def test_service_name_priority_explicit(self):
"""Service name priority: explicit parameter > env var > default."""
with patch.dict(os.environ, {"OTEL_SERVICE_NAME": "from-env"}):
with patch.object(mod, "TracerProvider"):
with patch.object(mod, "Resource") as mock_resource:
process_tracing_init("localhost:4317", "explicit-name")
# Verify Resource.create was called with the explicit name
mock_resource.create.assert_called_once()
call_kwargs = mock_resource.create.call_args[1]
self.assertEqual(
call_kwargs["attributes"][mod.SERVICE_NAME], "explicit-name"
)
@unittest.skipIf(not _has_otel, "OpenTelemetry not installed")
def test_service_name_priority_env_var(self):
"""Service name falls back to OTEL_SERVICE_NAME when explicit is None."""
with patch.dict(os.environ, {"OTEL_SERVICE_NAME": "from-env"}):
with patch.object(mod, "TracerProvider"):
with patch.object(mod, "Resource") as mock_resource:
process_tracing_init("localhost:4317", None)
# Verify Resource.create was called with env var value
mock_resource.create.assert_called_once()
call_kwargs = mock_resource.create.call_args[1]
self.assertEqual(
call_kwargs["attributes"][mod.SERVICE_NAME], "from-env"
)
@unittest.skipIf(not _has_otel, "OpenTelemetry not installed")
def test_service_name_priority_default(self):
"""Service name falls back to 'sglang' when both explicit and env are unset."""
with patch.dict(os.environ, {}, clear=True):
with patch.object(mod, "TracerProvider"):
with patch.object(mod, "Resource") as mock_resource:
process_tracing_init("localhost:4317", None)
# Verify Resource.create was called with default value
mock_resource.create.assert_called_once()
call_kwargs = mock_resource.create.call_args[1]
self.assertEqual(
call_kwargs["attributes"][mod.SERVICE_NAME], "sglang"
)
class TestTraceReqContextDisabled(unittest.TestCase):
def setUp(self):