openlit 1.34.19__py3-none-any.whl → 1.34.22__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.
- openlit/__helpers.py +40 -0
- openlit/instrumentation/bedrock/__init__.py +19 -14
- openlit/instrumentation/bedrock/bedrock.py +169 -35
- openlit/instrumentation/bedrock/utils.py +143 -172
- openlit/instrumentation/litellm/async_litellm.py +2 -2
- openlit/instrumentation/openai/__init__.py +63 -68
- openlit/instrumentation/openai/async_openai.py +203 -1277
- openlit/instrumentation/openai/openai.py +200 -1274
- openlit/instrumentation/openai/utils.py +794 -0
- openlit/instrumentation/vertexai/__init__.py +18 -23
- openlit/instrumentation/vertexai/async_vertexai.py +46 -364
- openlit/instrumentation/vertexai/utils.py +204 -0
- openlit/instrumentation/vertexai/vertexai.py +46 -364
- {openlit-1.34.19.dist-info → openlit-1.34.22.dist-info}/METADATA +1 -1
- {openlit-1.34.19.dist-info → openlit-1.34.22.dist-info}/RECORD +17 -15
- {openlit-1.34.19.dist-info → openlit-1.34.22.dist-info}/LICENSE +0 -0
- {openlit-1.34.19.dist-info → openlit-1.34.22.dist-info}/WHEEL +0 -0
openlit/__helpers.py
CHANGED
@@ -402,3 +402,43 @@ def record_embedding_metrics(metrics, gen_ai_operation, gen_ai_system, server_ad
|
|
402
402
|
metrics["genai_requests"].add(1, attributes)
|
403
403
|
metrics["genai_prompt_tokens"].add(input_tokens, attributes)
|
404
404
|
metrics["genai_cost"].record(cost, attributes)
|
405
|
+
|
406
|
+
def record_audio_metrics(metrics, gen_ai_operation, gen_ai_system, server_address, server_port,
|
407
|
+
request_model, response_model, environment, application_name, start_time, end_time, cost):
|
408
|
+
"""
|
409
|
+
Record audio-specific metrics for the operation.
|
410
|
+
"""
|
411
|
+
|
412
|
+
attributes = create_metrics_attributes(
|
413
|
+
operation=gen_ai_operation,
|
414
|
+
system=gen_ai_system,
|
415
|
+
server_address=server_address,
|
416
|
+
server_port=server_port,
|
417
|
+
request_model=request_model,
|
418
|
+
response_model=response_model,
|
419
|
+
service_name=application_name,
|
420
|
+
deployment_environment=environment,
|
421
|
+
)
|
422
|
+
metrics["genai_client_operation_duration"].record(end_time - start_time, attributes)
|
423
|
+
metrics["genai_requests"].add(1, attributes)
|
424
|
+
metrics["genai_cost"].record(cost, attributes)
|
425
|
+
|
426
|
+
def record_image_metrics(metrics, gen_ai_operation, gen_ai_system, server_address, server_port,
|
427
|
+
request_model, response_model, environment, application_name, start_time, end_time, cost):
|
428
|
+
"""
|
429
|
+
Record image-specific metrics for the operation.
|
430
|
+
"""
|
431
|
+
|
432
|
+
attributes = create_metrics_attributes(
|
433
|
+
operation=gen_ai_operation,
|
434
|
+
system=gen_ai_system,
|
435
|
+
server_address=server_address,
|
436
|
+
server_port=server_port,
|
437
|
+
request_model=request_model,
|
438
|
+
response_model=response_model,
|
439
|
+
service_name=application_name,
|
440
|
+
deployment_environment=environment,
|
441
|
+
)
|
442
|
+
metrics["genai_client_operation_duration"].record(end_time - start_time, attributes)
|
443
|
+
metrics["genai_requests"].add(1, attributes)
|
444
|
+
metrics["genai_cost"].record(cost, attributes)
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# pylint: disable=useless-return, bad-staticmethod-argument, disable=duplicate-code
|
2
1
|
"""Initializer of Auto Instrumentation of AWS Bedrock Functions"""
|
3
2
|
|
4
3
|
from typing import Collection
|
@@ -6,37 +5,43 @@ import importlib.metadata
|
|
6
5
|
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
|
7
6
|
from wrapt import wrap_function_wrapper
|
8
7
|
|
9
|
-
from openlit.instrumentation.bedrock.bedrock import converse
|
8
|
+
from openlit.instrumentation.bedrock.bedrock import converse, converse_stream
|
10
9
|
|
11
10
|
_instruments = ("boto3 >= 1.34.138",)
|
12
11
|
|
13
12
|
class BedrockInstrumentor(BaseInstrumentor):
|
14
13
|
"""
|
15
|
-
An instrumentor for AWS Bedrock
|
14
|
+
An instrumentor for AWS Bedrock client library.
|
16
15
|
"""
|
17
16
|
|
18
17
|
def instrumentation_dependencies(self) -> Collection[str]:
|
19
18
|
return _instruments
|
20
19
|
|
21
20
|
def _instrument(self, **kwargs):
|
22
|
-
|
23
|
-
environment = kwargs.get("environment", "
|
21
|
+
version = importlib.metadata.version("boto3")
|
22
|
+
environment = kwargs.get("environment", "default")
|
23
|
+
application_name = kwargs.get("application_name", "default")
|
24
24
|
tracer = kwargs.get("tracer")
|
25
|
-
event_provider = kwargs.get('event_provider')
|
26
|
-
metrics = kwargs.get("metrics_dict")
|
27
25
|
pricing_info = kwargs.get("pricing_info", {})
|
28
26
|
capture_message_content = kwargs.get("capture_message_content", False)
|
27
|
+
metrics = kwargs.get("metrics_dict")
|
29
28
|
disable_metrics = kwargs.get("disable_metrics")
|
30
|
-
version = importlib.metadata.version("boto3")
|
31
29
|
|
32
|
-
#sync
|
30
|
+
# sync
|
31
|
+
wrap_function_wrapper(
|
32
|
+
"botocore.client",
|
33
|
+
"ClientCreator.create_client",
|
34
|
+
converse(version, environment, application_name, tracer, pricing_info,
|
35
|
+
capture_message_content, metrics, disable_metrics),
|
36
|
+
)
|
37
|
+
|
38
|
+
# streaming
|
33
39
|
wrap_function_wrapper(
|
34
|
-
"botocore.client",
|
35
|
-
"ClientCreator.create_client",
|
36
|
-
|
37
|
-
|
40
|
+
"botocore.client",
|
41
|
+
"ClientCreator.create_client",
|
42
|
+
converse_stream(version, environment, application_name, tracer, pricing_info,
|
43
|
+
capture_message_content, metrics, disable_metrics),
|
38
44
|
)
|
39
45
|
|
40
46
|
def _uninstrument(self, **kwargs):
|
41
|
-
# Proper uninstrumentation logic to revert patched methods
|
42
47
|
pass
|
@@ -2,64 +2,65 @@
|
|
2
2
|
Module for monitoring Amazon Bedrock API calls.
|
3
3
|
"""
|
4
4
|
|
5
|
-
import logging
|
6
5
|
import time
|
7
6
|
from opentelemetry.trace import SpanKind
|
8
7
|
from openlit.__helpers import (
|
8
|
+
handle_exception,
|
9
9
|
set_server_address_and_port
|
10
10
|
)
|
11
11
|
from openlit.instrumentation.bedrock.utils import (
|
12
|
+
process_chunk,
|
12
13
|
process_chat_response,
|
14
|
+
process_streaming_chat_response,
|
13
15
|
)
|
14
16
|
from openlit.semcov import SemanticConvention
|
15
17
|
|
16
|
-
|
17
|
-
logger = logging.getLogger(__name__)
|
18
|
-
|
19
|
-
def converse(version, environment, application_name, tracer, event_provider,
|
20
|
-
pricing_info, capture_message_content, metrics, disable_metrics):
|
18
|
+
def converse(version, environment, application_name, tracer, pricing_info, capture_message_content, metrics, disable_metrics):
|
21
19
|
"""
|
22
|
-
Generates a telemetry wrapper for
|
20
|
+
Generates a telemetry wrapper for AWS Bedrock converse calls.
|
23
21
|
"""
|
24
22
|
|
25
23
|
def wrapper(wrapped, instance, args, kwargs):
|
26
24
|
"""
|
27
|
-
Wraps the
|
25
|
+
Wraps the ClientCreator.create_client call.
|
28
26
|
"""
|
29
27
|
|
30
28
|
def converse_wrapper(original_method, *method_args, **method_kwargs):
|
31
|
-
|
32
29
|
"""
|
33
|
-
Wraps the
|
30
|
+
Wraps the individual converse method call.
|
34
31
|
"""
|
35
32
|
|
36
|
-
server_address, server_port = set_server_address_and_port(instance,
|
37
|
-
request_model = method_kwargs.get(
|
33
|
+
server_address, server_port = set_server_address_and_port(instance, "aws.amazon.com", 443)
|
34
|
+
request_model = method_kwargs.get("modelId", "amazon.titan-text-express-v1")
|
38
35
|
|
39
|
-
span_name = f
|
36
|
+
span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}"
|
40
37
|
|
41
38
|
with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
|
42
39
|
start_time = time.time()
|
43
40
|
response = original_method(*method_args, **method_kwargs)
|
44
|
-
llm_config = method_kwargs.get(
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
41
|
+
llm_config = method_kwargs.get("inferenceConfig", {})
|
42
|
+
|
43
|
+
try:
|
44
|
+
response = process_chat_response(
|
45
|
+
response=response,
|
46
|
+
request_model=request_model,
|
47
|
+
pricing_info=pricing_info,
|
48
|
+
server_port=server_port,
|
49
|
+
server_address=server_address,
|
50
|
+
environment=environment,
|
51
|
+
application_name=application_name,
|
52
|
+
metrics=metrics,
|
53
|
+
start_time=start_time,
|
54
|
+
span=span,
|
55
|
+
capture_message_content=capture_message_content,
|
56
|
+
disable_metrics=disable_metrics,
|
57
|
+
version=version,
|
58
|
+
llm_config=llm_config,
|
59
|
+
**method_kwargs
|
60
|
+
)
|
61
|
+
|
62
|
+
except Exception as e:
|
63
|
+
handle_exception(span, e)
|
63
64
|
|
64
65
|
return response
|
65
66
|
|
@@ -67,10 +68,143 @@ def converse(version, environment, application_name, tracer, event_provider,
|
|
67
68
|
client = wrapped(*args, **kwargs)
|
68
69
|
|
69
70
|
# Replace the original method with the instrumented one
|
70
|
-
if kwargs.get(
|
71
|
+
if kwargs.get("service_name") == "bedrock-runtime":
|
71
72
|
original_invoke_model = client.converse
|
72
|
-
client.converse = lambda *args, **kwargs: converse_wrapper(original_invoke_model,
|
73
|
-
|
73
|
+
client.converse = lambda *args, **kwargs: converse_wrapper(original_invoke_model, *args, **kwargs)
|
74
|
+
|
75
|
+
return client
|
76
|
+
|
77
|
+
return wrapper
|
78
|
+
|
79
|
+
def converse_stream(version, environment, application_name, tracer, pricing_info, capture_message_content, metrics, disable_metrics):
|
80
|
+
"""
|
81
|
+
Generates a telemetry wrapper for AWS Bedrock converse_stream calls.
|
82
|
+
"""
|
83
|
+
|
84
|
+
class TracedSyncStream:
|
85
|
+
"""
|
86
|
+
Wrapper for streaming responses to collect telemetry.
|
87
|
+
"""
|
88
|
+
|
89
|
+
def __init__(
|
90
|
+
self,
|
91
|
+
wrapped_response,
|
92
|
+
span,
|
93
|
+
span_name,
|
94
|
+
kwargs,
|
95
|
+
server_address,
|
96
|
+
server_port,
|
97
|
+
**args,
|
98
|
+
):
|
99
|
+
self.__wrapped_response = wrapped_response
|
100
|
+
# Extract the actual stream iterator from the response
|
101
|
+
if isinstance(wrapped_response, dict) and "stream" in wrapped_response:
|
102
|
+
self.__wrapped_stream = iter(wrapped_response["stream"])
|
103
|
+
else:
|
104
|
+
self.__wrapped_stream = iter(wrapped_response)
|
105
|
+
|
106
|
+
self._span = span
|
107
|
+
self._span_name = span_name
|
108
|
+
self._llmresponse = ""
|
109
|
+
self._response_id = ""
|
110
|
+
self._response_model = ""
|
111
|
+
self._finish_reason = ""
|
112
|
+
self._tools = None
|
113
|
+
self._input_tokens = 0
|
114
|
+
self._output_tokens = 0
|
115
|
+
|
116
|
+
self._args = args
|
117
|
+
self._kwargs = kwargs
|
118
|
+
self._start_time = time.time()
|
119
|
+
self._end_time = None
|
120
|
+
self._timestamps = []
|
121
|
+
self._ttft = 0
|
122
|
+
self._tbt = 0
|
123
|
+
self._server_address = server_address
|
124
|
+
self._server_port = server_port
|
125
|
+
|
126
|
+
def __enter__(self):
|
127
|
+
if hasattr(self.__wrapped_stream, "__enter__"):
|
128
|
+
self.__wrapped_stream.__enter__()
|
129
|
+
return self
|
130
|
+
|
131
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
132
|
+
if hasattr(self.__wrapped_stream, "__exit__"):
|
133
|
+
self.__wrapped_stream.__exit__(exc_type, exc_value, traceback)
|
134
|
+
|
135
|
+
def __iter__(self):
|
136
|
+
return self
|
137
|
+
|
138
|
+
def __getattr__(self, name):
|
139
|
+
"""Delegate attribute access to the wrapped response."""
|
140
|
+
return getattr(self.__wrapped_response, name)
|
141
|
+
|
142
|
+
def get(self, key, default=None):
|
143
|
+
"""Delegate get method to the wrapped response if its a dict."""
|
144
|
+
if isinstance(self.__wrapped_response, dict):
|
145
|
+
return self.__wrapped_response.get(key, default)
|
146
|
+
return getattr(self.__wrapped_response, key, default)
|
147
|
+
|
148
|
+
def __getitem__(self, key):
|
149
|
+
"""Delegate item access to the wrapped response if its a dict."""
|
150
|
+
if isinstance(self.__wrapped_response, dict):
|
151
|
+
return self.__wrapped_response[key]
|
152
|
+
return getattr(self.__wrapped_response, key)
|
153
|
+
|
154
|
+
def __next__(self):
|
155
|
+
try:
|
156
|
+
chunk = next(self.__wrapped_stream)
|
157
|
+
process_chunk(self, chunk)
|
158
|
+
return chunk
|
159
|
+
except StopIteration:
|
160
|
+
try:
|
161
|
+
llm_config = self._kwargs.get("inferenceConfig", {})
|
162
|
+
with tracer.start_as_current_span(self._span_name, kind=SpanKind.CLIENT) as self._span:
|
163
|
+
process_streaming_chat_response(
|
164
|
+
self,
|
165
|
+
pricing_info=pricing_info,
|
166
|
+
environment=environment,
|
167
|
+
application_name=application_name,
|
168
|
+
metrics=metrics,
|
169
|
+
capture_message_content=capture_message_content,
|
170
|
+
disable_metrics=disable_metrics,
|
171
|
+
version=version,
|
172
|
+
llm_config=llm_config
|
173
|
+
)
|
174
|
+
|
175
|
+
except Exception as e:
|
176
|
+
handle_exception(self._span, e)
|
177
|
+
|
178
|
+
raise
|
179
|
+
|
180
|
+
def wrapper(wrapped, instance, args, kwargs):
|
181
|
+
"""
|
182
|
+
Wraps the ClientCreator.create_client call.
|
183
|
+
"""
|
184
|
+
|
185
|
+
def converse_stream_wrapper(original_method, *method_args, **method_kwargs):
|
186
|
+
"""
|
187
|
+
Wraps the individual converse_stream method call.
|
188
|
+
"""
|
189
|
+
|
190
|
+
server_address, server_port = set_server_address_and_port(instance, "aws.amazon.com", 443)
|
191
|
+
request_model = method_kwargs.get("modelId", "amazon.titan-text-express-v1")
|
192
|
+
|
193
|
+
span_name = f"{SemanticConvention.GEN_AI_OPERATION_TYPE_CHAT} {request_model}"
|
194
|
+
|
195
|
+
# Get the streaming response
|
196
|
+
stream_response = original_method(*method_args, **method_kwargs)
|
197
|
+
span = tracer.start_span(span_name, kind=SpanKind.CLIENT)
|
198
|
+
|
199
|
+
return TracedSyncStream(stream_response, span, span_name, method_kwargs, server_address, server_port)
|
200
|
+
|
201
|
+
# Get the original client instance from the wrapper
|
202
|
+
client = wrapped(*args, **kwargs)
|
203
|
+
|
204
|
+
# Replace the original method with the instrumented one
|
205
|
+
if kwargs.get("service_name") == "bedrock-runtime":
|
206
|
+
original_stream_model = client.converse_stream
|
207
|
+
client.converse_stream = lambda *args, **kwargs: converse_stream_wrapper(original_stream_model, *args, **kwargs)
|
74
208
|
|
75
209
|
return client
|
76
210
|
|