telemetry-dev-google-genai 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- telemetry_dev_google_genai-0.1.0/PKG-INFO +134 -0
- telemetry_dev_google_genai-0.1.0/README.md +112 -0
- telemetry_dev_google_genai-0.1.0/pyproject.toml +58 -0
- telemetry_dev_google_genai-0.1.0/src/telemetry_dev_google_genai/__init__.py +1213 -0
- telemetry_dev_google_genai-0.1.0/src/telemetry_dev_google_genai/py.typed +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: telemetry-dev-google-genai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Google GenAI (Gemini) integration for telemetry.dev Python SDK
|
|
5
|
+
Keywords: telemetry,opentelemetry,gemini,google-genai,llm,genai,tracing
|
|
6
|
+
Author: telemetry.dev
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: telemetry-dev>=0.1.0
|
|
17
|
+
Requires-Dist: google-genai>=2,<3
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Project-URL: Homepage, https://telemetry.dev
|
|
20
|
+
Project-URL: Repository, https://github.com/telemetry-dev/telemetry.dev
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# telemetry-dev-google-genai
|
|
24
|
+
|
|
25
|
+
Google GenAI (Gemini) SDK instrumentation for telemetry.dev. It wraps the official `google-genai` Python SDK and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install telemetry-dev-google-genai
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Initialize the core SDK first:
|
|
34
|
+
|
|
35
|
+
```py
|
|
36
|
+
import telemetry_dev
|
|
37
|
+
|
|
38
|
+
telemetry_dev.init(
|
|
39
|
+
api_key="td_live_...",
|
|
40
|
+
base_url="http://localhost:4318",
|
|
41
|
+
service_name="my-service",
|
|
42
|
+
)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Per-client wrapping
|
|
46
|
+
|
|
47
|
+
```py
|
|
48
|
+
from google import genai
|
|
49
|
+
from telemetry_dev_google_genai import wrap_google_genai
|
|
50
|
+
|
|
51
|
+
client = wrap_google_genai(genai.Client(api_key="..."))
|
|
52
|
+
|
|
53
|
+
client.models.generate_content(
|
|
54
|
+
model="gemini-2.5-flash",
|
|
55
|
+
contents=[{"role": "user", "parts": [{"text": "Tell me a joke about OpenTelemetry"}]}],
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use this when you want explicit control over which clients are instrumented. `wrap_google_genai` patches both sync `client.models` and async `client.aio.models`.
|
|
60
|
+
|
|
61
|
+
## Global instrumentation
|
|
62
|
+
|
|
63
|
+
```py
|
|
64
|
+
from google import genai
|
|
65
|
+
from telemetry_dev_google_genai import instrument_google_genai, uninstrument_google_genai
|
|
66
|
+
|
|
67
|
+
instrument_google_genai()
|
|
68
|
+
client = genai.Client(api_key="...")
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
client.models.generate_content(
|
|
72
|
+
model="gemini-2.5-flash",
|
|
73
|
+
contents="Tell me a joke about OpenTelemetry",
|
|
74
|
+
)
|
|
75
|
+
finally:
|
|
76
|
+
uninstrument_google_genai()
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Use this as the app-wide one-liner at startup when all GenAI clients should be instrumented.
|
|
80
|
+
|
|
81
|
+
## Instrumented surfaces
|
|
82
|
+
|
|
83
|
+
Sync and async variants are covered:
|
|
84
|
+
|
|
85
|
+
- `client.models.generate_content(...)` / `client.aio.models.generate_content(...)`
|
|
86
|
+
- `client.models.generate_content_stream(...)` / `client.aio.models.generate_content_stream(...)`
|
|
87
|
+
- `client.models.embed_content(...)` / `client.aio.models.embed_content(...)`
|
|
88
|
+
|
|
89
|
+
`client.chats.create(...).send_message(...)` and `send_message_stream(...)` are covered automatically because they call the wrapped `models` methods.
|
|
90
|
+
|
|
91
|
+
## What gets captured
|
|
92
|
+
|
|
93
|
+
| Gemini signal | telemetry.dev field / attribute |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `model` | `model` |
|
|
96
|
+
| `contents` | `input` |
|
|
97
|
+
| `config.system_instruction` | `system_instructions` |
|
|
98
|
+
| sampling params (`temperature`, `top_p`, `top_k`, `seed`, penalties, `max_output_tokens`, `stop_sequences`) | same-named span fields |
|
|
99
|
+
| JSON / schema output config | `output_type` (`json` or `text`) |
|
|
100
|
+
| `config.candidate_count` | `gen_ai.request.choice.count` |
|
|
101
|
+
| `config.tools` | `gen_ai.tool.definitions` |
|
|
102
|
+
| `config.tool_config`, `safety_settings`, `thinking_config`, `labels`, `cached_content`, `response_modalities` | `google_genai.request.*` attributes |
|
|
103
|
+
| response IDs, model version, finish reasons, output messages, usage tokens | mapped span fields |
|
|
104
|
+
| block/safety/grounding/url-context metadata | `google_genai.response.*` attributes |
|
|
105
|
+
| AFC history on the final response | replaces span `input`; sets `google_genai.automatic_function_calling=true` |
|
|
106
|
+
|
|
107
|
+
The integration maps native Gemini request/response shapes directly. It never mutates caller requests.
|
|
108
|
+
|
|
109
|
+
## Streaming
|
|
110
|
+
|
|
111
|
+
Gemini streams already include cumulative `usage_metadata` on chunks, so no request injection is needed. Stream spans record time-to-first-chunk, aggregate text parts (merging consecutive text with the same `thought` flag), last-seen usage/finish reasons, and end once when the stream completes, errors, or is closed.
|
|
112
|
+
|
|
113
|
+
## Automatic function calling (AFC)
|
|
114
|
+
|
|
115
|
+
When Python callables are passed in `tools`, the SDK may run an internal AFC loop across multiple transport calls. The integration emits one span for the public `generate_content` call and, when present, sets span input to `automatic_function_calling_history`.
|
|
116
|
+
|
|
117
|
+
## Embeddings
|
|
118
|
+
|
|
119
|
+
Embedding calls emit `gen_ai.operation.name = "embeddings"`, request model/input, embedding count/dimension attributes, optional token usage, and optional billable character counts. Embedding vectors are not captured as output.
|
|
120
|
+
|
|
121
|
+
## Provider values
|
|
122
|
+
|
|
123
|
+
- Gemini Developer API clients record provider `gcp.gemini`.
|
|
124
|
+
- Vertex AI clients (`vertexai=True`) record provider `gcp.vertex_ai`.
|
|
125
|
+
|
|
126
|
+
## Fail-open guarantee
|
|
127
|
+
|
|
128
|
+
Mapping code is defensive; wrapped calls return the SDK response unchanged and re-raise exceptions untouched. Telemetry bugs never break callers.
|
|
129
|
+
|
|
130
|
+
## Limitations
|
|
131
|
+
|
|
132
|
+
- Not instrumented: `count_tokens`, `compute_tokens`, `generate_images`, `generate_videos`, `live`, `caches`, `files`, `tunings`, `batches`.
|
|
133
|
+
- Deliberately not captured: logprobs, citation metadata, per-modality token detail arrays, `create_time`, `sdk_http_response`.
|
|
134
|
+
- Unconsumed streams end their spans only when the stream is exhausted, errors, or is closed.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# telemetry-dev-google-genai
|
|
2
|
+
|
|
3
|
+
Google GenAI (Gemini) SDK instrumentation for telemetry.dev. It wraps the official `google-genai` Python SDK and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pip install telemetry-dev-google-genai
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Initialize the core SDK first:
|
|
12
|
+
|
|
13
|
+
```py
|
|
14
|
+
import telemetry_dev
|
|
15
|
+
|
|
16
|
+
telemetry_dev.init(
|
|
17
|
+
api_key="td_live_...",
|
|
18
|
+
base_url="http://localhost:4318",
|
|
19
|
+
service_name="my-service",
|
|
20
|
+
)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Per-client wrapping
|
|
24
|
+
|
|
25
|
+
```py
|
|
26
|
+
from google import genai
|
|
27
|
+
from telemetry_dev_google_genai import wrap_google_genai
|
|
28
|
+
|
|
29
|
+
client = wrap_google_genai(genai.Client(api_key="..."))
|
|
30
|
+
|
|
31
|
+
client.models.generate_content(
|
|
32
|
+
model="gemini-2.5-flash",
|
|
33
|
+
contents=[{"role": "user", "parts": [{"text": "Tell me a joke about OpenTelemetry"}]}],
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use this when you want explicit control over which clients are instrumented. `wrap_google_genai` patches both sync `client.models` and async `client.aio.models`.
|
|
38
|
+
|
|
39
|
+
## Global instrumentation
|
|
40
|
+
|
|
41
|
+
```py
|
|
42
|
+
from google import genai
|
|
43
|
+
from telemetry_dev_google_genai import instrument_google_genai, uninstrument_google_genai
|
|
44
|
+
|
|
45
|
+
instrument_google_genai()
|
|
46
|
+
client = genai.Client(api_key="...")
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
client.models.generate_content(
|
|
50
|
+
model="gemini-2.5-flash",
|
|
51
|
+
contents="Tell me a joke about OpenTelemetry",
|
|
52
|
+
)
|
|
53
|
+
finally:
|
|
54
|
+
uninstrument_google_genai()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Use this as the app-wide one-liner at startup when all GenAI clients should be instrumented.
|
|
58
|
+
|
|
59
|
+
## Instrumented surfaces
|
|
60
|
+
|
|
61
|
+
Sync and async variants are covered:
|
|
62
|
+
|
|
63
|
+
- `client.models.generate_content(...)` / `client.aio.models.generate_content(...)`
|
|
64
|
+
- `client.models.generate_content_stream(...)` / `client.aio.models.generate_content_stream(...)`
|
|
65
|
+
- `client.models.embed_content(...)` / `client.aio.models.embed_content(...)`
|
|
66
|
+
|
|
67
|
+
`client.chats.create(...).send_message(...)` and `send_message_stream(...)` are covered automatically because they call the wrapped `models` methods.
|
|
68
|
+
|
|
69
|
+
## What gets captured
|
|
70
|
+
|
|
71
|
+
| Gemini signal | telemetry.dev field / attribute |
|
|
72
|
+
|---|---|
|
|
73
|
+
| `model` | `model` |
|
|
74
|
+
| `contents` | `input` |
|
|
75
|
+
| `config.system_instruction` | `system_instructions` |
|
|
76
|
+
| sampling params (`temperature`, `top_p`, `top_k`, `seed`, penalties, `max_output_tokens`, `stop_sequences`) | same-named span fields |
|
|
77
|
+
| JSON / schema output config | `output_type` (`json` or `text`) |
|
|
78
|
+
| `config.candidate_count` | `gen_ai.request.choice.count` |
|
|
79
|
+
| `config.tools` | `gen_ai.tool.definitions` |
|
|
80
|
+
| `config.tool_config`, `safety_settings`, `thinking_config`, `labels`, `cached_content`, `response_modalities` | `google_genai.request.*` attributes |
|
|
81
|
+
| response IDs, model version, finish reasons, output messages, usage tokens | mapped span fields |
|
|
82
|
+
| block/safety/grounding/url-context metadata | `google_genai.response.*` attributes |
|
|
83
|
+
| AFC history on the final response | replaces span `input`; sets `google_genai.automatic_function_calling=true` |
|
|
84
|
+
|
|
85
|
+
The integration maps native Gemini request/response shapes directly. It never mutates caller requests.
|
|
86
|
+
|
|
87
|
+
## Streaming
|
|
88
|
+
|
|
89
|
+
Gemini streams already include cumulative `usage_metadata` on chunks, so no request injection is needed. Stream spans record time-to-first-chunk, aggregate text parts (merging consecutive text with the same `thought` flag), last-seen usage/finish reasons, and end once when the stream completes, errors, or is closed.
|
|
90
|
+
|
|
91
|
+
## Automatic function calling (AFC)
|
|
92
|
+
|
|
93
|
+
When Python callables are passed in `tools`, the SDK may run an internal AFC loop across multiple transport calls. The integration emits one span for the public `generate_content` call and, when present, sets span input to `automatic_function_calling_history`.
|
|
94
|
+
|
|
95
|
+
## Embeddings
|
|
96
|
+
|
|
97
|
+
Embedding calls emit `gen_ai.operation.name = "embeddings"`, request model/input, embedding count/dimension attributes, optional token usage, and optional billable character counts. Embedding vectors are not captured as output.
|
|
98
|
+
|
|
99
|
+
## Provider values
|
|
100
|
+
|
|
101
|
+
- Gemini Developer API clients record provider `gcp.gemini`.
|
|
102
|
+
- Vertex AI clients (`vertexai=True`) record provider `gcp.vertex_ai`.
|
|
103
|
+
|
|
104
|
+
## Fail-open guarantee
|
|
105
|
+
|
|
106
|
+
Mapping code is defensive; wrapped calls return the SDK response unchanged and re-raise exceptions untouched. Telemetry bugs never break callers.
|
|
107
|
+
|
|
108
|
+
## Limitations
|
|
109
|
+
|
|
110
|
+
- Not instrumented: `count_tokens`, `compute_tokens`, `generate_images`, `generate_videos`, `live`, `caches`, `files`, `tunings`, `batches`.
|
|
111
|
+
- Deliberately not captured: logprobs, citation metadata, per-modality token detail arrays, `create_time`, `sdk_http_response`.
|
|
112
|
+
- Unconsumed streams end their spans only when the stream is exhausted, errors, or is closed.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "telemetry-dev-google-genai"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Google GenAI (Gemini) integration for telemetry.dev Python SDK"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "MIT"
|
|
7
|
+
requires-python = ">=3.10"
|
|
8
|
+
authors = [{ name = "telemetry.dev" }]
|
|
9
|
+
keywords = ["telemetry", "opentelemetry", "gemini", "google-genai", "llm", "genai", "tracing"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.10",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
dependencies = [
|
|
21
|
+
"telemetry-dev>=0.1.0",
|
|
22
|
+
"google-genai>=2,<3",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Homepage = "https://telemetry.dev"
|
|
27
|
+
Repository = "https://github.com/telemetry-dev/telemetry.dev"
|
|
28
|
+
|
|
29
|
+
[tool.uv.sources]
|
|
30
|
+
telemetry-dev = { path = "../python", editable = true }
|
|
31
|
+
|
|
32
|
+
[dependency-groups]
|
|
33
|
+
dev = [
|
|
34
|
+
"pytest>=8.3",
|
|
35
|
+
"pytest-asyncio>=0.25",
|
|
36
|
+
"ruff>=0.9",
|
|
37
|
+
"pyright>=1.1.390",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["uv_build>=0.9.0,<0.10.0"]
|
|
42
|
+
build-backend = "uv_build"
|
|
43
|
+
|
|
44
|
+
[tool.pytest.ini_options]
|
|
45
|
+
asyncio_mode = "auto"
|
|
46
|
+
testpaths = ["tests"]
|
|
47
|
+
|
|
48
|
+
[tool.ruff]
|
|
49
|
+
line-length = 100
|
|
50
|
+
target-version = "py310"
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint]
|
|
53
|
+
select = ["E", "F", "I", "UP", "B", "RUF"]
|
|
54
|
+
|
|
55
|
+
[tool.pyright]
|
|
56
|
+
include = ["src", "tests"]
|
|
57
|
+
typeCheckingMode = "strict"
|
|
58
|
+
pythonVersion = "3.10"
|