-
Notifications
You must be signed in to change notification settings - Fork 441
feat(google_genai): [MLOB-2932] add apm tracing for google-genai #13650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 34 commits
0f7eb0f
fc11773
4bc8e81
b6774bf
245dd33
88a6346
dbe7406
3c0bffd
d8abc0c
37cda72
4183303
95365d6
c8963b6
aa3eaab
f6549b4
545c3a5
a9e197b
72ae21b
fd72fa7
b9d5720
977ac43
7f6e417
87952f2
a6ee277
2115a0a
15b759f
156c69c
e5e9341
c6e8389
29fd0e5
d462cde
dc9d313
58c73e0
465e701
24d19ac
6b74729
769cdb9
05e50fe
7659f71
062a6aa
72b6109
505be8b
7b8564a
caa7c24
cd2ed4f
d4e3bf7
1dc8558
7b448e0
ae82d6f
a9aee36
1a1e7cf
25e7c73
5a8b350
f0a8d0e
ed9d83d
370dcf5
e0bbe1f
c70af6e
cfd96ff
c9694cc
eb33c02
f16b9b5
2aef56b
ade4b18
5457a43
9410a72
ff784fa
2504406
23ab599
efdb368
977aa82
0fcd51e
66a350a
c25b7a7
2a61f43
d75a9e0
ec49525
4bcd653
679593f
078dfbe
5be2c9a
6623f00
63a6727
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# | ||
# This file is autogenerated by pip-compile with Python 3.11 | ||
# by the following command: | ||
# | ||
# pip-compile --allow-unsafe --no-annotate .riot/requirements/1de4a65.in | ||
# | ||
annotated-types==0.7.0 | ||
anyio==4.9.0 | ||
attrs==25.3.0 | ||
cachetools==5.5.2 | ||
certifi==2025.4.26 | ||
charset-normalizer==3.4.2 | ||
coverage[toml]==7.9.0 | ||
google-auth==2.40.3 | ||
google-genai==1.20.0 | ||
h11==0.16.0 | ||
httpcore==1.0.9 | ||
httpx==0.28.1 | ||
hypothesis==6.45.0 | ||
idna==3.10 | ||
iniconfig==2.1.0 | ||
mock==5.2.0 | ||
multidict==6.4.4 | ||
opentracing==2.4.0 | ||
packaging==25.0 | ||
pluggy==1.6.0 | ||
propcache==0.3.2 | ||
pyasn1==0.6.1 | ||
pyasn1-modules==0.4.2 | ||
pydantic==2.11.5 | ||
pydantic-core==2.33.2 | ||
pygments==2.19.1 | ||
pytest==8.4.0 | ||
pytest-asyncio==1.0.0 | ||
pytest-cov==6.2.1 | ||
pytest-mock==3.14.1 | ||
pyyaml==6.0.2 | ||
requests==2.32.4 | ||
rsa==4.9.1 | ||
sniffio==1.3.1 | ||
sortedcontainers==2.4.0 | ||
typing-extensions==4.14.0 | ||
typing-inspection==0.4.1 | ||
urllib3==2.4.0 | ||
vcrpy==7.0.0 | ||
websockets==15.0.1 | ||
wrapt==1.17.2 | ||
yarl==1.20.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# | ||
# This file is autogenerated by pip-compile with Python 3.10 | ||
# by the following command: | ||
# | ||
# pip-compile --allow-unsafe --no-annotate .riot/requirements/7d83e7d.in | ||
# | ||
annotated-types==0.7.0 | ||
anyio==4.9.0 | ||
attrs==25.3.0 | ||
cachetools==5.5.2 | ||
certifi==2025.4.26 | ||
charset-normalizer==3.4.2 | ||
coverage[toml]==7.9.0 | ||
exceptiongroup==1.3.0 | ||
google-auth==2.40.3 | ||
google-genai==1.20.0 | ||
h11==0.16.0 | ||
httpcore==1.0.9 | ||
httpx==0.28.1 | ||
hypothesis==6.45.0 | ||
idna==3.10 | ||
iniconfig==2.1.0 | ||
mock==5.2.0 | ||
multidict==6.4.4 | ||
opentracing==2.4.0 | ||
packaging==25.0 | ||
pluggy==1.6.0 | ||
propcache==0.3.2 | ||
pyasn1==0.6.1 | ||
pyasn1-modules==0.4.2 | ||
pydantic==2.11.5 | ||
pydantic-core==2.33.2 | ||
pygments==2.19.1 | ||
pytest==8.4.0 | ||
pytest-asyncio==1.0.0 | ||
pytest-cov==6.2.1 | ||
pytest-mock==3.14.1 | ||
pyyaml==6.0.2 | ||
requests==2.32.4 | ||
rsa==4.9.1 | ||
sniffio==1.3.1 | ||
sortedcontainers==2.4.0 | ||
tomli==2.2.1 | ||
typing-extensions==4.14.0 | ||
typing-inspection==0.4.1 | ||
urllib3==2.4.0 | ||
vcrpy==7.0.0 | ||
websockets==15.0.1 | ||
wrapt==1.17.2 | ||
yarl==1.20.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# | ||
# This file is autogenerated by pip-compile with Python 3.12 | ||
# by the following command: | ||
# | ||
# pip-compile --allow-unsafe --no-annotate .riot/requirements/ce785c0.in | ||
# | ||
annotated-types==0.7.0 | ||
anyio==4.9.0 | ||
attrs==25.3.0 | ||
cachetools==5.5.2 | ||
certifi==2025.4.26 | ||
charset-normalizer==3.4.2 | ||
coverage[toml]==7.9.0 | ||
google-auth==2.40.3 | ||
google-genai==1.20.0 | ||
h11==0.16.0 | ||
httpcore==1.0.9 | ||
httpx==0.28.1 | ||
hypothesis==6.45.0 | ||
idna==3.10 | ||
iniconfig==2.1.0 | ||
mock==5.2.0 | ||
multidict==6.4.4 | ||
opentracing==2.4.0 | ||
packaging==25.0 | ||
pluggy==1.6.0 | ||
propcache==0.3.2 | ||
pyasn1==0.6.1 | ||
pyasn1-modules==0.4.2 | ||
pydantic==2.11.5 | ||
pydantic-core==2.33.2 | ||
pygments==2.19.1 | ||
pytest==8.4.0 | ||
pytest-asyncio==1.0.0 | ||
pytest-cov==6.2.1 | ||
pytest-mock==3.14.1 | ||
pyyaml==6.0.2 | ||
requests==2.32.4 | ||
rsa==4.9.1 | ||
sniffio==1.3.1 | ||
sortedcontainers==2.4.0 | ||
typing-extensions==4.14.0 | ||
typing-inspection==0.4.1 | ||
urllib3==2.4.0 | ||
vcrpy==7.0.0 | ||
websockets==15.0.1 | ||
wrapt==1.17.2 | ||
yarl==1.20.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# | ||
# This file is autogenerated by pip-compile with Python 3.9 | ||
# by the following command: | ||
# | ||
# pip-compile --allow-unsafe --no-annotate .riot/requirements/f5e518d.in | ||
# | ||
annotated-types==0.7.0 | ||
anyio==4.9.0 | ||
attrs==25.3.0 | ||
cachetools==5.5.2 | ||
certifi==2025.4.26 | ||
charset-normalizer==3.4.2 | ||
coverage[toml]==7.9.0 | ||
exceptiongroup==1.3.0 | ||
google-auth==2.40.3 | ||
google-genai==1.20.0 | ||
h11==0.16.0 | ||
httpcore==1.0.9 | ||
httpx==0.28.1 | ||
hypothesis==6.45.0 | ||
idna==3.10 | ||
iniconfig==2.1.0 | ||
mock==5.2.0 | ||
multidict==6.4.4 | ||
opentracing==2.4.0 | ||
packaging==25.0 | ||
pluggy==1.6.0 | ||
propcache==0.3.2 | ||
pyasn1==0.6.1 | ||
pyasn1-modules==0.4.2 | ||
pydantic==2.11.5 | ||
pydantic-core==2.33.2 | ||
pygments==2.19.1 | ||
pytest==8.4.0 | ||
pytest-asyncio==1.0.0 | ||
pytest-cov==6.2.1 | ||
pytest-mock==3.14.1 | ||
pyyaml==6.0.2 | ||
requests==2.32.4 | ||
rsa==4.9.1 | ||
sniffio==1.3.1 | ||
sortedcontainers==2.4.0 | ||
tomli==2.2.1 | ||
typing-extensions==4.14.0 | ||
typing-inspection==0.4.1 | ||
urllib3==1.26.20 | ||
vcrpy==7.0.0 | ||
websockets==15.0.1 | ||
wrapt==1.17.2 | ||
yarl==1.20.1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
""" | ||
The Google GenAI integration instruments the Google GenAI Python SDK to trace for requests made to Google models. | ||
|
||
All traces submitted from the Google GenAI integration are tagged by: | ||
|
||
- ``service``, ``env``, ``version``: see the `Unified Service Tagging docs <https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging>`_. | ||
- model used in the request. | ||
- provider used in the request. | ||
|
||
(beta) Prompt and Completion Sampling | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
Prompt texts and completion content are collected in span tags with a default sampling rate of ``1.0`` | ||
for the following methods: | ||
|
||
- ``generate_content/generate_content_stream`` of the ``google.genai.models.Models`` class | ||
|
||
These tags will have truncation applied if the text exceeds the configured character limit. | ||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Enabling | ||
~~~~~~~~ | ||
|
||
The Google GenAI integration is enabled automatically when you use | ||
:ref:`ddtrace-run<ddtracerun>` or :ref:`import ddtrace.auto<ddtraceauto>`. | ||
|
||
Alternatively, use :func:`patch() <ddtrace.patch>` to manually enable the Google GenAI integration:: | ||
|
||
from ddtrace import config, patch | ||
|
||
patch(google_genai=True) | ||
|
||
Global Configuration | ||
~~~~~~~~~~~~~~~~~~~~ | ||
|
||
.. py:data:: ddtrace.config.google_genai["service"] | ||
|
||
The service name reported by default for Google GenAI requests. | ||
|
||
Alternatively, you can set this option with the ``DD_SERVICE`` or ``DD_VERTEXAI_SERVICE`` environment | ||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
variables. | ||
|
||
Default: ``DD_SERVICE`` | ||
|
||
|
||
Instance Configuration | ||
~~~~~~~~~~~~~~~~~~~~~~ | ||
|
||
To configure the Google GenAI integration on a per-instance basis use the | ||
``Pin`` API:: | ||
|
||
from google import genai | ||
from ddtrace import config | ||
from ddtrace.trace import Pin | ||
|
||
Pin.override(genai, service="my-google-genai-service") | ||
""" |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,50 @@ | ||||||||||
import sys | ||||||||||
|
||||||||||
|
||||||||||
# https://cloud.google.com/vertex-ai/generative-ai/docs/model-garden/quickstart | ||||||||||
# for vertex, it seems like the best way to associate provider name with each call is based on the model name prefix | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I checked this link and it doesn't seem to show the model names in the below context. Is this the correct link?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wasn't able to find a definitive source for providers. Unlike what we initially thought, its hard to get the provider from the full path since it is not required and users can simply provide a model name. : https://github.com/googleapis/python-genai/blob/main/google/genai/models.py#L6005 So this code is a bit more best-effort. Gemini only exports google provided models whereas vertex lists supported models on the left side of the provided link. I just manually mapped supported models to providers. Let me know if you have any suggestions on how to improve this part. |
||||||||||
MODEL_PREFIX_TO_PROVIDER = { | ||||||||||
"gemini": "google", | ||||||||||
"imagen": "google", | ||||||||||
"veo": "google", | ||||||||||
"jamba": "ai21labs", | ||||||||||
"claude": "anthropic", | ||||||||||
"llama": "meta", | ||||||||||
"mistral": "mistral", | ||||||||||
} | ||||||||||
|
||||||||||
|
||||||||||
def extract_provider_and_model_name_genai(kwargs): | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
model_name = kwargs.get("model", "").split("/")[-1] | ||||||||||
provider_name = "other" | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
for prefix in MODEL_PREFIX_TO_PROVIDER.keys(): | ||||||||||
if model_name.startswith(prefix): | ||||||||||
provider_name = MODEL_PREFIX_TO_PROVIDER[prefix] | ||||||||||
return provider_name, model_name if len(model_name) > 0 else "unknown" | ||||||||||
|
||||||||||
|
||||||||||
class BaseTracedGoogleGenAIStreamResponse: | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
def __init__(self, generation_response, integration, span, args, kwargs): | ||||||||||
self._generation_response = generation_response | ||||||||||
self._integration = integration | ||||||||||
self._dd_span = span | ||||||||||
self._args = args | ||||||||||
self._kwargs = kwargs | ||||||||||
self._chunks = [] | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
|
||||||||||
|
||||||||||
class TracedGoogleGenAIStreamResponse(BaseTracedGoogleGenAIStreamResponse): | ||||||||||
# generate_content_stream returns Iterator[GenerateContentResponse] | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
def __iter__(self): | ||||||||||
return self | ||||||||||
|
||||||||||
def __next__(self): | ||||||||||
try: | ||||||||||
chunk = self._generation_response.__next__() | ||||||||||
self._chunks.append(chunk) | ||||||||||
return chunk | ||||||||||
except StopIteration: | ||||||||||
raise | ||||||||||
except Exception: | ||||||||||
self._dd_span.set_exc_info(*sys.exc_info()) | ||||||||||
raise | ||||||||||
maxzhangdd marked this conversation as resolved.
Show resolved
Hide resolved
|
Uh oh!
There was an error while loading. Please reload this page.