opentelemetry-instrumentation-openai 0.21.4__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.
- opentelemetry/instrumentation/openai/shared/__init__.py +12 -12
- opentelemetry/instrumentation/openai/shared/chat_wrappers.py +41 -26
- opentelemetry/instrumentation/openai/shared/embeddings_wrappers.py +1 -1
- opentelemetry/instrumentation/openai/shared/image_gen_wrappers.py +2 -4
- opentelemetry/instrumentation/openai/utils.py +4 -1
- opentelemetry/instrumentation/openai/v0/__init__.py +16 -23
- opentelemetry/instrumentation/openai/v1/__init__.py +20 -34
- opentelemetry/instrumentation/openai/v1/assistant_wrappers.py +16 -5
- opentelemetry/instrumentation/openai/version.py +1 -1
- {opentelemetry_instrumentation_openai-0.21.4.dist-info → opentelemetry_instrumentation_openai-0.22.0.dist-info}/METADATA +2 -2
- opentelemetry_instrumentation_openai-0.22.0.dist-info/RECORD +17 -0
- opentelemetry_instrumentation_openai-0.21.4.dist-info/RECORD +0 -17
- {opentelemetry_instrumentation_openai-0.21.4.dist-info → opentelemetry_instrumentation_openai-0.22.0.dist-info}/WHEEL +0 -0
- {opentelemetry_instrumentation_openai-0.21.4.dist-info → opentelemetry_instrumentation_openai-0.22.0.dist-info}/entry_points.txt +0 -0
|
@@ -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(
|
|
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,
|
|
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,
|
|
69
|
-
_set_span_attribute(span,
|
|
70
|
-
_set_span_attribute(span,
|
|
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,
|
|
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
|
-
|
|
264
|
-
|
|
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,
|
|
@@ -294,10 +294,11 @@ def _set_chat_metrics(
|
|
|
294
294
|
def _set_choice_counter_metrics(choice_counter, choices, shared_attributes):
|
|
295
295
|
choice_counter.add(len(choices), attributes=shared_attributes)
|
|
296
296
|
for choice in choices:
|
|
297
|
-
attributes_with_reason = {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
297
|
+
attributes_with_reason = {**shared_attributes}
|
|
298
|
+
if choice.get("finish_reason"):
|
|
299
|
+
attributes_with_reason[SpanAttributes.LLM_RESPONSE_FINISH_REASON] = (
|
|
300
|
+
choice.get("finish_reason")
|
|
301
|
+
)
|
|
301
302
|
choice_counter.add(1, attributes=attributes_with_reason)
|
|
302
303
|
|
|
303
304
|
|
|
@@ -306,7 +307,7 @@ def _set_token_counter_metrics(token_counter, usage, shared_attributes):
|
|
|
306
307
|
if name in OPENAI_LLM_USAGE_TOKEN_TYPES:
|
|
307
308
|
attributes_with_token_type = {
|
|
308
309
|
**shared_attributes,
|
|
309
|
-
|
|
310
|
+
SpanAttributes.LLM_TOKEN_TYPE: _token_type(name),
|
|
310
311
|
}
|
|
311
312
|
token_counter.record(val, attributes=attributes_with_token_type)
|
|
312
313
|
|
|
@@ -423,14 +424,14 @@ def _set_streaming_token_metrics(
|
|
|
423
424
|
if type(prompt_usage) is int and prompt_usage >= 0:
|
|
424
425
|
attributes_with_token_type = {
|
|
425
426
|
**shared_attributes,
|
|
426
|
-
|
|
427
|
+
SpanAttributes.LLM_TOKEN_TYPE: "input",
|
|
427
428
|
}
|
|
428
429
|
token_counter.record(prompt_usage, attributes=attributes_with_token_type)
|
|
429
430
|
|
|
430
431
|
if type(completion_usage) is int and completion_usage >= 0:
|
|
431
432
|
attributes_with_token_type = {
|
|
432
433
|
**shared_attributes,
|
|
433
|
-
|
|
434
|
+
SpanAttributes.LLM_TOKEN_TYPE: "output",
|
|
434
435
|
}
|
|
435
436
|
token_counter.record(
|
|
436
437
|
completion_usage, attributes=attributes_with_token_type
|
|
@@ -463,8 +464,6 @@ class ChatStream(ObjectProxy):
|
|
|
463
464
|
):
|
|
464
465
|
super().__init__(response)
|
|
465
466
|
|
|
466
|
-
print("HEYY", response.__class__.__name__)
|
|
467
|
-
|
|
468
467
|
self._span = span
|
|
469
468
|
self._instance = instance
|
|
470
469
|
self._token_counter = token_counter
|
|
@@ -521,7 +520,7 @@ class ChatStream(ObjectProxy):
|
|
|
521
520
|
return chunk
|
|
522
521
|
|
|
523
522
|
def _process_item(self, item):
|
|
524
|
-
self._span.add_event(name="
|
|
523
|
+
self._span.add_event(name=f"{SpanAttributes.LLM_CONTENT_COMPLETION_CHUNK}")
|
|
525
524
|
|
|
526
525
|
if self._first_token and self._streaming_time_to_first_token:
|
|
527
526
|
self._time_of_first_token = time.time()
|
|
@@ -552,6 +551,23 @@ class ChatStream(ObjectProxy):
|
|
|
552
551
|
complete_choice["message"]["content"] += delta.get("content")
|
|
553
552
|
if delta and delta.get("role"):
|
|
554
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"]
|
|
555
571
|
|
|
556
572
|
def _shared_attributes(self):
|
|
557
573
|
return _metric_shared_attributes(
|
|
@@ -563,15 +579,15 @@ class ChatStream(ObjectProxy):
|
|
|
563
579
|
is_streaming=True,
|
|
564
580
|
)
|
|
565
581
|
|
|
582
|
+
@dont_throw
|
|
566
583
|
def _close_span(self):
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
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=
|
|
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=
|
|
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
|
-
|
|
51
|
-
name=
|
|
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=
|
|
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=
|
|
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=
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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
|
-
|
|
65
|
-
name=
|
|
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=
|
|
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=
|
|
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=
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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=
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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=
|
|
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
|
-
|
|
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.
|
|
1
|
+
__version__ = "0.22.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: opentelemetry-instrumentation-openai
|
|
3
|
-
Version: 0.
|
|
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.
|
|
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=0Wjb95q-7nzHKE8N6OCSQinvKZiKHdeIZO7J_NBTxsQ,24093
|
|
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=GyaC3hhx285KqPcqukJ07gRSFkuES5T27aUtAwvYYRw,23
|
|
14
|
-
opentelemetry_instrumentation_openai-0.21.4.dist-info/METADATA,sha256=gXXHbnllbvRwhKU-sykZ3e-5CK12ceUvuS60M-o06rI,2255
|
|
15
|
-
opentelemetry_instrumentation_openai-0.21.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
16
|
-
opentelemetry_instrumentation_openai-0.21.4.dist-info/entry_points.txt,sha256=vTBfiX5yXji5YHikuJHEOoBZ1TFdPQ1EI4ctd2pZSeE,93
|
|
17
|
-
opentelemetry_instrumentation_openai-0.21.4.dist-info/RECORD,,
|
|
File without changes
|