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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion instrumentation-genai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
| --------------- | ------------------ | --------------- | -------------- |
| [opentelemetry-instrumentation-anthropic](./opentelemetry-instrumentation-anthropic) | anthropic >= 0.16.0 | No | development
| [opentelemetry-instrumentation-claude-agent-sdk](./opentelemetry-instrumentation-claude-agent-sdk) | claude-agent-sdk >= 0.1.14 | No | development
| [opentelemetry-instrumentation-google-genai](./opentelemetry-instrumentation-google-genai) | google-genai >= 1.0.0 | No | development
| [opentelemetry-instrumentation-google-genai](./opentelemetry-instrumentation-google-genai) | google-genai >= 1.32.0 | No | development
| [opentelemetry-instrumentation-langchain](./opentelemetry-instrumentation-langchain) | langchain >= 0.3.21 | No | development
| [opentelemetry-instrumentation-openai-agents-v2](./opentelemetry-instrumentation-openai-agents-v2) | openai-agents >= 0.3.3 | No | development
| [opentelemetry-instrumentation-openai-v2](./opentelemetry-instrumentation-openai-v2) | openai >= 1.26.0 | Yes | development
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.

_instruments = ("google-genai >= 1.0.0",)
_instruments = ("google-genai >= 1.32.0",)
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@
from google.genai import types
from vcr.record_mode import RecordMode

try:
# These modules are only supported in python >= 3.10
from aiohttp.client_exceptions import ClientConnectionError
from vcr.stubs import aiohttp_stubs
except ImportError:
ClientConnectionError = None
aiohttp_stubs = None

from opentelemetry.instrumentation._semconv import (
OTEL_SEMCONV_STABILITY_OPT_IN,
_OpenTelemetrySemanticConventionStability,
Expand Down Expand Up @@ -135,6 +143,9 @@ def _redact_headers(headers):


def _before_record_request(request):
# aiohttp reports the request method in lower case while it is recorded in the cassette in upper case.
if request.method:
request.method = request.method.upper()
Comment thread
Rima-ag marked this conversation as resolved.
if request.headers:
_redact_headers(request.headers)
uri = request.uri
Expand Down Expand Up @@ -316,6 +327,48 @@ def setup_vcr(vcr):
return vcr


@pytest.fixture(name="patch_vcr_aiohttp_stream", scope="module", autouse=True)
def fixture_patch_vcr_aiohttp_stream():
Comment thread
Rima-ag marked this conversation as resolved.
# Allows the async tests to not be stuck in infinite loop when streaming
# a VCR cassette with aiohttp stubs.
# https://github.com/kevin1024/vcrpy/issues/927
if ClientConnectionError is None or aiohttp_stubs is None:
return

class _ReplayMockStream(aiohttp_stubs.MockStream):
# Keep vcrpy's stream behavior, but ignore aiohttp's
# close-time ClientConnectionError("Connection closed") during
# cassette replay, where the full response is already buffered
# and this condition should be treated as normal EOF.
def set_exception(self, exc):
if isinstance(exc, ClientConnectionError) and exc.args == (
"Connection closed",
):
return
super().set_exception(exc)

class _ReplayMockClientResponse(aiohttp_stubs.MockClientResponse):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._mock_content_stream = None

@property
def content(self):
# vcrpy's aiohttp MockClientResponse.content creates a fresh stream object
# on every property access. google-genai async streaming repeatedly reads
# response.content.readline() and expects the same stream instance until EOF is
# reached.
if self._mock_content_stream is None:
body = self._body or b""
stream = _ReplayMockStream()
stream.feed_data(body)
stream.feed_eof()
self._mock_content_stream = stream
return self._mock_content_stream

aiohttp_stubs.MockClientResponse = _ReplayMockClientResponse


@pytest.fixture(name="instrumentor")
def fixture_instrumentor():
return GoogleGenAiSdkInstrumentor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ pytest==7.4.4
pytest-asyncio==0.21.0
pytest-vcr==1.0.2

google-auth==2.38.0
google-genai==1.32.0
google-auth==2.47.0

google-genai==1.47.0; python_version < "3.10"
google-genai==1.64.0; python_version >= "3.10"

# Install locally from the folder. This path is relative to the
# root directory, given invocation from "tox" at root level.
Expand Down