Skip to content

Commit 26ae9ca

Browse files
authored
OpenAI v2 onboard onto semantic conventions 1.37.0: chat history and other breaking changes (#3715)
* Support latest experimental conventions in openai * format * changelog * lint * lint * update to use new test utils, fix tests * lint * review * address feedback * review * feedback: more readable
1 parent 489bca3 commit 26ae9ca

23 files changed

+3048
-1654
lines changed

instrumentation-genai/opentelemetry-instrumentation-openai-v2/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
- Fix `StreamWrapper` missing `.headers` and other attributes when using `with_raw_response` streaming
1111
([#4113](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/4113))
12+
- Add opt-in support for latest experimental semantic conventions (v1.37.0). Set
13+
`OTEL_SEMCONV_STABILITY_OPT_IN` to `gen_ai_latest_experimental` to enable.
14+
Add dependency on `opentelemetry-util-genai` pypi package.
15+
([#3715](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3715))
1216

1317
## Version 2.3b0 (2025-12-24)
1418

instrumentation-genai/opentelemetry-instrumentation-openai-v2/README.rst

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Many LLM platforms support the OpenAI SDK. This means systems such as the follow
1919
* - Name
2020
- gen_ai.system
2121
* - `Azure OpenAI <https://github.com/openai/openai-python?tab=readme-ov-file#microsoft-azure-openai>`_
22-
- ``az.ai.openai``
22+
- ``azure.ai.openai``
2323
* - `Gemini <https://developers.googleblog.com/en/gemini-is-now-accessible-from-the-openai-library/>`_
2424
- ``gemini``
2525
* - `Perplexity <https://docs.perplexity.ai/api-reference/chat-completions>`_
@@ -75,7 +75,7 @@ Make sure to configure OpenTelemetry tracing, logging, and events to capture all
7575
{"role": "user", "content": "Write a short poem on open telemetry."},
7676
],
7777
)
78-
78+
7979
# Embeddings example
8080
embedding_response = client.embeddings.create(
8181
model="text-embedding-3-small",
@@ -87,7 +87,28 @@ Enabling message content
8787

8888
Message content such as the contents of the prompt, completion, function arguments and return values
8989
are not captured by default. To capture message content as log events, set the environment variable
90-
`OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` to `true`.
90+
``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT`` to one of the following values:
91+
92+
- ``true`` - Legacy. Used to enable content capturing on ``gen_ai.{role}.message`` and ``gen_ai.choice`` events when
93+
`latest experimental features <#enabling-the-latest-experimental-features>`_ are *not* enabled.
94+
- ``span_only`` - Used to enable content capturing on *span* attributes when
95+
`latest experimental features <#enabling-the-latest-experimental-features>`_ are enabled.
96+
- ``event_only`` - Used to enable content capturing on *event* attributes when
97+
`latest experimental features <#enabling-the-latest-experimental-features>`_ are enabled.
98+
- ``span_and_event`` - Used to enable content capturing on both *span* and *event* attributes when
99+
`latest experimental features <#enabling-the-latest-experimental-features>`_ are enabled.
100+
101+
Enabling the latest experimental features
102+
***********************************************
103+
104+
To enable the latest experimental features, set the environment variable
105+
``OTEL_SEMCONV_STABILITY_OPT_IN`` to ``gen_ai_latest_experimental``. Or, if you use
106+
``OTEL_SEMCONV_STABILITY_OPT_IN`` to enable other features, append ``,gen_ai_latest_experimental`` to its value.
107+
108+
Without this setting, OpenAI instrumentation aligns with `Semantic Conventions v1.30.0 <https://github.com/open-telemetry/semantic-conventions/tree/v1.30.0/docs/gen-ai>`_
109+
and would not capture additional details introduced in later versions.
110+
111+
.. note:: Generative AI semantic conventions are still evolving. The latest experimental features will introduce breaking changes in future releases.
91112

92113
Uninstrument
93114
************

instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/.env

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,20 @@ OPENAI_API_KEY=sk-YOUR_API_KEY
1212

1313
OTEL_SERVICE_NAME=opentelemetry-python-openai
1414

15-
# Change to 'false' to hide prompt and completion content
16-
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
15+
# Remove to hide prompt and completion content
16+
# Possible values (case insensitive):
17+
# - `span_only` - record content on span attibutes
18+
# - `event_only` - record content on event attributes
19+
# - `span_and_event` - record content on both span and event attributes
20+
# - `true` - only used for backward compatibility when
21+
# `gen_ai_latest_experimental` is not set in the
22+
# `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable.
23+
# - everything else - don't record content on any signal
24+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only
25+
26+
# Enables latest and greatest features available in GenAI semantic conventions.
27+
# Note: since conventions are still in development, using this flag would
28+
# likely result in having breaking changes.
29+
#
30+
# Comment out if you want to use semantic conventions of version 1.30.0.
31+
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental

instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/manual/README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ your OpenAI requests.
1111

1212
Note: `.env <.env>`_ file configures additional environment variables:
1313

14-
- ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true`` configures OpenAI instrumentation to capture prompt and completion contents on events.
14+
- ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only`` configures OpenAI instrumentation to capture prompt and completion contents on *span* attributes.
15+
- ``OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental`` enables latest experimental features.
1516

1617
Setup
1718
-----

instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/zero-code/.env

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,20 @@ OTEL_SERVICE_NAME=opentelemetry-python-openai
1515
# Uncomment if your OTLP endpoint doesn't support logs
1616
# OTEL_LOGS_EXPORTER=console
1717

18-
# Change to 'false' to hide prompt and completion content
19-
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
18+
# Remove to hide prompt and completion content
19+
# Possible values (case insensitive):
20+
# - `span_only` - record content on span attibutes
21+
# - `event_only` - record content on event attributes
22+
# - `span_and_event` - record content on both span and event attributes
23+
# - `true` - only used for backward compatibility when
24+
# `gen_ai_latest_experimental` is not set in the
25+
# `OTEL_SEMCONV_STABILITY_OPT_IN` environment variable.
26+
# - everything else - don't record content on any signal
27+
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only
28+
29+
# Enables latest and greatest features available in GenAI semantic conventions.
30+
# Note: since conventions are still in development, using this flag would
31+
# likely result in having breaking changes.
32+
#
33+
# Comment out if you want to use semantic conventions of version 1.30.0.
34+
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental

instrumentation-genai/opentelemetry-instrumentation-openai-v2/examples/zero-code/README.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ your OpenAI requests.
1212

1313
Note: `.env <.env>`_ file configures additional environment variables:
1414

15-
- ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true`` configures OpenAI instrumentation to capture prompt and completion contents on events.
15+
- ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=span_only`` configures OpenAI instrumentation to capture prompt and completion contents on *span* attributes.
1616
- ``OTEL_LOGS_EXPORTER=otlp`` to specify exporter type.
17+
- ``OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental`` enables latest experimental features.
1718

1819
Setup
1920
-----

instrumentation-genai/opentelemetry-instrumentation-openai-v2/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ classifiers = [
2828
dependencies = [
2929
"opentelemetry-api ~= 1.37",
3030
"opentelemetry-instrumentation ~= 0.58b0",
31-
"opentelemetry-semantic-conventions ~= 0.58b0"
31+
"opentelemetry-semantic-conventions ~= 0.58b0",
32+
"opentelemetry-util-genai",
3233
]
3334

3435
[project.optional-dependencies]

instrumentation-genai/opentelemetry-instrumentation-openai-v2/src/opentelemetry/instrumentation/openai_v2/__init__.py

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,22 @@
5252
from opentelemetry.metrics import get_meter
5353
from opentelemetry.semconv.schemas import Schemas
5454
from opentelemetry.trace import get_tracer
55+
from opentelemetry.util.genai.handler import (
56+
TelemetryHandler,
57+
)
58+
from opentelemetry.util.genai.types import ContentCapturingMode
59+
from opentelemetry.util.genai.utils import (
60+
get_content_capturing_mode,
61+
is_experimental_mode,
62+
)
5563

5664
from .instruments import Instruments
5765
from .patch import (
58-
async_chat_completions_create,
66+
async_chat_completions_create_v_new,
67+
async_chat_completions_create_v_old,
5968
async_embeddings_create,
60-
chat_completions_create,
69+
chat_completions_create_v_new,
70+
chat_completions_create_v_old,
6171
embeddings_create,
6272
)
6373

@@ -71,43 +81,64 @@ def instrumentation_dependencies(self) -> Collection[str]:
7181

7282
def _instrument(self, **kwargs):
7383
"""Enable OpenAI instrumentation."""
84+
85+
latest_experimental_enabled = is_experimental_mode()
7486
tracer_provider = kwargs.get("tracer_provider")
7587
tracer = get_tracer(
7688
__name__,
7789
"",
7890
tracer_provider,
79-
schema_url=Schemas.V1_30_0.value,
91+
schema_url=Schemas.V1_30_0.value, # only used on the legacy path
8092
)
8193
logger_provider = kwargs.get("logger_provider")
8294
logger = get_logger(
8395
__name__,
8496
"",
85-
schema_url=Schemas.V1_30_0.value,
8697
logger_provider=logger_provider,
98+
schema_url=Schemas.V1_30_0.value, # only used on the legacy path
8799
)
88100
meter_provider = kwargs.get("meter_provider")
89101
self._meter = get_meter(
90102
__name__,
91103
"",
92104
meter_provider,
93-
schema_url=Schemas.V1_30_0.value,
105+
schema_url=Schemas.V1_30_0.value, # only used on the legacy path
94106
)
95107

96108
instruments = Instruments(self._meter)
97109

110+
content_mode = (
111+
get_content_capturing_mode()
112+
if latest_experimental_enabled
113+
else ContentCapturingMode.NO_CONTENT
114+
)
115+
handler = TelemetryHandler(
116+
tracer_provider=tracer_provider,
117+
meter_provider=meter_provider,
118+
logger_provider=logger_provider,
119+
)
120+
98121
wrap_function_wrapper(
99122
module="openai.resources.chat.completions",
100123
name="Completions.create",
101-
wrapper=chat_completions_create(
102-
tracer, logger, instruments, is_content_enabled()
124+
wrapper=(
125+
chat_completions_create_v_new(handler, content_mode)
126+
if latest_experimental_enabled
127+
else chat_completions_create_v_old(
128+
tracer, logger, instruments, is_content_enabled()
129+
)
103130
),
104131
)
105132

106133
wrap_function_wrapper(
107134
module="openai.resources.chat.completions",
108135
name="AsyncCompletions.create",
109-
wrapper=async_chat_completions_create(
110-
tracer, logger, instruments, is_content_enabled()
136+
wrapper=(
137+
async_chat_completions_create_v_new(handler, content_mode)
138+
if latest_experimental_enabled
139+
else async_chat_completions_create_v_old(
140+
tracer, logger, instruments, is_content_enabled()
141+
)
111142
),
112143
)
113144

@@ -116,15 +147,15 @@ def _instrument(self, **kwargs):
116147
module="openai.resources.embeddings",
117148
name="Embeddings.create",
118149
wrapper=embeddings_create(
119-
tracer, instruments, is_content_enabled()
150+
tracer, instruments, latest_experimental_enabled
120151
),
121152
)
122153

123154
wrap_function_wrapper(
124155
module="openai.resources.embeddings",
125156
name="AsyncEmbeddings.create",
126157
wrapper=async_embeddings_create(
127-
tracer, instruments, is_content_enabled()
158+
tracer, instruments, latest_experimental_enabled
128159
),
129160
)
130161

0 commit comments

Comments
 (0)