Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions packages/traceloop-sdk/tests/test_sdk_initialization.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import json
import os
import warnings
import pytest
from unittest.mock import patch
from openai import OpenAI
from traceloop.sdk import Traceloop
from traceloop.sdk.config import is_content_tracing_enabled
from traceloop.sdk.decorators import workflow
from traceloop.sdk.tracing.tracing import TracerWrapper
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, BatchSpanProcessor
Expand Down Expand Up @@ -358,3 +360,87 @@ def probe():
del TracerWrapper.instance
if saved_instance is not None:
TracerWrapper.instance = saved_instance


@pytest.fixture
def isolated_trace_content_env():
"""Save/restore TRACELOOP_TRACE_CONTENT so trace_content tests don't leak.

Also clears the var before yielding so tests start from a known-unset state —
otherwise a CI env that pre-sets TRACELOOP_TRACE_CONTENT could mask bugs in
tests that exercise the "env not set" default path."""
saved = os.environ.pop("TRACELOOP_TRACE_CONTENT", None)
yield
if saved is None:
os.environ.pop("TRACELOOP_TRACE_CONTENT", None)
else:
os.environ["TRACELOOP_TRACE_CONTENT"] = saved


def test_trace_content_false_disables_content_tracing(
isolated_tracer_wrapper, isolated_trace_content_env
):
"""trace_content=False must disable content capture regardless of how the env was set."""
os.environ["TRACELOOP_TRACE_CONTENT"] = "true"

Traceloop.init(
exporter=InMemorySpanExporter(),
disable_batch=True,
trace_content=False,
)

assert is_content_tracing_enabled() is False
assert os.environ["TRACELOOP_TRACE_CONTENT"] == "false"


def test_trace_content_true_overrides_env(
isolated_tracer_wrapper, isolated_trace_content_env
):
"""An explicit trace_content=True must win over an env that disabled it —
otherwise the new arg would be weaker than the env var it is meant to expose."""
os.environ["TRACELOOP_TRACE_CONTENT"] = "false"

Traceloop.init(
exporter=InMemorySpanExporter(),
disable_batch=True,
trace_content=True,
)

assert is_content_tracing_enabled() is True
assert os.environ["TRACELOOP_TRACE_CONTENT"] == "true"


def test_trace_content_none_honors_env(
isolated_tracer_wrapper, isolated_trace_content_env
):
"""When trace_content is omitted, the env var stays authoritative — existing
deployments that rely on TRACELOOP_TRACE_CONTENT must not change behavior."""
os.environ["TRACELOOP_TRACE_CONTENT"] = "false"

Traceloop.init(exporter=InMemorySpanExporter(), disable_batch=True)

assert is_content_tracing_enabled() is False
assert os.environ["TRACELOOP_TRACE_CONTENT"] == "false"


def test_trace_content_override_is_sticky_across_inits(
isolated_tracer_wrapper, isolated_trace_content_env
):
"""An explicit trace_content setting must persist across subsequent init()
calls that omit the arg. Once the env has been overwritten, trace_content=None
cannot restore the pre-init env value — the most recent explicit setting wins
until something external resets the env. This pins the documented behavior so
a future "save/restore env on init exit" refactor would force a docs update."""
os.environ["TRACELOOP_TRACE_CONTENT"] = "false"

Traceloop.init(
exporter=InMemorySpanExporter(),
disable_batch=True,
trace_content=True,
)
assert os.environ["TRACELOOP_TRACE_CONTENT"] == "true"

Traceloop.init(exporter=InMemorySpanExporter(), disable_batch=True)

assert is_content_tracing_enabled() is True
assert os.environ["TRACELOOP_TRACE_CONTENT"] == "true"
28 changes: 28 additions & 0 deletions packages/traceloop-sdk/traceloop/sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand All @@ -88,6 +89,30 @@ 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 are captured by the
bundled instrumentations. If ``None`` (default), the value of the
``TRACELOOP_TRACE_CONTENT`` environment variable is honored (defaults
to enabled). If ``True`` or ``False``, the argument explicitly overrides
the environment variable for the lifetime of the process. Use
``False`` to disable prompt/completion capture when sensitive content
must not leave the host.

Notes:
* This is implemented by writing ``TRACELOOP_TRACE_CONTENT`` into
``os.environ``, so child processes and any other code reading
that variable will observe the override.
* The override is sticky: a subsequent ``Traceloop.init()`` call
with ``trace_content=None`` does not restore the previous
env-driven value — the most recent explicit ``True``/``False``
keeps winning until the env var is changed externally.
* Per-span enablement via the ``override_enable_content_tracing``
OTel context value still works when ``trace_content=False`` —
instrumentations treat env and context as OR, so individual
spans can opt back in while the global default stays off.
* Not applied when ``enabled=False`` or when tracing is disabled
via ``TRACELOOP_TRACING_ENABLED``: ``init()`` returns early
before the override would take effect, so the env var is left
untouched in those no-op paths.
"""
if use_attributes is not None and use_legacy_attributes is not None:
raise TypeError(
Expand Down Expand Up @@ -125,6 +150,9 @@ def init(
print(Fore.YELLOW + "Tracing is disabled" + Fore.RESET)
return

if trace_content is not None:
os.environ["TRACELOOP_TRACE_CONTENT"] = "true" if trace_content else "false"

enable_content_tracing = is_content_tracing_enabled()

if exporter and processor:
Expand Down