From 37bbc26f50df6a7f0807128f044396ebbe3662d3 Mon Sep 17 00:00:00 2001 From: Sage Date: Mon, 20 Jul 2026 17:12:37 +0800 Subject: [PATCH] feat(sdk): add trace_content parameter to Traceloop.init() Add a parameter to that controls whether sensitive content (prompts, completions) is sent to Traceloop. When explicitly passed, the parameter takes precedence over the environment variable. When omitted, it falls back to the env var (which defaults to "true"), preserving backward compatibility. Closes #137 --- .../tests/test_sdk_initialization.py | 48 +++++++++++++++++++ .../traceloop-sdk/traceloop/sdk/__init__.py | 12 ++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/packages/traceloop-sdk/tests/test_sdk_initialization.py b/packages/traceloop-sdk/tests/test_sdk_initialization.py index 18ef5d7d0f..9f41bb0e01 100644 --- a/packages/traceloop-sdk/tests/test_sdk_initialization.py +++ b/packages/traceloop-sdk/tests/test_sdk_initialization.py @@ -358,3 +358,51 @@ def probe(): del TracerWrapper.instance if saved_instance is not None: TracerWrapper.instance = saved_instance + + +def test_trace_content_default_true(isolated_tracer_wrapper): + """trace_content defaults to True when not passed, equivalent to the + default env var behaviour.""" + Traceloop.init(exporter=InMemorySpanExporter(), disable_batch=True) + + assert TracerWrapper.enable_content_tracing is True + + +def test_trace_content_false_disables_content(isolated_tracer_wrapper): + """Explicit trace_content=False must disable content tracing.""" + Traceloop.init( + exporter=InMemorySpanExporter(), + disable_batch=True, + trace_content=False, + ) + + assert TracerWrapper.enable_content_tracing is False + + +def test_trace_content_env_var_still_works(isolated_tracer_wrapper): + """When trace_content is not passed, the TRACELOOP_TRACE_CONTENT env var + must still be honoured.""" + import os + + os.environ["TRACELOOP_TRACE_CONTENT"] = "false" + try: + Traceloop.init(exporter=InMemorySpanExporter(), disable_batch=True) + assert TracerWrapper.enable_content_tracing is False + finally: + os.environ.pop("TRACELOOP_TRACE_CONTENT", None) + + +def test_trace_content_overrides_env_var(isolated_tracer_wrapper): + """Explicit trace_content=False must override TRACELOOP_TRACE_CONTENT=true.""" + import os + + os.environ["TRACELOOP_TRACE_CONTENT"] = "true" + try: + Traceloop.init( + exporter=InMemorySpanExporter(), + disable_batch=True, + trace_content=False, + ) + assert TracerWrapper.enable_content_tracing is False + finally: + os.environ.pop("TRACELOOP_TRACE_CONTENT", None) diff --git a/packages/traceloop-sdk/traceloop/sdk/__init__.py b/packages/traceloop-sdk/traceloop/sdk/__init__.py index 6663429d99..c93041ecb1 100644 --- a/packages/traceloop-sdk/traceloop/sdk/__init__.py +++ b/packages/traceloop-sdk/traceloop/sdk/__init__.py @@ -73,6 +73,7 @@ def init( endpoint_is_traceloop: Optional[bool] = False, use_attributes: Optional[bool] = None, use_legacy_attributes: Optional[bool] = None, + trace_content: Optional[bool] = None, ) -> Optional[Client]: """Initialize Traceloop tracing, metrics, and instrumentation. @@ -88,6 +89,12 @@ def init( events have nowhere to go and no prompt/completion data will be recorded. use_legacy_attributes: Deprecated alias for ``use_attributes``. Will be removed in a future release. + trace_content: Controls whether prompts, completions, and other + sensitive content are sent to Traceloop. When ``False``, only + metadata (token counts, latency, model name, etc.) is traced + and the actual content is omitted. Defaults to ``True``. + Falls back to the ``TRACELOOP_TRACE_CONTENT`` environment + variable if not provided. """ if use_attributes is not None and use_legacy_attributes is not None: raise TypeError( @@ -125,7 +132,10 @@ def init( print(Fore.YELLOW + "Tracing is disabled" + Fore.RESET) return - enable_content_tracing = is_content_tracing_enabled() + if trace_content is not None: + enable_content_tracing = trace_content + else: + enable_content_tracing = is_content_tracing_enabled() if exporter and processor: warnings.warn(