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"