From f423bfdd5ec6357f5bbb082f0c6ba588c602dde1 Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 17 Jun 2026 18:16:38 -0700 Subject: [PATCH 1/3] Remove exception handling around instrumentation code --- .../src/opentelemetry/util/genai/stream.py | 85 ++++--------------- 1 file changed, 17 insertions(+), 68 deletions(-) diff --git a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/stream.py b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/stream.py index 88181146..83bb0a49 100644 --- a/util/opentelemetry-util-genai/src/opentelemetry/util/genai/stream.py +++ b/util/opentelemetry-util-genai/src/opentelemetry/util/genai/stream.py @@ -80,7 +80,7 @@ def __exit__( exc_tb: TracebackType | None, ) -> Literal[False]: if exc_val is not None: - self._safe_finalize_failure(exc_val) + self._finalize_failure(exc_val) try: self._self_stream.close() except Exception: # pylint: disable=broad-exception-caught @@ -97,9 +97,9 @@ def close(self) -> None: try: self._self_stream.close() except Exception as error: - self._safe_finalize_failure(error) + self._finalize_failure(error) raise - self._safe_finalize_success() + self._finalize_success() def __iter__(self): # Override ``ObjectProxy.__iter__`` so iteration drives ``__next__`` @@ -111,15 +111,12 @@ def __next__(self) -> ChunkT: try: chunk = next(self._self_iterator) except StopIteration: - self._safe_finalize_success() + self._finalize_success() raise except Exception as error: - self._safe_finalize_failure(error) + self._finalize_failure(error) raise - try: - self._process_chunk(chunk) - except Exception as error: # pylint: disable=broad-exception-caught - self._handle_process_chunk_error(error) + self._process_chunk(chunk) return chunk def _finalize_success(self) -> None: @@ -134,24 +131,6 @@ def _finalize_failure(self, error: BaseException) -> None: self._self_finalized = True self._on_stream_error(error) - def _safe_finalize_success(self) -> None: - try: - self._finalize_success() - except Exception: # pylint: disable=broad-exception-caught - _logger.debug( - "GenAI stream instrumentation error during finalization", - exc_info=True, - ) - - def _safe_finalize_failure(self, error: BaseException) -> None: - try: - self._finalize_failure(error) - except Exception: # pylint: disable=broad-exception-caught - _logger.debug( - "GenAI stream instrumentation error during failure finalization", - exc_info=True, - ) - @abstractmethod def _process_chunk(self, chunk: ChunkT) -> None: """Process one stream chunk for telemetry.""" @@ -164,13 +143,6 @@ def _on_stream_end(self) -> None: def _on_stream_error(self, error: BaseException) -> None: """Finalize the stream with failure.""" - @staticmethod - def _handle_process_chunk_error(_error: Exception) -> None: - _logger.debug( - "GenAI stream instrumentation error during chunk processing", - exc_info=True, - ) - class AsyncStreamWrapper( _ObjectProxy, @@ -207,7 +179,7 @@ async def __aexit__( exc_tb: TracebackType | None, ) -> Literal[False]: if exc_val is not None: - self._safe_finalize_failure(exc_val) + self._finalize_failure(exc_val) try: await self._self_stream.close() except Exception: # pylint: disable=broad-exception-caught @@ -226,9 +198,13 @@ async def close(self) -> None: try: await self._self_stream.close() except Exception as error: - self._safe_finalize_failure(error) + self._finalize_failure(error) + _logger.debug( + "GenAI stream close error during close", + exc_info=True, + ) raise - self._safe_finalize_success() + self._finalize_success() def __aiter__(self): # Override ``ObjectProxy.__aiter__`` so iteration drives ``__anext__`` @@ -240,15 +216,13 @@ async def __anext__(self) -> ChunkT: try: chunk = await anext(self._self_aiter) except StopAsyncIteration: - self._safe_finalize_success() + self._finalize_success() raise except Exception as error: - self._safe_finalize_failure(error) + self._finalize_failure(error) raise - try: - self._process_chunk(chunk) - except Exception as error: # pylint: disable=broad-exception-caught - self._handle_process_chunk_error(error) + + self._process_chunk(chunk) return chunk def _finalize_success(self) -> None: @@ -263,24 +237,6 @@ def _finalize_failure(self, error: BaseException) -> None: self._self_finalized = True self._on_stream_error(error) - def _safe_finalize_success(self) -> None: - try: - self._finalize_success() - except Exception: # pylint: disable=broad-exception-caught - _logger.debug( - "GenAI stream instrumentation error during finalization", - exc_info=True, - ) - - def _safe_finalize_failure(self, error: BaseException) -> None: - try: - self._finalize_failure(error) - except Exception: # pylint: disable=broad-exception-caught - _logger.debug( - "GenAI stream instrumentation error during failure finalization", - exc_info=True, - ) - @abstractmethod def _process_chunk(self, chunk: ChunkT) -> None: """Process one stream chunk for telemetry.""" @@ -293,13 +249,6 @@ def _on_stream_end(self) -> None: def _on_stream_error(self, error: BaseException) -> None: """Finalize the stream with failure.""" - @staticmethod - def _handle_process_chunk_error(_error: Exception) -> None: - _logger.debug( - "GenAI stream instrumentation error during chunk processing", - exc_info=True, - ) - __all__ = [ "AsyncStreamWrapper", From 12f50f9f79cbdce20dd42a8cbe92ca437c6c40ab Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 17 Jun 2026 20:09:57 -0700 Subject: [PATCH 2/3] up --- ...reate_instrumentation_error_swallowed.yaml | 138 ---------------- ...tation_error_swallowed[content_mode0].yaml | 148 ------------------ ...tation_error_swallowed[content_mode0].yaml | 125 --------------- .../tests/test_async_responses.py | 38 ----- .../tests/test_chat_completions.py | 25 --- .../tests/test_responses.py | 35 ----- 6 files changed, 509 deletions(-) delete mode 100644 instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/cassettes/test_sync_messages_create_instrumentation_error_swallowed.yaml delete mode 100644 instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_create_instrumentation_error_swallowed[content_mode0].yaml delete mode 100644 instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_create_instrumentation_error_swallowed[content_mode0].yaml diff --git a/instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/cassettes/test_sync_messages_create_instrumentation_error_swallowed.yaml b/instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/cassettes/test_sync_messages_create_instrumentation_error_swallowed.yaml deleted file mode 100644 index ef4a43e2..00000000 --- a/instrumentation/opentelemetry-instrumentation-genai-anthropic/tests/cassettes/test_sync_messages_create_instrumentation_error_swallowed.yaml +++ /dev/null @@ -1,138 +0,0 @@ -interactions: -- request: - body: |- - { - "max_tokens": 100, - "messages": [ - { - "role": "user", - "content": "Say hello in one word." - } - ], - "model": "claude-sonnet-4-20250514", - "stream": true - } - headers: - accept: - - application/json - accept-encoding: - - gzip, deflate - anthropic-version: - - '2023-06-01' - connection: - - keep-alive - content-length: - - '131' - content-type: - - application/json - host: - - api.anthropic.com - user-agent: - - Anthropic/Python 0.75.0 - x-api-key: - - test_anthropic_api_key - x-stainless-arch: - - arm64 - x-stainless-async: - - 'false' - x-stainless-lang: - - python - x-stainless-os: - - MacOS - x-stainless-package-version: - - 0.75.0 - x-stainless-read-timeout: - - '600' - x-stainless-retry-count: - - '0' - x-stainless-runtime: - - CPython - x-stainless-runtime-version: - - 3.9.6 - x-stainless-timeout: - - NOT_GIVEN - method: POST - uri: https://api.anthropic.com/v1/messages - response: - body: - string: |+ - event: message_start - data: {"type":"message_start","message":{"model":"claude-sonnet-4-20250514","id":"msg_01NpSWjDnYM3G9wFsxNwNaBh","type":"message","role":"assistant","content":[],"stop_reason":null,"stop_sequence":null,"usage":{"input_tokens":13,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"cache_creation":{"ephemeral_5m_input_tokens":0,"ephemeral_1h_input_tokens":0},"output_tokens":2,"service_tier":"standard","inference_geo":"not_available"}} } - - event: content_block_start - data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""} } - - event: ping - data: {"type": "ping"} - - event: content_block_delta - data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello!"} } - - event: content_block_stop - data: {"type":"content_block_stop","index":0} - - event: message_delta - data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"input_tokens":13,"cache_creation_input_tokens":0,"cache_read_input_tokens":0,"output_tokens":5} } - - event: message_stop - data: {"type":"message_stop"} - - headers: - CF-RAY: - - 9d6568736addb785-EWR - Cache-Control: - - no-cache - Connection: - - keep-alive - Content-Security-Policy: - - default-src 'none'; frame-ancestors 'none' - Content-Type: - - text/event-stream; charset=utf-8 - Date: - - Tue, 03 Mar 2026 03:03:27 GMT - Server: - - cloudflare - Transfer-Encoding: - - chunked - X-Robots-Tag: - - none - anthropic-ratelimit-input-tokens-limit: - - '450000' - anthropic-ratelimit-input-tokens-remaining: - - '450000' - anthropic-ratelimit-input-tokens-reset: - - '2026-03-03T03:03:26Z' - anthropic-ratelimit-output-tokens-limit: - - '90000' - anthropic-ratelimit-output-tokens-remaining: - - '90000' - anthropic-ratelimit-output-tokens-reset: - - '2026-03-03T03:03:26Z' - anthropic-ratelimit-requests-limit: - - '1000' - anthropic-ratelimit-requests-remaining: - - '999' - anthropic-ratelimit-requests-reset: - - '2026-03-03T03:03:26Z' - anthropic-ratelimit-tokens-limit: - - '540000' - anthropic-ratelimit-tokens-remaining: - - '540000' - anthropic-ratelimit-tokens-reset: - - '2026-03-03T03:03:26Z' - cf-cache-status: - - DYNAMIC - content-length: - - '1094' - request-id: - - req_011CYfQPJSkizN91DEN4ZUpZ - strict-transport-security: - - max-age=31536000; includeSubDomains; preload - vary: - - Accept-Encoding - x-envoy-upstream-service-time: - - '1001' - status: - code: 200 - message: OK -version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_create_instrumentation_error_swallowed[content_mode0].yaml b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_create_instrumentation_error_swallowed[content_mode0].yaml deleted file mode 100644 index af70ff22..00000000 --- a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_async_responses_create_instrumentation_error_swallowed[content_mode0].yaml +++ /dev/null @@ -1,148 +0,0 @@ -interactions: -- request: - body: |- - { - "input": "Say this is a test", - "instructions": "You are a helpful assistant.", - "model": "gpt-4o-mini", - "stream": true - } - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '112' - Content-Type: - - application/json - Host: - - api.openai.com - User-Agent: - - AsyncOpenAI/Python 2.38.0 - X-Stainless-Arch: - - arm64 - X-Stainless-Async: - - async:asyncio - X-Stainless-Lang: - - python - X-Stainless-OS: - - MacOS - X-Stainless-Package-Version: - - 2.38.0 - X-Stainless-Runtime: - - CPython - X-Stainless-Runtime-Version: - - 3.12.12 - authorization: - - Bearer test_openai_api_key - x-stainless-read-timeout: - - '600' - x-stainless-retry-count: - - '0' - method: POST - uri: https://api.openai.com/v1/responses - response: - body: - string: |+ - event: response.created - data: {"type":"response.created","response":{"id":"resp_014bb885a71baa42006a1639f89b108195bb687322856589ba","object":"response","created_at":1779841528,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"context":null,"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} - - event: response.in_progress - data: {"type":"response.in_progress","response":{"id":"resp_014bb885a71baa42006a1639f89b108195bb687322856589ba","object":"response","created_at":1779841528,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"context":null,"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} - - event: response.output_item.added - data: {"type":"response.output_item.added","item":{"id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","type":"message","status":"in_progress","content":[],"role":"assistant"},"output_index":0,"sequence_number":2} - - event: response.content_part.added - data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":"This","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"2Q4NsWGpR6cj","output_index":0,"sequence_number":4} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" is","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"7gDACtp33Fnos","output_index":0,"sequence_number":5} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" a","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"7X1oN5yZ8ZAaDR","output_index":0,"sequence_number":6} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" test","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"r8GPT4wZEv4","output_index":0,"sequence_number":7} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":".","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"rlsiz2CB0edahX6","output_index":0,"sequence_number":8} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" How","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"0VMRRkIcXQHo","output_index":0,"sequence_number":9} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" can","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"byooUOrTf715","output_index":0,"sequence_number":10} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" I","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"BbWCCQLQwfVFMp","output_index":0,"sequence_number":11} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" assist","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"jIWuuSbwv","output_index":0,"sequence_number":12} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" you","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"CgoYX9Jlflc4","output_index":0,"sequence_number":13} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" further","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"pvfXS2YS","output_index":0,"sequence_number":14} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":"?","item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"obfuscation":"naDXTakLQJoisTZ","output_index":0,"sequence_number":15} - - event: response.output_text.done - data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","logprobs":[],"output_index":0,"sequence_number":16,"text":"This is a test. How can I assist you further?"} - - event: response.content_part.done - data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test. How can I assist you further?"},"sequence_number":17} - - event: response.output_item.done - data: {"type":"response.output_item.done","item":{"id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test. How can I assist you further?"}],"role":"assistant"},"output_index":0,"sequence_number":18} - - event: response.completed - data: {"type":"response.completed","response":{"id":"resp_014bb885a71baa42006a1639f89b108195bb687322856589ba","object":"response","created_at":1779841528,"status":"completed","background":false,"completed_at":1779841529,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","moderation":null,"output":[{"id":"msg_014bb885a71baa42006a1639f91efc819595218e2cd72f930c","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test. How can I assist you further?"}],"role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"context":null,"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":22,"input_tokens_details":{"cached_tokens":0},"output_tokens":13,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":35},"user":null,"metadata":{}},"sequence_number":19} - - headers: - Access-Control-Expose-Headers: - - CF-Ray - CF-Cache-Status: - - DYNAMIC - CF-Ray: - - a020e1f16f833547-EWR - Connection: - - keep-alive - Content-Type: - - text/event-stream; charset=utf-8 - Date: - - Wed, 27 May 2026 00:25:28 GMT - Server: - - cloudflare - Strict-Transport-Security: - - max-age=31536000; includeSubDomains; preload - Transfer-Encoding: - - chunked - X-Content-Type-Options: - - nosniff - access-control-expose-headers: - - X-Request-ID - - CF-Ray - alt-svc: - - h3=":443"; ma=86400 - openai-organization: test_openai_org_id - openai-processing-ms: - - '123' - openai-project: test_openai_project_id - openai-version: - - '2020-10-01' - set-cookie: test_set_cookie - x-request-id: - - req_208874b61cb9484081d030f7c3cb08d7 - status: - code: 200 - message: OK -version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_create_instrumentation_error_swallowed[content_mode0].yaml b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_create_instrumentation_error_swallowed[content_mode0].yaml deleted file mode 100644 index 45644ee4..00000000 --- a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/cassettes/test_responses_create_instrumentation_error_swallowed[content_mode0].yaml +++ /dev/null @@ -1,125 +0,0 @@ -interactions: -- request: - body: |- - { - "input": "Say this is a test", - "instructions": "You are a helpful assistant.", - "model": "gpt-4o-mini", - "stream": true - } - headers: - Accept: - - application/json - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '119' - Content-Type: - - application/json - Host: - - api.openai.com - User-Agent: - - OpenAI/Python 1.109.1 - X-Stainless-Arch: - - arm64 - X-Stainless-Async: - - 'false' - X-Stainless-Lang: - - python - X-Stainless-OS: - - MacOS - X-Stainless-Package-Version: - - 1.109.1 - X-Stainless-Runtime: - - CPython - X-Stainless-Runtime-Version: - - 3.12.12 - authorization: - - Bearer test_openai_api_key - x-stainless-read-timeout: - - '600' - x-stainless-retry-count: - - '0' - method: POST - uri: https://api.openai.com/v1/responses - response: - body: - string: |+ - event: response.created - data: {"type":"response.created","response":{"id":"resp_052003e5c7cd2fe10069e2f400498c819f943227bcc94a63a6","object":"response","created_at":1776481280,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":0} - - event: response.in_progress - data: {"type":"response.in_progress","response":{"id":"resp_052003e5c7cd2fe10069e2f400498c819f943227bcc94a63a6","object":"response","created_at":1776481280,"status":"in_progress","background":false,"completed_at":null,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"auto","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":null,"user":null,"metadata":{}},"sequence_number":1} - - event: response.output_item.added - data: {"type":"response.output_item.added","item":{"id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","type":"message","status":"in_progress","content":[],"role":"assistant"},"output_index":0,"sequence_number":2} - - event: response.content_part.added - data: {"type":"response.content_part.added","content_index":0,"item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":""},"sequence_number":3} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":"This","item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"obfuscation":"hmEwhe4L8nm4","output_index":0,"sequence_number":4} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" is","item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"obfuscation":"u3Q5kHUIahzcI","output_index":0,"sequence_number":5} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" a","item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"obfuscation":"0ZnBkOCdgrlbIT","output_index":0,"sequence_number":6} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":" test","item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"obfuscation":"hYsQ5M0hWLs","output_index":0,"sequence_number":7} - - event: response.output_text.delta - data: {"type":"response.output_text.delta","content_index":0,"delta":".","item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"obfuscation":"PyM68hgEwGGLkTN","output_index":0,"sequence_number":8} - - event: response.output_text.done - data: {"type":"response.output_text.done","content_index":0,"item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","logprobs":[],"output_index":0,"sequence_number":9,"text":"This is a test."} - - event: response.content_part.done - data: {"type":"response.content_part.done","content_index":0,"item_id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","output_index":0,"part":{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test."},"sequence_number":10} - - event: response.output_item.done - data: {"type":"response.output_item.done","item":{"id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test."}],"role":"assistant"},"output_index":0,"sequence_number":11} - - event: response.completed - data: {"type":"response.completed","response":{"id":"resp_052003e5c7cd2fe10069e2f400498c819f943227bcc94a63a6","object":"response","created_at":1776481280,"status":"completed","background":false,"completed_at":1776481280,"error":null,"frequency_penalty":0.0,"incomplete_details":null,"instructions":"You are a helpful assistant.","max_output_tokens":null,"max_tool_calls":null,"model":"gpt-4o-mini-2024-07-18","output":[{"id":"msg_052003e5c7cd2fe10069e2f400ec70819f90c4df2a4b73f05c","type":"message","status":"completed","content":[{"type":"output_text","annotations":[],"logprobs":[],"text":"This is a test."}],"role":"assistant"}],"parallel_tool_calls":true,"presence_penalty":0.0,"previous_response_id":null,"prompt_cache_key":null,"prompt_cache_retention":"in_memory","reasoning":{"effort":null,"summary":null},"safety_identifier":null,"service_tier":"default","store":true,"temperature":1.0,"text":{"format":{"type":"text"},"verbosity":"medium"},"tool_choice":"auto","tools":[],"top_logprobs":0,"top_p":1.0,"truncation":"disabled","usage":{"input_tokens":22,"input_tokens_details":{"cached_tokens":0},"output_tokens":6,"output_tokens_details":{"reasoning_tokens":0},"total_tokens":28},"user":null,"metadata":{}},"sequence_number":12} - - headers: - CF-RAY: - - 9ee06ca19ad7606a-EWR - Connection: - - keep-alive - Content-Type: - - text/event-stream; charset=utf-8 - Date: - - Sat, 18 Apr 2026 03:01:20 GMT - Server: - - cloudflare - Set-Cookie: test_set_cookie - Strict-Transport-Security: - - max-age=31536000; includeSubDomains; preload - Transfer-Encoding: - - chunked - X-Content-Type-Options: - - nosniff - alt-svc: - - h3=":443"; ma=86400 - cf-cache-status: - - DYNAMIC - openai-organization: test_openai_org_id - openai-processing-ms: - - '51' - openai-project: - - test_openai_project_id - openai-version: - - '2020-10-01' - set-cookie: - - test_set_cookie - x-request-id: - - req_4e7549325e3f4abaa4ac13b74667292e - status: - code: 200 - message: OK -version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py index 231f66c9..86d41ae1 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py +++ b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_async_responses.py @@ -14,9 +14,6 @@ ) from opentelemetry.instrumentation.genai.openai import OpenAIInstrumentor -from opentelemetry.instrumentation.genai.openai.response_wrappers import ( - AsyncResponseStreamWrapper, -) from opentelemetry.semconv._incubating.attributes import ( error_attributes as ErrorAttributes, ) @@ -656,41 +653,6 @@ async def test_async_responses_create_streaming_user_exception( assert span.attributes[ErrorAttributes.ERROR_TYPE] == "ValueError" -@pytest.mark.asyncio() -async def test_async_responses_create_instrumentation_error_swallowed( - span_exporter, async_openai_client, instrument_no_content, monkeypatch, vcr -): - _skip_if_not_latest() - - def exploding_process_event(self, event): - del self - del event - raise RuntimeError("instrumentation bug") - - monkeypatch.setattr( - AsyncResponseStreamWrapper, "process_event", exploding_process_event - ) - - with vcr.use_cassette( - "test_async_responses_create_instrumentation_error_swallowed[content_mode0].yaml" - ): - async with await async_openai_client.responses.create( - model=DEFAULT_MODEL, - instructions=SYSTEM_INSTRUCTIONS, - input=USER_ONLY_PROMPT[0]["content"], - stream=True, - ) as stream: - events = [event async for event in stream] - - assert len(events) > 0 - - (span,) = span_exporter.get_finished_spans() - assert ( - span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == DEFAULT_MODEL - ) - assert ErrorAttributes.ERROR_TYPE not in span.attributes - - @pytest.mark.asyncio() @pytest.mark.skipif( not _has_tools_param, diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_chat_completions.py b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_chat_completions.py index 07e86a68..0f3ea08d 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_chat_completions.py +++ b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_chat_completions.py @@ -1096,31 +1096,6 @@ def close_raises(): assert "RuntimeError" == spans[0].attributes[ErrorAttributes.ERROR_TYPE] -def test_chat_completion_streaming_instrumentation_finalize_errors_swallowed( - span_exporter, openai_client, instrument_with_content, vcr, monkeypatch -): - if not is_experimental_mode(): - pytest.skip("new stream wrapper only") - - kwargs = { - "model": DEFAULT_MODEL, - "messages": USER_ONLY_PROMPT, - "stream": True, - "stream_options": {"include_usage": True}, - } - - with vcr.use_cassette("test_chat_completion_streaming.yaml"): - response = openai_client.chat.completions.create(**kwargs) - - def stop_raises(): - raise RuntimeError("instrumentation failure") - - monkeypatch.setattr(response, "_on_stream_end", stop_raises) - response.close() - - assert span_exporter.get_finished_spans() == () - - def test_chat_completion_streaming_not_complete( span_exporter, log_exporter, openai_client, instrument_with_content, vcr ): diff --git a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py index af3ee4e0..07c0e2ec 100644 --- a/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py +++ b/instrumentation/opentelemetry-instrumentation-genai-openai/tests/test_responses.py @@ -8,9 +8,6 @@ from openai import APIConnectionError, BadRequestError, NotFoundError, OpenAI from opentelemetry.instrumentation.genai.openai import OpenAIInstrumentor -from opentelemetry.instrumentation.genai.openai.response_wrappers import ( - ResponseStreamWrapper, -) from opentelemetry.semconv._incubating.attributes import ( error_attributes as ErrorAttributes, ) @@ -630,38 +627,6 @@ def test_responses_create_streaming_user_exception( assert span.attributes[ErrorAttributes.ERROR_TYPE] == "ValueError" -@pytest.mark.vcr() -def test_responses_create_instrumentation_error_swallowed( - request, span_exporter, openai_client, instrument_no_content, monkeypatch -): - _skip_if_not_latest() - - def exploding_process_event(self, event): - del self - del event - raise RuntimeError("instrumentation bug") - - monkeypatch.setattr( - ResponseStreamWrapper, "process_event", exploding_process_event - ) - - with openai_client.responses.create( - model=DEFAULT_MODEL, - instructions=SYSTEM_INSTRUCTIONS, - input=USER_ONLY_PROMPT[0]["content"], - stream=True, - ) as stream: - events = list(stream) - - assert len(events) > 0 - - (span,) = span_exporter.get_finished_spans() - assert ( - span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == DEFAULT_MODEL - ) - assert ErrorAttributes.ERROR_TYPE not in span.attributes - - @pytest.mark.vcr() @pytest.mark.skipif( not _has_tools_param, From f9d637f01084c7a6f15528ab662cd13da720b9ed Mon Sep 17 00:00:00 2001 From: Liudmila Molkova Date: Wed, 17 Jun 2026 20:34:02 -0700 Subject: [PATCH 3/3] fix tests --- .../tests/test_stream.py | 154 ------------------ 1 file changed, 154 deletions(-) diff --git a/util/opentelemetry-util-genai/tests/test_stream.py b/util/opentelemetry-util-genai/tests/test_stream.py index dfbb4795..31ac9a1d 100644 --- a/util/opentelemetry-util-genai/tests/test_stream.py +++ b/util/opentelemetry-util-genai/tests/test_stream.py @@ -19,7 +19,6 @@ def test_stream_wrapper_abstract_method_signatures_match(): "_process_chunk", "_on_stream_end", "_on_stream_error", - "_handle_process_chunk_error", ) for method_name in method_names: @@ -178,56 +177,6 @@ def test_sync_stream_wrapper_exit_closes_and_propagates_user_errors(): assert wrapper._self_failures == [error] -def test_sync_stream_wrapper_exit_keeps_user_error_when_close_fails(): - close_error = RuntimeError("close failure") - stream = _FakeSyncStream(chunks=["chunk"], close_error=close_error) - wrapper = _TestSyncStreamWrapper(stream) - error = RuntimeError("user failure") - - assert wrapper.__exit__(RuntimeError, error, None) is False - - assert stream.close_count == 1 - assert wrapper._self_failures == [error] - assert wrapper._self_stop_count == 0 - - -def test_sync_stream_wrapper_swallows_finalize_errors(): - wrapper = _FailingSyncStopStreamWrapper(_FakeSyncStream()) - - wrapper.close() - wrapper.close() - - assert wrapper._self_stop_count == 1 - - -def test_sync_stream_wrapper_swallows_failure_finalize_errors(): - close_error = RuntimeError("close failure") - stream = _FakeSyncStream(close_error=close_error) - wrapper = _FailingSyncFailStreamWrapper(stream) - - with pytest.raises(RuntimeError, match="close failure"): - wrapper.close() - stream._close_error = None - wrapper.close() - - assert wrapper._self_failures == [close_error] - - -def test_sync_stream_wrapper_swallows_stop_iteration_finalize_errors(): - wrapper = _FailingSyncStopStreamWrapper(_FakeSyncStream()) - - with pytest.raises(StopIteration): - next(wrapper) - - -def test_sync_stream_wrapper_preserves_stream_error_when_finalize_fails(): - error = RuntimeError("stream failure") - wrapper = _FailingSyncFailStreamWrapper(_FakeSyncStream(error=error)) - - with pytest.raises(RuntimeError, match="stream failure"): - next(wrapper) - - def test_sync_stream_wrapper_getattr_passthrough(): wrapper = _TestSyncStreamWrapper(_FakeSyncStream()) @@ -258,15 +207,6 @@ def test_sync_stream_wrapper_stop_iteration_does_not_double_finalize(): assert not wrapper._self_failures -def test_sync_stream_wrapper_swallows_process_chunk_errors(): - wrapper = _FailingSyncProcessStreamWrapper( - _FakeSyncStream(chunks=["chunk"]) - ) - - assert next(wrapper) == "chunk" - assert not wrapper._self_failures - - class _FakeAsyncStream: def __init__(self, chunks=None, error=None, close_error=None): self._chunks = list(chunks or []) @@ -323,23 +263,6 @@ def _on_stream_error(self, error): self._self_failures.append(error) -class _FailingAsyncProcessStreamWrapper(_TestAsyncStreamWrapper): - def _process_chunk(self, chunk): - raise ValueError("instrumentation failed") - - -class _FailingAsyncStopStreamWrapper(_TestAsyncStreamWrapper): - def _on_stream_end(self): - self._self_stop_count += 1 - raise ValueError("instrumentation failed") - - -class _FailingAsyncFailStreamWrapper(_TestAsyncStreamWrapper): - def _on_stream_error(self, error): - self._self_failures.append(error) - raise ValueError("instrumentation failed") - - def test_async_stream_wrapper_processes_chunks_and_stops(): async def exercise(): wrapper = _TestAsyncStreamWrapper(_FakeAsyncStream(chunks=["chunk"])) @@ -432,71 +355,6 @@ async def exercise(): asyncio.run(exercise()) -def test_async_stream_wrapper_exit_keeps_user_error_when_close_fails(): - async def exercise(): - close_error = RuntimeError("close failure") - stream = _FakeAsyncStream(chunks=["chunk"], close_error=close_error) - wrapper = _TestAsyncStreamWrapper(stream) - error = RuntimeError("user failure") - - assert await wrapper.__aexit__(RuntimeError, error, None) is False - - assert stream.close_count == 1 - assert wrapper._self_failures == [error] - assert wrapper._self_stop_count == 0 - - asyncio.run(exercise()) - - -def test_async_stream_wrapper_swallows_finalize_errors(): - async def exercise(): - wrapper = _FailingAsyncStopStreamWrapper(_FakeAsyncStream()) - - await wrapper.close() - await wrapper.close() - - assert wrapper._self_stop_count == 1 - - asyncio.run(exercise()) - - -def test_async_stream_wrapper_swallows_failure_finalize_errors(): - async def exercise(): - close_error = RuntimeError("close failure") - stream = _FakeAsyncStream(close_error=close_error) - wrapper = _FailingAsyncFailStreamWrapper(stream) - - with pytest.raises(RuntimeError, match="close failure"): - await wrapper.close() - stream._close_error = None - await wrapper.close() - - assert wrapper._self_failures == [close_error] - - asyncio.run(exercise()) - - -def test_async_stream_wrapper_swallows_stop_iteration_finalize_errors(): - async def exercise(): - wrapper = _FailingAsyncStopStreamWrapper(_FakeAsyncStream()) - - with pytest.raises(StopAsyncIteration): - await anext(wrapper) - - asyncio.run(exercise()) - - -def test_async_stream_wrapper_preserves_stream_error_when_finalize_fails(): - async def exercise(): - error = RuntimeError("stream failure") - wrapper = _FailingAsyncFailStreamWrapper(_FakeAsyncStream(error=error)) - - with pytest.raises(RuntimeError, match="stream failure"): - await anext(wrapper) - - asyncio.run(exercise()) - - def test_async_stream_wrapper_getattr_passthrough(): wrapper = _TestAsyncStreamWrapper(_FakeAsyncStream()) @@ -528,15 +386,3 @@ async def exercise(): assert not wrapper._self_failures asyncio.run(exercise()) - - -def test_async_stream_wrapper_swallows_process_chunk_errors(): - async def exercise(): - wrapper = _FailingAsyncProcessStreamWrapper( - _FakeAsyncStream(chunks=["chunk"]) - ) - - assert await anext(wrapper) == "chunk" - assert not wrapper._self_failures - - asyncio.run(exercise())