diff --git a/packages/opentelemetry-instrumentation-agno/opentelemetry/instrumentation/agno/utils.py b/packages/opentelemetry-instrumentation-agno/opentelemetry/instrumentation/agno/utils.py index 3b12dadcf4..04d2832c38 100644 --- a/packages/opentelemetry-instrumentation-agno/opentelemetry/instrumentation/agno/utils.py +++ b/packages/opentelemetry-instrumentation-agno/opentelemetry/instrumentation/agno/utils.py @@ -2,6 +2,7 @@ from typing import Any from functools import wraps import asyncio +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.trace import Span logger = logging.getLogger(__name__) @@ -38,9 +39,3 @@ def set_span_attribute(span: Span, name: str, value: Any) -> None: set_span_attribute(span, f"{name}.{index}", item) else: span.set_attribute(name, value) - - -def should_send_prompts() -> bool: - """Check if prompts should be sent based on environment variables.""" - import os - return os.getenv("TRACELOOP_TRACE_CONTENT", "true").lower() == "true" diff --git a/packages/opentelemetry-instrumentation-agno/pyproject.toml b/packages/opentelemetry-instrumentation-agno/pyproject.toml index 6a823e0c32..4b0f6b9365 100644 --- a/packages/opentelemetry-instrumentation-agno/pyproject.toml +++ b/packages/opentelemetry-instrumentation-agno/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.28.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -76,4 +76,5 @@ select = ["E", "F", "W"] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] [tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } opentelemetry-instrumentation-openai = { path = "../opentelemetry-instrumentation-openai", editable = true } diff --git a/packages/opentelemetry-instrumentation-alephalpha/opentelemetry/instrumentation/alephalpha/__init__.py b/packages/opentelemetry-instrumentation-alephalpha/opentelemetry/instrumentation/alephalpha/__init__.py index c05d50f786..4bd70edbcc 100644 --- a/packages/opentelemetry-instrumentation-alephalpha/opentelemetry/instrumentation/alephalpha/__init__.py +++ b/packages/opentelemetry-instrumentation-alephalpha/opentelemetry/instrumentation/alephalpha/__init__.py @@ -1,7 +1,6 @@ """OpenTelemetry Aleph Alpha instrumentation""" import logging -import os from typing import Collection, List, Optional, Union from opentelemetry import context as context_api @@ -31,6 +30,7 @@ LLMRequestTypeValues, SpanAttributes, ) +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.trace import SpanKind, Tracer, get_tracer from opentelemetry.trace.span import Span from opentelemetry.trace.status import Status, StatusCode @@ -47,14 +47,6 @@ }, ] -TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" - - -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - def should_emit_events(): return not Config.use_legacy_attributes diff --git a/packages/opentelemetry-instrumentation-alephalpha/pyproject.toml b/packages/opentelemetry-instrumentation-alephalpha/pyproject.toml index 9f35d1eeeb..421f3f0d17 100644 --- a/packages/opentelemetry-instrumentation-alephalpha/pyproject.toml +++ b/packages/opentelemetry-instrumentation-alephalpha/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py b/packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py index a060031017..7b344427d1 100644 --- a/packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py +++ b/packages/opentelemetry-instrumentation-anthropic/opentelemetry/instrumentation/anthropic/utils.py @@ -2,12 +2,11 @@ import inspect import json import logging -import os import threading import traceback from importlib.metadata import version -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.anthropic.config import Config from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -27,12 +26,6 @@ def set_span_attribute(span, name, value): return -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-anthropic/pyproject.toml b/packages/opentelemetry-instrumentation-anthropic/pyproject.toml index 34d8351bc6..e4ca01f168 100644 --- a/packages/opentelemetry-instrumentation-anthropic/pyproject.toml +++ b/packages/opentelemetry-instrumentation-anthropic/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/utils.py b/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/utils.py index ec4a8ef993..9788bdc1f6 100644 --- a/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/utils.py +++ b/packages/opentelemetry-instrumentation-bedrock/opentelemetry/instrumentation/bedrock/utils.py @@ -1,8 +1,7 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.bedrock.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" @@ -33,12 +32,6 @@ def wrapper(*args, **kwargs): return wrapper -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-bedrock/pyproject.toml b/packages/opentelemetry-instrumentation-bedrock/pyproject.toml index 2b08c1ecf0..32a770925c 100644 --- a/packages/opentelemetry-instrumentation-bedrock/pyproject.toml +++ b/packages/opentelemetry-instrumentation-bedrock/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -77,3 +77,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/utils.py b/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/utils.py index 2ed13915cd..cc7d1abab0 100644 --- a/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/utils.py +++ b/packages/opentelemetry-instrumentation-cohere/opentelemetry/instrumentation/cohere/utils.py @@ -1,10 +1,9 @@ import dataclasses import json import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.cohere.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" @@ -35,12 +34,6 @@ def wrapper(*args, **kwargs): return wrapper -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-cohere/pyproject.toml b/packages/opentelemetry-instrumentation-cohere/pyproject.toml index 5840810aaa..f93bc86270 100644 --- a/packages/opentelemetry-instrumentation-cohere/pyproject.toml +++ b/packages/opentelemetry-instrumentation-cohere/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/utils.py b/packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/utils.py index d76c620102..4e2661ad45 100644 --- a/packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/utils.py +++ b/packages/opentelemetry-instrumentation-google-generativeai/opentelemetry/instrumentation/google_generativeai/utils.py @@ -3,10 +3,9 @@ import importlib import importlib.util import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.google_generativeai.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" @@ -54,12 +53,6 @@ def wrapper(*args, **kwargs): return wrapper -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-google-generativeai/pyproject.toml b/packages/opentelemetry-instrumentation-google-generativeai/pyproject.toml index 0f5fd32c0e..06a3f9136c 100644 --- a/packages/opentelemetry-instrumentation-google-generativeai/pyproject.toml +++ b/packages/opentelemetry-instrumentation-google-generativeai/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-groq/opentelemetry/instrumentation/groq/utils.py b/packages/opentelemetry-instrumentation-groq/opentelemetry/instrumentation/groq/utils.py index e1f01b60ec..557624c692 100644 --- a/packages/opentelemetry-instrumentation-groq/opentelemetry/instrumentation/groq/utils.py +++ b/packages/opentelemetry-instrumentation-groq/opentelemetry/instrumentation/groq/utils.py @@ -1,9 +1,8 @@ import logging -import os import traceback from importlib.metadata import version -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.groq.config import Config from opentelemetry.semconv._incubating.attributes import ( gen_ai_attributes as GenAIAttributes, @@ -19,12 +18,6 @@ def set_span_attribute(span, name, value): span.set_attribute(name, value) -def should_send_prompts(): - return (os.getenv(TRACELOOP_TRACE_CONTENT) or "true").lower() == "true" or context_api.get_value( - "override_enable_content_tracing" - ) - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-groq/pyproject.toml b/packages/opentelemetry-instrumentation-groq/pyproject.toml index 91883fa91b..33b30c1cf2 100644 --- a/packages/opentelemetry-instrumentation-groq/pyproject.toml +++ b/packages/opentelemetry-instrumentation-groq/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-haystack/opentelemetry/instrumentation/haystack/utils.py b/packages/opentelemetry-instrumentation-haystack/opentelemetry/instrumentation/haystack/utils.py index cbb3b8a437..9b178134f1 100644 --- a/packages/opentelemetry-instrumentation-haystack/opentelemetry/instrumentation/haystack/utils.py +++ b/packages/opentelemetry-instrumentation-haystack/opentelemetry/instrumentation/haystack/utils.py @@ -1,10 +1,9 @@ import dataclasses import json import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.haystack.config import Config from opentelemetry.semconv_ai import SpanAttributes @@ -18,12 +17,6 @@ def default(self, o): return super().default(o) -def should_send_prompts(): - return ( - os.getenv("TRACELOOP_TRACE_CONTENT") or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-haystack/pyproject.toml b/packages/opentelemetry-instrumentation-haystack/pyproject.toml index 5039cacafe..5fb1d6acbe 100644 --- a/packages/opentelemetry-instrumentation-haystack/pyproject.toml +++ b/packages/opentelemetry-instrumentation-haystack/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-langchain/opentelemetry/instrumentation/langchain/utils.py b/packages/opentelemetry-instrumentation-langchain/opentelemetry/instrumentation/langchain/utils.py index 77449279b7..93a9c527f8 100644 --- a/packages/opentelemetry-instrumentation-langchain/opentelemetry/instrumentation/langchain/utils.py +++ b/packages/opentelemetry-instrumentation-langchain/opentelemetry/instrumentation/langchain/utils.py @@ -3,10 +3,9 @@ import importlib.util import json import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry._logs import Logger from opentelemetry.instrumentation.langchain.config import Config from opentelemetry.semconv._incubating.attributes import ( @@ -46,12 +45,6 @@ def default(self, o): return "" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-langchain/pyproject.toml b/packages/opentelemetry-instrumentation-langchain/pyproject.toml index 4f893e66ee..95a20d0058 100644 --- a/packages/opentelemetry-instrumentation-langchain/pyproject.toml +++ b/packages/opentelemetry-instrumentation-langchain/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -91,6 +91,7 @@ select = ["E", "F", "W"] constraint-dependencies = ["urllib3>=2.6.3", "langgraph-checkpoint>=4.0.0", "pip>=25.3"] [tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } opentelemetry-instrumentation-bedrock = { path = "../opentelemetry-instrumentation-bedrock", editable = true } opentelemetry-instrumentation-openai = { path = "../opentelemetry-instrumentation-openai", editable = true } diff --git a/packages/opentelemetry-instrumentation-litellm/opentelemetry/instrumentation/litellm/utils.py b/packages/opentelemetry-instrumentation-litellm/opentelemetry/instrumentation/litellm/utils.py index 9362c066df..bf46dfdce6 100644 --- a/packages/opentelemetry-instrumentation-litellm/opentelemetry/instrumentation/litellm/utils.py +++ b/packages/opentelemetry-instrumentation-litellm/opentelemetry/instrumentation/litellm/utils.py @@ -2,16 +2,8 @@ import os import traceback -from opentelemetry import context as context_api from opentelemetry.instrumentation.litellm.config import Config - -TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" - - -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts def is_metrics_enabled() -> bool: diff --git a/packages/opentelemetry-instrumentation-litellm/pyproject.toml b/packages/opentelemetry-instrumentation-litellm/pyproject.toml index 92a71a5f56..a69af23189 100644 --- a/packages/opentelemetry-instrumentation-litellm/pyproject.toml +++ b/packages/opentelemetry-instrumentation-litellm/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-llamaindex/opentelemetry/instrumentation/llamaindex/utils.py b/packages/opentelemetry-instrumentation-llamaindex/opentelemetry/instrumentation/llamaindex/utils.py index c9abd32fea..8a2aef11f8 100644 --- a/packages/opentelemetry-instrumentation-llamaindex/opentelemetry/instrumentation/llamaindex/utils.py +++ b/packages/opentelemetry-instrumentation-llamaindex/opentelemetry/instrumentation/llamaindex/utils.py @@ -2,11 +2,10 @@ import inspect import json import logging -import os import traceback from contextlib import asynccontextmanager -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry._logs import Logger from opentelemetry.instrumentation.llamaindex.config import Config from opentelemetry.semconv_ai import SpanAttributes @@ -30,12 +29,6 @@ async def start_as_current_span_async(tracer, *args, **kwargs): yield span -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-llamaindex/pyproject.toml b/packages/opentelemetry-instrumentation-llamaindex/pyproject.toml index 048f2e8b33..201d8ef3e9 100644 --- a/packages/opentelemetry-instrumentation-llamaindex/pyproject.toml +++ b/packages/opentelemetry-instrumentation-llamaindex/pyproject.toml @@ -14,7 +14,7 @@ dependencies = [ "inflection>=0.5.1,<0.6.0", "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -86,6 +86,7 @@ select = ["E", "F", "W"] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] [tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } opentelemetry-instrumentation-chromadb = { path = "../opentelemetry-instrumentation-chromadb", editable = true } opentelemetry-instrumentation-cohere = { path = "../opentelemetry-instrumentation-cohere", editable = true } opentelemetry-instrumentation-openai = { path = "../opentelemetry-instrumentation-openai", editable = true } diff --git a/packages/opentelemetry-instrumentation-mcp/opentelemetry/instrumentation/mcp/utils.py b/packages/opentelemetry-instrumentation-mcp/opentelemetry/instrumentation/mcp/utils.py index 6ce7a90c91..53e44003f6 100644 --- a/packages/opentelemetry-instrumentation-mcp/opentelemetry/instrumentation/mcp/utils.py +++ b/packages/opentelemetry-instrumentation-mcp/opentelemetry/instrumentation/mcp/utils.py @@ -2,13 +2,12 @@ import asyncio import logging -import os import traceback from contextlib import contextmanager from typing import Optional -from opentelemetry import context as context_api from opentelemetry.semconv.attributes.error_attributes import ERROR_TYPE +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.trace import INVALID_SPAN, Status, StatusCode @@ -16,22 +15,6 @@ class Config: exception_logger = None -def should_send_prompts() -> bool: - """Whether request/response content may be recorded on spans. - - Mirrors the traceloop SDK's ``TRACELOOP_TRACE_CONTENT`` switch: content - capture is on unless an operator explicitly turns it off. Shared by the - FastMCP server wrapper and the MCP client path so a single environment - variable governs both, which is what the package README documents. - - Like the other instrumentations, the SDK's per-association content allow - list can also enable capture via ``override_enable_content_tracing``. - """ - return ( - os.getenv("TRACELOOP_TRACE_CONTENT") or "true" - ).lower() == "true" or bool(context_api.get_value("override_enable_content_tracing")) - - def frames_without_content(exc: BaseException) -> str: """`exc`'s stack as file, line and function -- without the frames' source lines. diff --git a/packages/opentelemetry-instrumentation-mcp/pyproject.toml b/packages/opentelemetry-instrumentation-mcp/pyproject.toml index 5c723bfca3..8f90e2e71f 100644 --- a/packages/opentelemetry-instrumentation-mcp/pyproject.toml +++ b/packages/opentelemetry-instrumentation-mcp/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -77,3 +77,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-mistralai/opentelemetry/instrumentation/mistralai/utils.py b/packages/opentelemetry-instrumentation-mistralai/opentelemetry/instrumentation/mistralai/utils.py index 791590be97..423383cc76 100644 --- a/packages/opentelemetry-instrumentation-mistralai/opentelemetry/instrumentation/mistralai/utils.py +++ b/packages/opentelemetry-instrumentation-mistralai/opentelemetry/instrumentation/mistralai/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.mistralai.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-mistralai/pyproject.toml b/packages/opentelemetry-instrumentation-mistralai/pyproject.toml index c757f77b4e..cdb42c93ed 100644 --- a/packages/opentelemetry-instrumentation-mistralai/pyproject.toml +++ b/packages/opentelemetry-instrumentation-mistralai/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama/utils.py b/packages/opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama/utils.py index 14112b8a27..d91576ccfc 100644 --- a/packages/opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama/utils.py +++ b/packages/opentelemetry-instrumentation-ollama/opentelemetry/instrumentation/ollama/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.ollama.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-ollama/pyproject.toml b/packages/opentelemetry-instrumentation-ollama/pyproject.toml index 9c1dcbb088..435bc39b67 100644 --- a/packages/opentelemetry-instrumentation-ollama/pyproject.toml +++ b/packages/opentelemetry-instrumentation-ollama/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-openai-agents/opentelemetry/instrumentation/openai_agents/utils.py b/packages/opentelemetry-instrumentation-openai-agents/opentelemetry/instrumentation/openai_agents/utils.py index a6f58e0090..3195f2ed1e 100644 --- a/packages/opentelemetry-instrumentation-openai-agents/opentelemetry/instrumentation/openai_agents/utils.py +++ b/packages/opentelemetry-instrumentation-openai-agents/opentelemetry/instrumentation/openai_agents/utils.py @@ -4,16 +4,15 @@ import inspect import json import logging -import os import traceback -from opentelemetry import context as context_api + +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts # Handoff span attribute names GEN_AI_HANDOFF_FROM_AGENT = "gen_ai.handoff.from_agent" GEN_AI_HANDOFF_TO_AGENT = "gen_ai.handoff.to_agent" GEN_AI_HANDOFF_PARENT_AGENT = "gen_ai.agent.handoff_parent" OPENAI_AGENT_HANDOFFS = "openai.agent.handoffs" -_TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" def set_span_attribute(span, name, value): @@ -23,20 +22,6 @@ def set_span_attribute(span, name, value): return -def _is_truthy(value): - return str(value).strip().lower() in ("true", "1", "yes", "on") - - -def should_send_prompts() -> bool: - """Determine if LLM content tracing should be enabled. - - Content includes not only prompts, but also responses. - """ - env_setting = os.getenv(_TRACELOOP_TRACE_CONTENT, "true") - override = context_api.get_value("override_enable_content_tracing") - return _is_truthy(env_setting) or _is_truthy(override) - - class JSONEncoder(json.JSONEncoder): def default(self, o): if dataclasses.is_dataclass(o): diff --git a/packages/opentelemetry-instrumentation-openai-agents/pyproject.toml b/packages/opentelemetry-instrumentation-openai-agents/pyproject.toml index 0b92901130..4e8b69bdbd 100644 --- a/packages/opentelemetry-instrumentation-openai-agents/pyproject.toml +++ b/packages/opentelemetry-instrumentation-openai-agents/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/utils.py b/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/utils.py index 338550693b..1c8b90fe00 100644 --- a/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/utils.py +++ b/packages/opentelemetry-instrumentation-openai/opentelemetry/instrumentation/openai/utils.py @@ -8,16 +8,14 @@ from importlib.metadata import version from packaging import version as pkg_version -from opentelemetry import context as context_api from opentelemetry._logs import Logger from opentelemetry.instrumentation.openai.shared.config import Config +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts import openai _OPENAI_VERSION = version("openai") -TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" - def is_openai_v1(): return pkg_version.parse(_OPENAI_VERSION) >= pkg_version.parse("1.0.0") @@ -190,20 +188,6 @@ def run_async(method): asyncio.run(method) -def _is_truthy(value): - return str(value).strip().lower() in ("true", "1", "yes", "on") - - -def should_send_prompts() -> bool: - """Determine if LLM content tracing should be enabled. - - Content includes not only prompts, but also responses. - """ - env_setting = os.getenv(TRACELOOP_TRACE_CONTENT, "true") - override = context_api.get_value("override_enable_content_tracing") - return _is_truthy(env_setting) or _is_truthy(override) - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-openai/pyproject.toml b/packages/opentelemetry-instrumentation-openai/pyproject.toml index 68cb642b4c..4cbe37c735 100644 --- a/packages/opentelemetry-instrumentation-openai/pyproject.toml +++ b/packages/opentelemetry-instrumentation-openai/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -73,3 +73,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-openai/tests/test_capture_message_content.py b/packages/opentelemetry-instrumentation-openai/tests/test_capture_message_content.py new file mode 100644 index 0000000000..9f5090e5ab --- /dev/null +++ b/packages/opentelemetry-instrumentation-openai/tests/test_capture_message_content.py @@ -0,0 +1,27 @@ +"""Regression tests for the standard OTel content capture switch.""" + +from opentelemetry.instrumentation.openai.utils import should_send_prompts + +OTEL_VAR = "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT" +TRACELOOP_VAR = "TRACELOOP_TRACE_CONTENT" + + +def test_otel_switch_disables_capture(monkeypatch): + """The OpenAI instrumentation used to ignore this variable.""" + monkeypatch.delenv(TRACELOOP_VAR, raising=False) + monkeypatch.setenv(OTEL_VAR, "false") + assert should_send_prompts() is False + + +def test_default_is_unchanged(monkeypatch): + """With neither variable set, content capture stays on.""" + monkeypatch.delenv(OTEL_VAR, raising=False) + monkeypatch.delenv(TRACELOOP_VAR, raising=False) + assert should_send_prompts() is True + + +def test_traceloop_switch_still_disables_capture(monkeypatch): + """Existing behavior is preserved when the OTel variable is unset.""" + monkeypatch.delenv(OTEL_VAR, raising=False) + monkeypatch.setenv(TRACELOOP_VAR, "false") + assert should_send_prompts() is False diff --git a/packages/opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate/utils.py b/packages/opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate/utils.py index f409d7fef0..2b3951e145 100644 --- a/packages/opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate/utils.py +++ b/packages/opentelemetry-instrumentation-replicate/opentelemetry/instrumentation/replicate/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.replicate.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-replicate/pyproject.toml b/packages/opentelemetry-instrumentation-replicate/pyproject.toml index 21573df248..0b325bec55 100644 --- a/packages/opentelemetry-instrumentation-replicate/pyproject.toml +++ b/packages/opentelemetry-instrumentation-replicate/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -71,3 +71,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-sagemaker/opentelemetry/instrumentation/sagemaker/utils.py b/packages/opentelemetry-instrumentation-sagemaker/opentelemetry/instrumentation/sagemaker/utils.py index cc21efba1d..d2a50f7101 100644 --- a/packages/opentelemetry-instrumentation-sagemaker/opentelemetry/instrumentation/sagemaker/utils.py +++ b/packages/opentelemetry-instrumentation-sagemaker/opentelemetry/instrumentation/sagemaker/utils.py @@ -1,8 +1,7 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.sagemaker.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" @@ -33,12 +32,6 @@ def wrapper(*args, **kwargs): return wrapper -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-sagemaker/pyproject.toml b/packages/opentelemetry-instrumentation-sagemaker/pyproject.toml index 76a7555646..9c63cacfd5 100644 --- a/packages/opentelemetry-instrumentation-sagemaker/pyproject.toml +++ b/packages/opentelemetry-instrumentation-sagemaker/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -69,3 +69,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-together/opentelemetry/instrumentation/together/utils.py b/packages/opentelemetry-instrumentation-together/opentelemetry/instrumentation/together/utils.py index 0536c95a9c..bafb39bb34 100644 --- a/packages/opentelemetry-instrumentation-together/opentelemetry/instrumentation/together/utils.py +++ b/packages/opentelemetry-instrumentation-together/opentelemetry/instrumentation/together/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.together.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-together/pyproject.toml b/packages/opentelemetry-instrumentation-together/pyproject.toml index 2b889888ee..99efff914b 100644 --- a/packages/opentelemetry-instrumentation-together/pyproject.toml +++ b/packages/opentelemetry-instrumentation-together/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-transformers/opentelemetry/instrumentation/transformers/utils.py b/packages/opentelemetry-instrumentation-transformers/opentelemetry/instrumentation/transformers/utils.py index 690f933ef8..9d228d09e6 100644 --- a/packages/opentelemetry-instrumentation-transformers/opentelemetry/instrumentation/transformers/utils.py +++ b/packages/opentelemetry-instrumentation-transformers/opentelemetry/instrumentation/transformers/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.transformers.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def with_tracer_wrapper(func): """Helper for providing tracer for wrapper functions.""" diff --git a/packages/opentelemetry-instrumentation-transformers/pyproject.toml b/packages/opentelemetry-instrumentation-transformers/pyproject.toml index 5ada9d8178..7c773f6f76 100644 --- a/packages/opentelemetry-instrumentation-transformers/pyproject.toml +++ b/packages/opentelemetry-instrumentation-transformers/pyproject.toml @@ -13,7 +13,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -67,3 +67,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-vertexai/opentelemetry/instrumentation/vertexai/utils.py b/packages/opentelemetry-instrumentation-vertexai/opentelemetry/instrumentation/vertexai/utils.py index df31122429..c8621b10fe 100644 --- a/packages/opentelemetry-instrumentation-vertexai/opentelemetry/instrumentation/vertexai/utils.py +++ b/packages/opentelemetry-instrumentation-vertexai/opentelemetry/instrumentation/vertexai/utils.py @@ -1,19 +1,12 @@ import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.vertexai.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-vertexai/pyproject.toml b/packages/opentelemetry-instrumentation-vertexai/pyproject.toml index f7cc82869d..f1c56d2211 100644 --- a/packages/opentelemetry-instrumentation-vertexai/pyproject.toml +++ b/packages/opentelemetry-instrumentation-vertexai/pyproject.toml @@ -14,7 +14,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -78,3 +78,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-voyageai/opentelemetry/instrumentation/voyageai/utils.py b/packages/opentelemetry-instrumentation-voyageai/opentelemetry/instrumentation/voyageai/utils.py index f4ff8183c3..ecc283c65f 100644 --- a/packages/opentelemetry-instrumentation-voyageai/opentelemetry/instrumentation/voyageai/utils.py +++ b/packages/opentelemetry-instrumentation-voyageai/opentelemetry/instrumentation/voyageai/utils.py @@ -1,10 +1,9 @@ import dataclasses import json import logging -import os import traceback -from opentelemetry import context as context_api +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.instrumentation.voyageai.config import Config TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" @@ -35,12 +34,6 @@ def wrapper(*args, **kwargs): return wrapper -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-voyageai/pyproject.toml b/packages/opentelemetry-instrumentation-voyageai/pyproject.toml index ea85db02ef..3bd7fa6c70 100644 --- a/packages/opentelemetry-instrumentation-voyageai/pyproject.toml +++ b/packages/opentelemetry-instrumentation-voyageai/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -72,3 +72,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-watsonx/opentelemetry/instrumentation/watsonx/utils.py b/packages/opentelemetry-instrumentation-watsonx/opentelemetry/instrumentation/watsonx/utils.py index dd25a47288..e7bafa3bcd 100644 --- a/packages/opentelemetry-instrumentation-watsonx/opentelemetry/instrumentation/watsonx/utils.py +++ b/packages/opentelemetry-instrumentation-watsonx/opentelemetry/instrumentation/watsonx/utils.py @@ -1,20 +1,8 @@ import logging -import os import traceback -from opentelemetry import context as context_api from opentelemetry.instrumentation.watsonx.config import Config - -OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = ( - "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT" -) -TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" - - -def should_send_prompts(): - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts def dont_throw(func): @@ -42,14 +30,6 @@ def wrapper(*args, **kwargs): return wrapper -def is_content_enabled() -> bool: - capture_content = os.environ.get( - OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT, "false" - ) - - return capture_content.lower() == "true" - - def should_emit_events() -> bool: """ Checks if the instrumentation isn't using the legacy attributes diff --git a/packages/opentelemetry-instrumentation-watsonx/pyproject.toml b/packages/opentelemetry-instrumentation-watsonx/pyproject.toml index e6dfb2c533..b3ec7953ca 100644 --- a/packages/opentelemetry-instrumentation-watsonx/pyproject.toml +++ b/packages/opentelemetry-instrumentation-watsonx/pyproject.toml @@ -11,7 +11,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -64,3 +64,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "requests>=2.32.5", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-instrumentation-writer/opentelemetry/instrumentation/writer/utils.py b/packages/opentelemetry-instrumentation-writer/opentelemetry/instrumentation/writer/utils.py index e420cb3fc2..bbe8e16084 100644 --- a/packages/opentelemetry-instrumentation-writer/opentelemetry/instrumentation/writer/utils.py +++ b/packages/opentelemetry-instrumentation-writer/opentelemetry/instrumentation/writer/utils.py @@ -1,9 +1,9 @@ import logging -import os import traceback from importlib.metadata import version from typing import Any +from opentelemetry.semconv_ai.utils import should_send_prompts as should_send_prompts from opentelemetry.semconv_ai import LLMRequestTypeValues, SpanAttributes from opentelemetry.trace import Span from writerai.types import ChatCompletion, Completion @@ -11,7 +11,6 @@ from writerai.types.chat_completion_message import ChatCompletionMessage from writerai.types.shared.tool_call import Function, ToolCall -from opentelemetry import context as context_api from opentelemetry.instrumentation.writer import Config GEN_AI_SYSTEM = "gen_ai.system" @@ -30,12 +29,6 @@ def set_span_attribute(span: Span, name: str, value: Any | None) -> None: span.set_attribute(name, value) -def should_send_prompts() -> bool: - return ( - os.getenv(TRACELOOP_TRACE_CONTENT) or "true" - ).lower() == "true" or context_api.get_value("override_enable_content_tracing") - - def dont_throw(func): """ A decorator that wraps the passed in function and logs exceptions instead of throwing them. diff --git a/packages/opentelemetry-instrumentation-writer/pyproject.toml b/packages/opentelemetry-instrumentation-writer/pyproject.toml index b5ce92449c..e838ad8070 100644 --- a/packages/opentelemetry-instrumentation-writer/pyproject.toml +++ b/packages/opentelemetry-instrumentation-writer/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10,<4" dependencies = [ "opentelemetry-api>=1.38.0,<2", "opentelemetry-instrumentation>=0.59b0", - "opentelemetry-semantic-conventions-ai>=0.5.1,<0.6.0", + "opentelemetry-semantic-conventions-ai>=0.5.2,<0.6.0", "opentelemetry-semantic-conventions>=0.63b1", ] @@ -74,3 +74,6 @@ select = ["E", "F", "W"] [tool.uv] constraint-dependencies = ["urllib3>=2.6.3", "pyarrow>=18.1.0", "pip>=25.3"] + +[tool.uv.sources] +opentelemetry-semantic-conventions-ai = { path = "../opentelemetry-semantic-conventions-ai", editable = true } diff --git a/packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/utils.py b/packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/utils.py index 1470fa7f13..f310c4f2e6 100644 --- a/packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/utils.py +++ b/packages/opentelemetry-semantic-conventions-ai/opentelemetry/semconv_ai/utils.py @@ -1,4 +1,50 @@ import logging +import os + +from opentelemetry import context as context_api + +OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT = ( + "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT" +) +TRACELOOP_TRACE_CONTENT = "TRACELOOP_TRACE_CONTENT" + +# Values defined by the OTel GenAI conventions for the capture switch. Any +# other value is parsed as a boolean, so ``false`` also disables capture. +# EVENT_ONLY is off here because ``should_send_prompts`` gates span attributes; +# event-based capture is not wired to this switch yet. +_OTEL_CAPTURE_VALUES = { + "no_content": False, + "span_only": True, + "event_only": False, + "span_and_event": True, +} + + +def _is_truthy(value) -> bool: + return str(value).strip().lower() in ("true", "1", "yes", "on") + + +def should_send_prompts() -> bool: + """Return whether prompts and completions may be recorded. + + ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT`` is honored when it + is explicitly set; otherwise ``TRACELOOP_TRACE_CONTENT`` is used, which + defaults to on. The ``override_enable_content_tracing`` context value can + still enable capture for a specific call. + """ + configured = os.getenv(OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT) + if configured is not None: + normalized = configured.strip().lower() + if normalized in _OTEL_CAPTURE_VALUES: + enabled = _OTEL_CAPTURE_VALUES[normalized] + else: + enabled = _is_truthy(configured) + else: + enabled = _is_truthy(os.getenv(TRACELOOP_TRACE_CONTENT, "true")) + + return enabled or _is_truthy( + context_api.get_value("override_enable_content_tracing") + ) def dont_throw(func): diff --git a/packages/opentelemetry-semantic-conventions-ai/tests/test_capture_message_content.py b/packages/opentelemetry-semantic-conventions-ai/tests/test_capture_message_content.py new file mode 100644 index 0000000000..b94a12f7cc --- /dev/null +++ b/packages/opentelemetry-semantic-conventions-ai/tests/test_capture_message_content.py @@ -0,0 +1,73 @@ +"""Tests for the shared content capture switch.""" + +import pytest +from opentelemetry import context + +from opentelemetry.semconv_ai.utils import should_send_prompts + +OTEL_VAR = "OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT" +TRACELOOP_VAR = "TRACELOOP_TRACE_CONTENT" + + +@pytest.fixture(autouse=True) +def capture_env(monkeypatch): + """Start every test from a clean environment.""" + monkeypatch.delenv(OTEL_VAR, raising=False) + monkeypatch.delenv(TRACELOOP_VAR, raising=False) + + +def test_default_is_enabled(): + """With neither variable set, capture stays on, as it was before.""" + assert should_send_prompts() is True + + +def test_traceloop_switch_still_disables_capture(monkeypatch): + """The existing Traceloop switch keeps working.""" + monkeypatch.setenv(TRACELOOP_VAR, "false") + assert should_send_prompts() is False + + +def test_otel_switch_disables_capture(monkeypatch): + """The standard OTel variable is honored; it used to be ignored.""" + monkeypatch.setenv(OTEL_VAR, "false") + assert should_send_prompts() is False + + +@pytest.mark.parametrize("value", ["SPAN_ONLY", "SPAN_AND_EVENT"]) +def test_otel_capture_values_enable_capture(monkeypatch, value): + """The OTel convention's span capture values keep content on.""" + monkeypatch.setenv(OTEL_VAR, value) + assert should_send_prompts() is True + + +def test_otel_event_only_does_not_enable_span_capture(monkeypatch): + """Content must not leak into spans in event-only mode.""" + monkeypatch.setenv(OTEL_VAR, "EVENT_ONLY") + assert should_send_prompts() is False + + +def test_otel_no_content_disables_capture(monkeypatch): + """NO_CONTENT is the OTel convention's explicit off value.""" + monkeypatch.setenv(OTEL_VAR, "NO_CONTENT") + assert should_send_prompts() is False + + +def test_otel_switch_takes_precedence(monkeypatch): + """An explicit OTel setting wins over the Traceloop fallback.""" + monkeypatch.setenv(TRACELOOP_VAR, "true") + monkeypatch.setenv(OTEL_VAR, "false") + assert should_send_prompts() is False + + monkeypatch.setenv(TRACELOOP_VAR, "false") + monkeypatch.setenv(OTEL_VAR, "true") + assert should_send_prompts() is True + + +def test_context_override_still_enables_capture(monkeypatch): + """The SDK's per-association allow list can still enable capture.""" + monkeypatch.setenv(OTEL_VAR, "false") + token = context.attach(context.set_value("override_enable_content_tracing", True)) + try: + assert should_send_prompts() is True + finally: + context.detach(token)