opentelemetry-instrumentation-openai 0.21.5__py3-none-any.whl → 0.22.0__py3-none-any.whl

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.

Potentially problematic release.


This version of opentelemetry-instrumentation-openai might be problematic. Click here for more details.

@@ -15,10 +15,6 @@ from opentelemetry.instrumentation.openai.utils import (
15
15
  should_record_stream_token_usage,
16
16
  )
17
17
 
18
- OPENAI_API_VERSION = "openai.api_version"
19
- OPENAI_API_BASE = "openai.api_base"
20
- OPENAI_API_TYPE = "openai.api_type"
21
-
22
18
  OPENAI_LLM_USAGE_TOKEN_TYPES = ["prompt_tokens", "completion_tokens"]
23
19
 
24
20
  # tiktoken encodings map for different model, key is model_name, value is tiktoken encoding
@@ -49,10 +45,12 @@ def _set_client_attributes(span, instance):
49
45
 
50
46
  client = instance._client # pylint: disable=protected-access
51
47
  if isinstance(client, (openai.AsyncOpenAI, openai.OpenAI)):
52
- _set_span_attribute(span, OPENAI_API_BASE, str(client.base_url))
48
+ _set_span_attribute(
49
+ span, SpanAttributes.LLM_OPENAI_API_BASE, str(client.base_url)
50
+ )
53
51
  if isinstance(client, (openai.AsyncAzureOpenAI, openai.AzureOpenAI)):
54
52
  _set_span_attribute(
55
- span, OPENAI_API_VERSION, client._api_version
53
+ span, SpanAttributes.LLM_OPENAI_API_VERSION, client._api_version
56
54
  ) # pylint: disable=protected-access
57
55
 
58
56
 
@@ -65,9 +63,9 @@ def _set_api_attributes(span):
65
63
 
66
64
  base_url = openai.base_url if hasattr(openai, "base_url") else openai.api_base
67
65
 
68
- _set_span_attribute(span, OPENAI_API_BASE, base_url)
69
- _set_span_attribute(span, OPENAI_API_TYPE, openai.api_type)
70
- _set_span_attribute(span, OPENAI_API_VERSION, openai.api_version)
66
+ _set_span_attribute(span, SpanAttributes.LLM_OPENAI_API_BASE, base_url)
67
+ _set_span_attribute(span, SpanAttributes.LLM_OPENAI_API_TYPE, openai.api_type)
68
+ _set_span_attribute(span, SpanAttributes.LLM_OPENAI_API_VERSION, openai.api_version)
71
69
 
72
70
  return
73
71
 
@@ -142,7 +140,9 @@ def _set_response_attributes(span, response):
142
140
  _set_span_attribute(span, SpanAttributes.LLM_RESPONSE_MODEL, response.get("model"))
143
141
 
144
142
  _set_span_attribute(
145
- span, "gen_ai.openai.system_fingerprint", response.get("system_fingerprint")
143
+ span,
144
+ SpanAttributes.LLM_OPENAI_RESPONSE_SYSTEM_FINGERPRINT,
145
+ response.get("system_fingerprint"),
146
146
  )
147
147
 
148
148
  usage = response.get("usage")
@@ -260,8 +260,8 @@ def _metric_shared_attributes(
260
260
  response_model: str, operation: str, server_address: str, is_streaming: bool = False
261
261
  ):
262
262
  return {
263
- "gen_ai.system": "openai",
264
- "gen_ai.response.model": response_model,
263
+ SpanAttributes.LLM_SYSTEM: "openai",
264
+ SpanAttributes.LLM_RESPONSE_MODEL: response_model,
265
265
  "gen_ai.operation.name": operation,
266
266
  "server.address": server_address,
267
267
  "stream": is_streaming,
@@ -296,8 +296,8 @@ def _set_choice_counter_metrics(choice_counter, choices, shared_attributes):
296
296
  for choice in choices:
297
297
  attributes_with_reason = {**shared_attributes}
298
298
  if choice.get("finish_reason"):
299
- attributes_with_reason["llm.response.finish_reason"] = choice.get(
300
- "finish_reason"
299
+ attributes_with_reason[SpanAttributes.LLM_RESPONSE_FINISH_REASON] = (
300
+ choice.get("finish_reason")
301
301
  )
302
302
  choice_counter.add(1, attributes=attributes_with_reason)
303
303
 
@@ -307,7 +307,7 @@ def _set_token_counter_metrics(token_counter, usage, shared_attributes):
307
307
  if name in OPENAI_LLM_USAGE_TOKEN_TYPES:
308
308
  attributes_with_token_type = {
309
309
  **shared_attributes,
310
- "gen_ai.token.type": _token_type(name),
310
+ SpanAttributes.LLM_TOKEN_TYPE: _token_type(name),
311
311
  }
312
312
  token_counter.record(val, attributes=attributes_with_token_type)
313
313
 
@@ -424,14 +424,14 @@ def _set_streaming_token_metrics(
424
424
  if type(prompt_usage) is int and prompt_usage >= 0:
425
425
  attributes_with_token_type = {
426
426
  **shared_attributes,
427
- "gen_ai.token.type": "input",
427
+ SpanAttributes.LLM_TOKEN_TYPE: "input",
428
428
  }
429
429
  token_counter.record(prompt_usage, attributes=attributes_with_token_type)
430
430
 
431
431
  if type(completion_usage) is int and completion_usage >= 0:
432
432
  attributes_with_token_type = {
433
433
  **shared_attributes,
434
- "gen_ai.token.type": "output",
434
+ SpanAttributes.LLM_TOKEN_TYPE: "output",
435
435
  }
436
436
  token_counter.record(
437
437
  completion_usage, attributes=attributes_with_token_type
@@ -520,7 +520,7 @@ class ChatStream(ObjectProxy):
520
520
  return chunk
521
521
 
522
522
  def _process_item(self, item):
523
- self._span.add_event(name="llm.content.completion.chunk")
523
+ self._span.add_event(name=f"{SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK}")
524
524
 
525
525
  if self._first_token and self._streaming_time_to_first_token:
526
526
  self._time_of_first_token = time.time()
@@ -551,6 +551,23 @@ class ChatStream(ObjectProxy):
551
551
  complete_choice["message"]["content"] += delta.get("content")
552
552
  if delta and delta.get("role"):
553
553
  complete_choice["message"]["role"] = delta.get("role")
554
+ if delta and delta.get("tool_calls"):
555
+ tool_calls = delta.get("tool_calls")
556
+ if not isinstance(tool_calls, list) or len(tool_calls) == 0:
557
+ continue
558
+
559
+ if not complete_choice["message"].get("tool_calls"):
560
+ complete_choice["message"]["tool_calls"] = [
561
+ {"function": {"name": "", "arguments": ""}}
562
+ ]
563
+
564
+ tool_call = tool_calls[0]
565
+ function = complete_choice["message"]["tool_calls"][0]["function"]
566
+
567
+ if tool_call.get("function") and tool_call["function"].get("name"):
568
+ function["name"] += tool_call["function"]["name"]
569
+ if tool_call.get("function") and tool_call["function"].get("arguments"):
570
+ function["arguments"] += tool_call["function"]["arguments"]
554
571
 
555
572
  def _shared_attributes(self):
556
573
  return _metric_shared_attributes(
@@ -564,14 +581,13 @@ class ChatStream(ObjectProxy):
564
581
 
565
582
  @dont_throw
566
583
  def _close_span(self):
567
- if not is_azure_openai(self._instance):
568
- _set_streaming_token_metrics(
569
- self._request_kwargs,
570
- self._complete_response,
571
- self._span,
572
- self._token_counter,
573
- self._shared_attributes(),
574
- )
584
+ _set_streaming_token_metrics(
585
+ self._request_kwargs,
586
+ self._complete_response,
587
+ self._span,
588
+ self._token_counter,
589
+ self._shared_attributes(),
590
+ )
575
591
 
576
592
  # choice metrics
577
593
  if self._choice_counter and self._complete_response.get("choices"):
@@ -627,7 +643,7 @@ def _build_from_streaming_response(
627
643
  time_of_first_token = start_time # will be updated when first token is received
628
644
 
629
645
  for item in response:
630
- span.add_event(name="llm.content.completion.chunk")
646
+ span.add_event(name=f"{SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK}")
631
647
 
632
648
  item_to_yield = item
633
649
 
@@ -641,15 +657,14 @@ def _build_from_streaming_response(
641
657
  yield item_to_yield
642
658
 
643
659
  shared_attributes = {
644
- "gen_ai.response.model": complete_response.get("model") or None,
660
+ SpanAttributes.LLM_RESPONSE_MODEL: complete_response.get("model") or None,
645
661
  "server.address": _get_openai_base_url(instance),
646
662
  "stream": True,
647
663
  }
648
664
 
649
- if not is_azure_openai(instance):
650
- _set_streaming_token_metrics(
651
- request_kwargs, complete_response, span, token_counter, shared_attributes
652
- )
665
+ _set_streaming_token_metrics(
666
+ request_kwargs, complete_response, span, token_counter, shared_attributes
667
+ )
653
668
 
654
669
  # choice metrics
655
670
  if choice_counter and complete_response.get("choices"):
@@ -695,7 +710,7 @@ async def _abuild_from_streaming_response(
695
710
  time_of_first_token = start_time # will be updated when first token is received
696
711
 
697
712
  async for item in response:
698
- span.add_event(name="llm.content.completion.chunk")
713
+ span.add_event(name=f"{SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK}")
699
714
 
700
715
  item_to_yield = item
701
716
 
@@ -709,7 +724,7 @@ async def _abuild_from_streaming_response(
709
724
  yield item_to_yield
710
725
 
711
726
  shared_attributes = {
712
- "gen_ai.response.model": complete_response.get("model") or None,
727
+ SpanAttributes.LLM_RESPONSE_MODEL: complete_response.get("model") or None,
713
728
  "server.address": _get_openai_base_url(instance),
714
729
  "stream": True,
715
730
  }
@@ -203,7 +203,7 @@ def _set_embeddings_metrics(
203
203
  if name in OPENAI_LLM_USAGE_TOKEN_TYPES:
204
204
  attributes_with_token_type = {
205
205
  **shared_attributes,
206
- "gen_ai.token.type": _token_type(name),
206
+ SpanAttributes.LLM_TOKEN_TYPE: _token_type(name),
207
207
  }
208
208
  token_counter.record(val, attributes=attributes_with_token_type)
209
209
 
@@ -1,10 +1,6 @@
1
1
  import time
2
2
 
3
3
  from opentelemetry import context as context_api
4
- from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
5
-
6
- from opentelemetry.metrics import Counter, Histogram
7
-
8
4
  from opentelemetry.instrumentation.openai import is_openai_v1
9
5
  from opentelemetry.instrumentation.openai.shared import (
10
6
  _get_openai_base_url,
@@ -14,6 +10,8 @@ from opentelemetry.instrumentation.openai.shared import (
14
10
  from opentelemetry.instrumentation.openai.utils import (
15
11
  _with_image_gen_metric_wrapper,
16
12
  )
13
+ from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
14
+ from opentelemetry.metrics import Counter, Histogram
17
15
 
18
16
 
19
17
  @_with_image_gen_metric_wrapper
@@ -2,6 +2,7 @@ from importlib.metadata import version
2
2
  from contextlib import asynccontextmanager
3
3
  import logging
4
4
  import os
5
+ import traceback
5
6
 
6
7
  import openai
7
8
  from opentelemetry.instrumentation.openai.shared.config import Config
@@ -124,7 +125,9 @@ def dont_throw(func):
124
125
  return func(*args, **kwargs)
125
126
  except Exception as e:
126
127
  logger.debug(
127
- "OpenLLMetry failed to trace in %s, error: %s", func.__name__, str(e)
128
+ "OpenLLMetry failed to trace in %s, error: %s",
129
+ func.__name__,
130
+ traceback.format_exc(),
128
131
  )
129
132
  if Config.exception_logger:
130
133
  Config.exception_logger(e)
@@ -19,6 +19,7 @@ from opentelemetry.instrumentation.openai.shared.embeddings_wrappers import (
19
19
  )
20
20
  from opentelemetry.instrumentation.openai.utils import is_metrics_enabled
21
21
  from opentelemetry.instrumentation.openai.version import __version__
22
+ from opentelemetry.semconv.ai import Meters
22
23
 
23
24
  _instruments = ("openai >= 0.27.0", "openai < 1.0.0")
24
25
 
@@ -36,36 +37,36 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
36
37
 
37
38
  if is_metrics_enabled():
38
39
  tokens_histogram = meter.create_histogram(
39
- name="gen_ai.client.token.usage",
40
+ name=Meters.LLM_TOKEN_USAGE,
40
41
  unit="token",
41
42
  description="Measures number of input and output tokens used",
42
43
  )
43
44
 
44
45
  chat_choice_counter = meter.create_counter(
45
- name="gen_ai.client.generation.choices",
46
+ name=Meters.LLM_GENERATION_CHOICES,
46
47
  unit="choice",
47
48
  description="Number of choices returned by chat completions call",
48
49
  )
49
50
 
50
- chat_duration_histogram = meter.create_histogram(
51
- name="gen_ai.client.operation.duration",
51
+ duration_histogram = meter.create_histogram(
52
+ name=Meters.LLM_OPERATION_DURATION,
52
53
  unit="s",
53
54
  description="GenAI operation duration",
54
55
  )
55
56
 
56
57
  chat_exception_counter = meter.create_counter(
57
- name="llm.openai.chat_completions.exceptions",
58
+ name=Meters.LLM_COMPLETIONS_EXCEPTIONS,
58
59
  unit="time",
59
60
  description="Number of exceptions occurred during chat completions",
60
61
  )
61
62
 
62
63
  streaming_time_to_first_token = meter.create_histogram(
63
- name="llm.openai.chat_completions.streaming_time_to_first_token",
64
+ name=Meters.LLM_STREAMING_TIME_TO_FIRST_TOKEN,
64
65
  unit="s",
65
66
  description="Time to first token in streaming chat completions",
66
67
  )
67
68
  streaming_time_to_generate = meter.create_histogram(
68
- name="llm.openai.chat_completions.streaming_time_to_generate",
69
+ name=Meters.LLM_STREAMING_TIME_TO_GENERATE,
69
70
  unit="s",
70
71
  description="Time between first token and completion in streaming chat completions",
71
72
  )
@@ -73,7 +74,7 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
73
74
  (
74
75
  tokens_histogram,
75
76
  chat_choice_counter,
76
- chat_duration_histogram,
77
+ duration_histogram,
77
78
  chat_exception_counter,
78
79
  streaming_time_to_first_token,
79
80
  streaming_time_to_generate,
@@ -81,19 +82,12 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
81
82
 
82
83
  if is_metrics_enabled():
83
84
  embeddings_vector_size_counter = meter.create_counter(
84
- name="llm.openai.embeddings.vector_size",
85
+ name=Meters.LLM_EMBEDDINGS_VECTOR_SIZE,
85
86
  unit="element",
86
87
  description="he size of returned vector",
87
88
  )
88
-
89
- embeddings_duration_histogram = meter.create_histogram(
90
- name="llm.openai.embeddings.duration",
91
- unit="s",
92
- description="Duration of embeddings operation",
93
- )
94
-
95
89
  embeddings_exception_counter = meter.create_counter(
96
- name="llm.openai.embeddings.exceptions",
90
+ name=Meters.LLM_EMBEDDINGS_EXCEPTIONS,
97
91
  unit="time",
98
92
  description="Number of exceptions occurred during embeddings operation",
99
93
  )
@@ -101,9 +95,8 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
101
95
  (
102
96
  tokens_histogram,
103
97
  embeddings_vector_size_counter,
104
- embeddings_duration_histogram,
105
98
  embeddings_exception_counter,
106
- ) = (None, None, None, None)
99
+ ) = (None, None, None)
107
100
 
108
101
  wrap_function_wrapper("openai", "Completion.create", completion_wrapper(tracer))
109
102
  wrap_function_wrapper(
@@ -116,7 +109,7 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
116
109
  tracer,
117
110
  tokens_histogram,
118
111
  chat_choice_counter,
119
- chat_duration_histogram,
112
+ duration_histogram,
120
113
  chat_exception_counter,
121
114
  streaming_time_to_first_token,
122
115
  streaming_time_to_generate,
@@ -129,7 +122,7 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
129
122
  tracer,
130
123
  tokens_histogram,
131
124
  chat_choice_counter,
132
- chat_duration_histogram,
125
+ duration_histogram,
133
126
  chat_exception_counter,
134
127
  streaming_time_to_first_token,
135
128
  streaming_time_to_generate,
@@ -142,7 +135,7 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
142
135
  tracer,
143
136
  tokens_histogram,
144
137
  embeddings_vector_size_counter,
145
- embeddings_duration_histogram,
138
+ duration_histogram,
146
139
  embeddings_exception_counter,
147
140
  ),
148
141
  )
@@ -153,7 +146,7 @@ class OpenAIV0Instrumentor(BaseInstrumentor):
153
146
  tracer,
154
147
  tokens_histogram,
155
148
  embeddings_vector_size_counter,
156
- embeddings_duration_histogram,
149
+ duration_histogram,
157
150
  embeddings_exception_counter,
158
151
  ),
159
152
  )
@@ -33,6 +33,8 @@ from opentelemetry.instrumentation.openai.v1.assistant_wrappers import (
33
33
  from opentelemetry.instrumentation.openai.utils import is_metrics_enabled
34
34
  from opentelemetry.instrumentation.openai.version import __version__
35
35
 
36
+ from opentelemetry.semconv.ai import Meters
37
+
36
38
  _instruments = ("openai >= 1.0.0",)
37
39
 
38
40
 
@@ -50,36 +52,36 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
50
52
 
51
53
  if is_metrics_enabled():
52
54
  tokens_histogram = meter.create_histogram(
53
- name="gen_ai.client.token.usage",
55
+ name=Meters.LLM_TOKEN_USAGE,
54
56
  unit="token",
55
57
  description="Measures number of input and output tokens used",
56
58
  )
57
59
 
58
60
  chat_choice_counter = meter.create_counter(
59
- name="gen_ai.client.generation.choices",
61
+ name=Meters.LLM_GENERATION_CHOICES,
60
62
  unit="choice",
61
63
  description="Number of choices returned by chat completions call",
62
64
  )
63
65
 
64
- chat_duration_histogram = meter.create_histogram(
65
- name="gen_ai.client.operation.duration",
66
+ duration_histogram = meter.create_histogram(
67
+ name=Meters.LLM_OPERATION_DURATION,
66
68
  unit="s",
67
69
  description="GenAI operation duration",
68
70
  )
69
71
 
70
72
  chat_exception_counter = meter.create_counter(
71
- name="llm.openai.chat_completions.exceptions",
73
+ name=Meters.LLM_COMPLETIONS_EXCEPTIONS,
72
74
  unit="time",
73
75
  description="Number of exceptions occurred during chat completions",
74
76
  )
75
77
 
76
78
  streaming_time_to_first_token = meter.create_histogram(
77
- name="llm.openai.chat_completions.streaming_time_to_first_token",
79
+ name=Meters.LLM_STREAMING_TIME_TO_FIRST_TOKEN,
78
80
  unit="s",
79
81
  description="Time to first token in streaming chat completions",
80
82
  )
81
83
  streaming_time_to_generate = meter.create_histogram(
82
- name="llm.openai.chat_completions.streaming_time_to_generate",
84
+ name=Meters.LLM_STREAMING_TIME_TO_GENERATE,
83
85
  unit="s",
84
86
  description="Time between first token and completion in streaming chat completions",
85
87
  )
@@ -87,7 +89,7 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
87
89
  (
88
90
  tokens_histogram,
89
91
  chat_choice_counter,
90
- chat_duration_histogram,
92
+ duration_histogram,
91
93
  chat_exception_counter,
92
94
  streaming_time_to_first_token,
93
95
  streaming_time_to_generate,
@@ -100,7 +102,7 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
100
102
  tracer,
101
103
  tokens_histogram,
102
104
  chat_choice_counter,
103
- chat_duration_histogram,
105
+ duration_histogram,
104
106
  chat_exception_counter,
105
107
  streaming_time_to_first_token,
106
108
  streaming_time_to_generate,
@@ -115,19 +117,12 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
115
117
 
116
118
  if is_metrics_enabled():
117
119
  embeddings_vector_size_counter = meter.create_counter(
118
- name="llm.openai.embeddings.vector_size",
120
+ name=Meters.LLM_EMBEDDINGS_VECTOR_SIZE,
119
121
  unit="element",
120
122
  description="he size of returned vector",
121
123
  )
122
-
123
- embeddings_duration_histogram = meter.create_histogram(
124
- name="llm.openai.embeddings.duration",
125
- unit="s",
126
- description="Duration of embeddings operation",
127
- )
128
-
129
124
  embeddings_exception_counter = meter.create_counter(
130
- name="llm.openai.embeddings.exceptions",
125
+ name=Meters.LLM_EMBEDDINGS_EXCEPTIONS,
131
126
  unit="time",
132
127
  description="Number of exceptions occurred during embeddings operation",
133
128
  )
@@ -135,9 +130,8 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
135
130
  (
136
131
  tokens_histogram,
137
132
  embeddings_vector_size_counter,
138
- embeddings_duration_histogram,
139
133
  embeddings_exception_counter,
140
- ) = (None, None, None, None)
134
+ ) = (None, None, None)
141
135
 
142
136
  wrap_function_wrapper(
143
137
  "openai.resources.embeddings",
@@ -146,7 +140,7 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
146
140
  tracer,
147
141
  tokens_histogram,
148
142
  embeddings_vector_size_counter,
149
- embeddings_duration_histogram,
143
+ duration_histogram,
150
144
  embeddings_exception_counter,
151
145
  ),
152
146
  )
@@ -158,7 +152,7 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
158
152
  tracer,
159
153
  tokens_histogram,
160
154
  chat_choice_counter,
161
- chat_duration_histogram,
155
+ duration_histogram,
162
156
  chat_exception_counter,
163
157
  streaming_time_to_first_token,
164
158
  streaming_time_to_generate,
@@ -176,32 +170,24 @@ class OpenAIV1Instrumentor(BaseInstrumentor):
176
170
  tracer,
177
171
  tokens_histogram,
178
172
  embeddings_vector_size_counter,
179
- embeddings_duration_histogram,
173
+ duration_histogram,
180
174
  embeddings_exception_counter,
181
175
  ),
182
176
  )
183
177
 
184
178
  if is_metrics_enabled():
185
- image_gen_duration_histogram = meter.create_histogram(
186
- name="llm.openai.image_generations.duration",
187
- unit="s",
188
- description="Duration of image generations operation",
189
- )
190
-
191
179
  image_gen_exception_counter = meter.create_counter(
192
- name="llm.openai.image_generations.exceptions",
180
+ name=Meters.LLM_IMAGE_GENERATIONS_EXCEPTIONS,
193
181
  unit="time",
194
182
  description="Number of exceptions occurred during image generations operation",
195
183
  )
196
184
  else:
197
- image_gen_duration_histogram, image_gen_exception_counter = None, None
185
+ image_gen_exception_counter = None
198
186
 
199
187
  wrap_function_wrapper(
200
188
  "openai.resources.images",
201
189
  "Images.generate",
202
- image_gen_metrics_wrapper(
203
- image_gen_duration_histogram, image_gen_exception_counter
204
- ),
190
+ image_gen_metrics_wrapper(duration_histogram, image_gen_exception_counter),
205
191
  )
206
192
 
207
193
  # Beta APIs may not be available consistently in all versions
@@ -10,9 +10,12 @@ from opentelemetry.instrumentation.utils import _SUPPRESS_INSTRUMENTATION_KEY
10
10
 
11
11
  from opentelemetry.semconv.ai import SpanAttributes, LLMRequestTypeValues
12
12
 
13
- from opentelemetry.instrumentation.openai.utils import _with_tracer_wrapper
13
+ from opentelemetry.instrumentation.openai.utils import _with_tracer_wrapper, dont_throw
14
14
  from opentelemetry.instrumentation.openai.shared.config import Config
15
15
 
16
+ from openai._legacy_response import LegacyAPIResponse
17
+ from openai.types.beta.threads.run import Run
18
+
16
19
  logger = logging.getLogger(__name__)
17
20
 
18
21
  assistants = {}
@@ -55,15 +58,23 @@ def runs_create_wrapper(tracer, wrapped, instance, args, kwargs):
55
58
 
56
59
  @_with_tracer_wrapper
57
60
  def runs_retrieve_wrapper(tracer, wrapped, instance, args, kwargs):
61
+ @dont_throw
62
+ def process_response(response):
63
+ if type(response) is LegacyAPIResponse:
64
+ parsed_response = response.parse()
65
+ else:
66
+ parsed_response = response
67
+ assert type(parsed_response) is Run
68
+
69
+ if parsed_response.id in runs:
70
+ runs[thread_id]["end_time"] = time.time_ns()
71
+
58
72
  if context_api.get_value(_SUPPRESS_INSTRUMENTATION_KEY):
59
73
  return wrapped(*args, **kwargs)
60
74
 
61
75
  thread_id = kwargs.get("thread_id")
62
-
63
76
  response = wrapped(*args, **kwargs)
64
-
65
- if response.id in runs:
66
- runs[thread_id]["end_time"] = time.time_ns()
77
+ process_response(response)
67
78
 
68
79
  return response
69
80
 
@@ -1 +1 @@
1
- __version__ = "0.21.5"
1
+ __version__ = "0.22.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: opentelemetry-instrumentation-openai
3
- Version: 0.21.5
3
+ Version: 0.22.0
4
4
  Summary: OpenTelemetry OpenAI instrumentation
5
5
  Home-page: https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-openai
6
6
  License: Apache-2.0
@@ -17,7 +17,7 @@ Provides-Extra: instruments
17
17
  Requires-Dist: opentelemetry-api (>=1.25.0,<2.0.0)
18
18
  Requires-Dist: opentelemetry-instrumentation (>=0.46b0,<0.47)
19
19
  Requires-Dist: opentelemetry-semantic-conventions (>=0.46b0,<0.47)
20
- Requires-Dist: opentelemetry-semantic-conventions-ai (==0.2.0)
20
+ Requires-Dist: opentelemetry-semantic-conventions-ai (==0.3.1)
21
21
  Requires-Dist: tiktoken (>=0.6.0,<1)
22
22
  Project-URL: Repository, https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-openai
23
23
  Description-Content-Type: text/markdown
@@ -0,0 +1,17 @@
1
+ opentelemetry/instrumentation/openai/__init__.py,sha256=xl3Kvqry9glVhu8VtdknfUE9FpXQ7KWAFqtVlpjE-40,1344
2
+ opentelemetry/instrumentation/openai/shared/__init__.py,sha256=vRPcdI_4Tseg7mBYRrDdWzRcnec3vZeC2tPYpLlT2Xc,8076
3
+ opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=4utwf6nvum3-Uo5V6pEQGx0JWpRbDgeMYqD9gm5GhcU,25009
4
+ opentelemetry/instrumentation/openai/shared/completion_wrappers.py,sha256=-JHfgyxic5I3Wr3Uc_L-U7ztDVFcyovtF37tNLtaW3s,6604
5
+ opentelemetry/instrumentation/openai/shared/config.py,sha256=5uekQEnmYo1o6tsTD2IGc-cVmHUo5KmUC4pOVdrFFNk,102
6
+ opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py,sha256=gzKmjwI7xhGUUDiIxwuyvSH-YDCTIaa0dXECpPc_vaY,6696
7
+ opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py,sha256=uREeAWW0xsCsyCDLVMj3LVbHtP5vlm74uVIpZT3YKzc,1959
8
+ opentelemetry/instrumentation/openai/utils.py,sha256=3ONjsia3xG4rRMOwjU91liOVpZxoRE39CxJ-C5HxIgQ,3464
9
+ opentelemetry/instrumentation/openai/v0/__init__.py,sha256=FYq3xhtaIdvy7mwCPzxaqNNGzfHEi0Q2JFQl51s6yNo,5475
10
+ opentelemetry/instrumentation/openai/v1/__init__.py,sha256=wDO1rjgeZRNVXXA3IJUdqYVXRsvst7_JTtAjBK-m1Gc,7693
11
+ opentelemetry/instrumentation/openai/v1/assistant_wrappers.py,sha256=4BDLcqOfwl0LFUdAjLE_PgRcWsQYKoCM_okWLCU8A9U,6277
12
+ opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py,sha256=SAzYoun2yyOloofyOWtxpm8E2M9TL3Nm8TgKdNyXHuY,2779
13
+ opentelemetry/instrumentation/openai/version.py,sha256=0kk8efeJF41FZIYweGTJylbizaWrp9W3qN78RClCWIU,23
14
+ opentelemetry_instrumentation_openai-0.22.0.dist-info/METADATA,sha256=gELGIuun2eJMmT2PjO3V49_gc2_JJRkqSDAVl08tHQQ,2255
15
+ opentelemetry_instrumentation_openai-0.22.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
16
+ opentelemetry_instrumentation_openai-0.22.0.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
17
+ opentelemetry_instrumentation_openai-0.22.0.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- opentelemetry/instrumentation/openai/__init__.py,sha256=xl3Kvqry9glVhu8VtdknfUE9FpXQ7KWAFqtVlpjE-40,1344
2
- opentelemetry/instrumentation/openai/shared/__init__.py,sha256=rn8AqGI0s0RAPlJGFgOtKE4ONPUF9N8rBPkmPErqB9o,8018
3
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py,sha256=UtS3c3Ox8-bosx2T8kLBHPKj7TUOH-xzFYkHZw1xQLo,24132
4
- opentelemetry/instrumentation/openai/shared/completion_wrappers.py,sha256=-JHfgyxic5I3Wr3Uc_L-U7ztDVFcyovtF37tNLtaW3s,6604
5
- opentelemetry/instrumentation/openai/shared/config.py,sha256=5uekQEnmYo1o6tsTD2IGc-cVmHUo5KmUC4pOVdrFFNk,102
6
- opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py,sha256=7aVXEaDw0Lzb_iAmVaUSqNTXLnXxAmWURM1iGHdXI18,6686
7
- opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py,sha256=uN9eK-EFWZNn7OKgAEMSxju_5b_MGRePynn3ov3Exgw,1961
8
- opentelemetry/instrumentation/openai/utils.py,sha256=c7y4iO4C-81PQQFXCuZ7smFz9bsuw9AH1_RHFUr7SZA,3398
9
- opentelemetry/instrumentation/openai/v0/__init__.py,sha256=ZpnAQW0vJYVeNC--RYR21hI3nQFEo8mRjHPELfTBdlk,5819
10
- opentelemetry/instrumentation/openai/v1/__init__.py,sha256=sAA10BU4nsviHpqp0SLJdsKKLOyPS-xi0bk5N5uM2fE,8355
11
- opentelemetry/instrumentation/openai/v1/assistant_wrappers.py,sha256=T6Vtdp1fAZdcYjGiTMZwkn4F4DgsltD4p4xLEFW-GhI,5874
12
- opentelemetry/instrumentation/openai/v1/event_handler_wrapper.py,sha256=SAzYoun2yyOloofyOWtxpm8E2M9TL3Nm8TgKdNyXHuY,2779
13
- opentelemetry/instrumentation/openai/version.py,sha256=yq-fGfdU069XbMVu8cXj7x9Ga-YNsSY_1SmDswa-WEI,23
14
- opentelemetry_instrumentation_openai-0.21.5.dist-info/METADATA,sha256=DUug8rOWmmoy07j_PUp6CWGqGQ4S_dNFyeQe50DcktY,2255
15
- opentelemetry_instrumentation_openai-0.21.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
16
- opentelemetry_instrumentation_openai-0.21.5.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
17
- opentelemetry_instrumentation_openai-0.21.5.dist-info/RECORD,,