telemetry-dev-openai 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.
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: telemetry-dev-openai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenAI integration for telemetry.dev Python SDK
|
|
5
|
+
Keywords: telemetry,opentelemetry,openai,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: openai>=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-openai
|
|
24
|
+
|
|
25
|
+
OpenAI SDK instrumentation for telemetry.dev. It wraps the official `openai` Python SDK and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install telemetry-dev-openai
|
|
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 openai import OpenAI
|
|
49
|
+
from telemetry_dev_openai import wrap_openai
|
|
50
|
+
|
|
51
|
+
client = wrap_openai(OpenAI())
|
|
52
|
+
|
|
53
|
+
client.chat.completions.create(
|
|
54
|
+
model="gpt-4o-mini",
|
|
55
|
+
messages=[{"role": "user", "content": "Tell me a joke about OpenTelemetry"}],
|
|
56
|
+
)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Use this when you want explicit control over which sync or async clients are instrumented.
|
|
60
|
+
|
|
61
|
+
## Global instrumentation
|
|
62
|
+
|
|
63
|
+
```py
|
|
64
|
+
from openai import OpenAI
|
|
65
|
+
from telemetry_dev_openai import instrument_openai, uninstrument_openai
|
|
66
|
+
|
|
67
|
+
instrument_openai()
|
|
68
|
+
client = OpenAI()
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
client.responses.create(model="gpt-4o-mini", input="Tell me a joke about OpenTelemetry")
|
|
72
|
+
finally:
|
|
73
|
+
uninstrument_openai()
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Use this as the app-wide one-liner at startup when all OpenAI clients should be instrumented.
|
|
77
|
+
|
|
78
|
+
## Instrumented surfaces
|
|
79
|
+
|
|
80
|
+
Sync and async variants are covered:
|
|
81
|
+
|
|
82
|
+
- `client.chat.completions.create(...)`
|
|
83
|
+
- `client.chat.completions.parse(...)`
|
|
84
|
+
- `client.chat.completions.stream(...)`
|
|
85
|
+
- `client.responses.create(...)`
|
|
86
|
+
- `client.responses.parse(...)`
|
|
87
|
+
- `client.responses.stream(...)` when starting a new response
|
|
88
|
+
- `client.embeddings.create(...)`
|
|
89
|
+
|
|
90
|
+
The integration maps native OpenAI request/response shapes directly into telemetry.dev fields. It does not normalize messages into another schema.
|
|
91
|
+
|
|
92
|
+
## Streaming
|
|
93
|
+
|
|
94
|
+
Chat completion streams are traced. Requests are sent unchanged by default, so token usage is only captured when the caller sets `stream_options={"include_usage": True}` themselves. Pass `inject_stream_usage=True` to `wrap_openai` or `instrument_openai` to inject it automatically; the synthetic usage-only chunk is then hidden from the caller. Injection is opt-in because some providers reject `stream_options` — for example Azure OpenAI "on your data" (`data_sources`) returns 400 for it while plain `stream=True` works.
|
|
95
|
+
|
|
96
|
+
```py
|
|
97
|
+
client = wrap_openai(OpenAI(), inject_stream_usage=True)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Responses API streams are traced through `responses.create(stream=True)`; terminal `response.completed`, `response.failed`, and `response.incomplete` events close the span.
|
|
101
|
+
|
|
102
|
+
## Embeddings
|
|
103
|
+
|
|
104
|
+
Embedding calls emit `gen_ai.operation.name = "embeddings"`, request model/input, response model, and token usage. Embedding vectors are intentionally not captured as output.
|
|
105
|
+
|
|
106
|
+
## Azure OpenAI
|
|
107
|
+
|
|
108
|
+
`wrap_openai(AzureOpenAI(...))` and `wrap_openai(AsyncAzureOpenAI(...))` record provider `azure.ai.openai`. Global class instrumentation detects Azure from the resource client when available.
|
|
109
|
+
|
|
110
|
+
## Limitations
|
|
111
|
+
|
|
112
|
+
- `with_raw_response` snapshots bound methods on first access in the OpenAI Python SDK. Call `wrap_openai()` or `instrument_openai()` before accessing `with_raw_response` if those methods need instrumentation.
|
|
113
|
+
- `responses.stream(response_id=...)` resumes an existing response through `retrieve()`, which is not instrumented in this version.
|
|
114
|
+
- Unconsumed streams end their spans only when the stream is exhausted, errors, or is closed.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# telemetry-dev-openai
|
|
2
|
+
|
|
3
|
+
OpenAI SDK instrumentation for telemetry.dev. It wraps the official `openai` Python SDK and emits telemetry.dev generation and embedding spans through `telemetry-dev`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
pip install telemetry-dev-openai
|
|
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 openai import OpenAI
|
|
27
|
+
from telemetry_dev_openai import wrap_openai
|
|
28
|
+
|
|
29
|
+
client = wrap_openai(OpenAI())
|
|
30
|
+
|
|
31
|
+
client.chat.completions.create(
|
|
32
|
+
model="gpt-4o-mini",
|
|
33
|
+
messages=[{"role": "user", "content": "Tell me a joke about OpenTelemetry"}],
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use this when you want explicit control over which sync or async clients are instrumented.
|
|
38
|
+
|
|
39
|
+
## Global instrumentation
|
|
40
|
+
|
|
41
|
+
```py
|
|
42
|
+
from openai import OpenAI
|
|
43
|
+
from telemetry_dev_openai import instrument_openai, uninstrument_openai
|
|
44
|
+
|
|
45
|
+
instrument_openai()
|
|
46
|
+
client = OpenAI()
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
client.responses.create(model="gpt-4o-mini", input="Tell me a joke about OpenTelemetry")
|
|
50
|
+
finally:
|
|
51
|
+
uninstrument_openai()
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use this as the app-wide one-liner at startup when all OpenAI clients should be instrumented.
|
|
55
|
+
|
|
56
|
+
## Instrumented surfaces
|
|
57
|
+
|
|
58
|
+
Sync and async variants are covered:
|
|
59
|
+
|
|
60
|
+
- `client.chat.completions.create(...)`
|
|
61
|
+
- `client.chat.completions.parse(...)`
|
|
62
|
+
- `client.chat.completions.stream(...)`
|
|
63
|
+
- `client.responses.create(...)`
|
|
64
|
+
- `client.responses.parse(...)`
|
|
65
|
+
- `client.responses.stream(...)` when starting a new response
|
|
66
|
+
- `client.embeddings.create(...)`
|
|
67
|
+
|
|
68
|
+
The integration maps native OpenAI request/response shapes directly into telemetry.dev fields. It does not normalize messages into another schema.
|
|
69
|
+
|
|
70
|
+
## Streaming
|
|
71
|
+
|
|
72
|
+
Chat completion streams are traced. Requests are sent unchanged by default, so token usage is only captured when the caller sets `stream_options={"include_usage": True}` themselves. Pass `inject_stream_usage=True` to `wrap_openai` or `instrument_openai` to inject it automatically; the synthetic usage-only chunk is then hidden from the caller. Injection is opt-in because some providers reject `stream_options` — for example Azure OpenAI "on your data" (`data_sources`) returns 400 for it while plain `stream=True` works.
|
|
73
|
+
|
|
74
|
+
```py
|
|
75
|
+
client = wrap_openai(OpenAI(), inject_stream_usage=True)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Responses API streams are traced through `responses.create(stream=True)`; terminal `response.completed`, `response.failed`, and `response.incomplete` events close the span.
|
|
79
|
+
|
|
80
|
+
## Embeddings
|
|
81
|
+
|
|
82
|
+
Embedding calls emit `gen_ai.operation.name = "embeddings"`, request model/input, response model, and token usage. Embedding vectors are intentionally not captured as output.
|
|
83
|
+
|
|
84
|
+
## Azure OpenAI
|
|
85
|
+
|
|
86
|
+
`wrap_openai(AzureOpenAI(...))` and `wrap_openai(AsyncAzureOpenAI(...))` record provider `azure.ai.openai`. Global class instrumentation detects Azure from the resource client when available.
|
|
87
|
+
|
|
88
|
+
## Limitations
|
|
89
|
+
|
|
90
|
+
- `with_raw_response` snapshots bound methods on first access in the OpenAI Python SDK. Call `wrap_openai()` or `instrument_openai()` before accessing `with_raw_response` if those methods need instrumentation.
|
|
91
|
+
- `responses.stream(response_id=...)` resumes an existing response through `retrieve()`, which is not instrumented in this version.
|
|
92
|
+
- 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-openai"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "OpenAI 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", "openai", "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
|
+
"openai>=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"
|