openlit 1.33.9__py3-none-any.whl → 1.33.11__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 +78 -0
- openlit/__init__.py +41 -13
- openlit/instrumentation/ag2/__init__.py +9 -10
- openlit/instrumentation/ag2/ag2.py +134 -69
- openlit/instrumentation/ai21/__init__.py +6 -5
- openlit/instrumentation/ai21/ai21.py +71 -534
- openlit/instrumentation/ai21/async_ai21.py +71 -534
- openlit/instrumentation/ai21/utils.py +407 -0
- openlit/instrumentation/anthropic/__init__.py +3 -3
- openlit/instrumentation/anthropic/anthropic.py +5 -5
- openlit/instrumentation/anthropic/async_anthropic.py +5 -5
- openlit/instrumentation/assemblyai/__init__.py +2 -2
- openlit/instrumentation/assemblyai/assemblyai.py +3 -3
- openlit/instrumentation/astra/__init__.py +25 -25
- openlit/instrumentation/astra/astra.py +7 -7
- openlit/instrumentation/astra/async_astra.py +7 -7
- openlit/instrumentation/azure_ai_inference/__init__.py +5 -5
- openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +11 -11
- openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +11 -11
- openlit/instrumentation/bedrock/__init__.py +2 -2
- openlit/instrumentation/bedrock/bedrock.py +3 -3
- openlit/instrumentation/chroma/__init__.py +9 -9
- openlit/instrumentation/chroma/chroma.py +7 -7
- openlit/instrumentation/cohere/__init__.py +7 -7
- openlit/instrumentation/cohere/async_cohere.py +10 -10
- openlit/instrumentation/cohere/cohere.py +11 -11
- openlit/instrumentation/controlflow/__init__.py +4 -4
- openlit/instrumentation/controlflow/controlflow.py +5 -5
- openlit/instrumentation/crawl4ai/__init__.py +3 -3
- openlit/instrumentation/crawl4ai/async_crawl4ai.py +5 -5
- openlit/instrumentation/crawl4ai/crawl4ai.py +5 -5
- openlit/instrumentation/crewai/__init__.py +3 -3
- openlit/instrumentation/crewai/crewai.py +6 -4
- openlit/instrumentation/dynamiq/__init__.py +5 -5
- openlit/instrumentation/dynamiq/dynamiq.py +5 -5
- openlit/instrumentation/elevenlabs/__init__.py +5 -5
- openlit/instrumentation/elevenlabs/async_elevenlabs.py +4 -5
- openlit/instrumentation/elevenlabs/elevenlabs.py +4 -5
- openlit/instrumentation/embedchain/__init__.py +2 -2
- openlit/instrumentation/embedchain/embedchain.py +9 -9
- openlit/instrumentation/firecrawl/__init__.py +3 -3
- openlit/instrumentation/firecrawl/firecrawl.py +5 -5
- openlit/instrumentation/google_ai_studio/__init__.py +3 -3
- openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +3 -3
- openlit/instrumentation/google_ai_studio/google_ai_studio.py +3 -3
- openlit/instrumentation/gpt4all/__init__.py +5 -5
- openlit/instrumentation/gpt4all/gpt4all.py +350 -225
- openlit/instrumentation/gpu/__init__.py +5 -5
- openlit/instrumentation/groq/__init__.py +5 -5
- openlit/instrumentation/groq/async_groq.py +359 -243
- openlit/instrumentation/groq/groq.py +359 -243
- openlit/instrumentation/haystack/__init__.py +2 -2
- openlit/instrumentation/haystack/haystack.py +5 -5
- openlit/instrumentation/julep/__init__.py +7 -7
- openlit/instrumentation/julep/async_julep.py +6 -6
- openlit/instrumentation/julep/julep.py +6 -6
- openlit/instrumentation/langchain/__init__.py +15 -9
- openlit/instrumentation/langchain/async_langchain.py +388 -0
- openlit/instrumentation/langchain/langchain.py +110 -497
- openlit/instrumentation/letta/__init__.py +7 -7
- openlit/instrumentation/letta/letta.py +10 -8
- openlit/instrumentation/litellm/__init__.py +9 -10
- openlit/instrumentation/litellm/async_litellm.py +321 -250
- openlit/instrumentation/litellm/litellm.py +319 -248
- openlit/instrumentation/llamaindex/__init__.py +2 -2
- openlit/instrumentation/llamaindex/llamaindex.py +5 -5
- openlit/instrumentation/mem0/__init__.py +2 -2
- openlit/instrumentation/mem0/mem0.py +5 -5
- openlit/instrumentation/milvus/__init__.py +2 -2
- openlit/instrumentation/milvus/milvus.py +7 -7
- openlit/instrumentation/mistral/__init__.py +13 -13
- openlit/instrumentation/mistral/async_mistral.py +426 -253
- openlit/instrumentation/mistral/mistral.py +424 -250
- openlit/instrumentation/multion/__init__.py +7 -7
- openlit/instrumentation/multion/async_multion.py +9 -7
- openlit/instrumentation/multion/multion.py +9 -7
- openlit/instrumentation/ollama/__init__.py +19 -39
- openlit/instrumentation/ollama/async_ollama.py +137 -563
- openlit/instrumentation/ollama/ollama.py +136 -563
- openlit/instrumentation/ollama/utils.py +333 -0
- openlit/instrumentation/openai/__init__.py +11 -11
- openlit/instrumentation/openai/async_openai.py +25 -27
- openlit/instrumentation/openai/openai.py +25 -27
- openlit/instrumentation/phidata/__init__.py +2 -2
- openlit/instrumentation/phidata/phidata.py +6 -4
- openlit/instrumentation/pinecone/__init__.py +6 -6
- openlit/instrumentation/pinecone/pinecone.py +7 -7
- openlit/instrumentation/premai/__init__.py +5 -5
- openlit/instrumentation/premai/premai.py +268 -219
- openlit/instrumentation/qdrant/__init__.py +2 -2
- openlit/instrumentation/qdrant/async_qdrant.py +7 -7
- openlit/instrumentation/qdrant/qdrant.py +7 -7
- openlit/instrumentation/reka/__init__.py +5 -5
- openlit/instrumentation/reka/async_reka.py +93 -55
- openlit/instrumentation/reka/reka.py +93 -55
- openlit/instrumentation/together/__init__.py +9 -9
- openlit/instrumentation/together/async_together.py +284 -242
- openlit/instrumentation/together/together.py +284 -242
- openlit/instrumentation/transformers/__init__.py +3 -3
- openlit/instrumentation/transformers/transformers.py +79 -48
- openlit/instrumentation/vertexai/__init__.py +19 -69
- openlit/instrumentation/vertexai/async_vertexai.py +333 -990
- openlit/instrumentation/vertexai/vertexai.py +333 -990
- openlit/instrumentation/vllm/__init__.py +3 -3
- openlit/instrumentation/vllm/vllm.py +65 -35
- openlit/otel/events.py +85 -0
- openlit/otel/tracing.py +3 -13
- openlit/semcov/__init__.py +16 -4
- {openlit-1.33.9.dist-info → openlit-1.33.11.dist-info}/METADATA +2 -2
- openlit-1.33.11.dist-info/RECORD +125 -0
- openlit-1.33.9.dist-info/RECORD +0 -121
- {openlit-1.33.9.dist-info → openlit-1.33.11.dist-info}/LICENSE +0 -0
- {openlit-1.33.9.dist-info → openlit-1.33.11.dist-info}/WHEEL +0 -0
@@ -4,9 +4,17 @@ Module for monitoring Langchain applications.
|
|
4
4
|
"""
|
5
5
|
|
6
6
|
import logging
|
7
|
+
import time
|
7
8
|
from opentelemetry.trace import SpanKind, Status, StatusCode
|
8
|
-
from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
|
9
|
-
from openlit.__helpers import
|
9
|
+
from opentelemetry.sdk.resources import SERVICE_NAME, TELEMETRY_SDK_NAME, DEPLOYMENT_ENVIRONMENT
|
10
|
+
from openlit.__helpers import (
|
11
|
+
get_chat_model_cost,
|
12
|
+
handle_exception,
|
13
|
+
general_tokens,
|
14
|
+
calculate_ttft,
|
15
|
+
calculate_tbt,
|
16
|
+
create_metrics_attributes,
|
17
|
+
)
|
10
18
|
from openlit.semcov import SemanticConvetion
|
11
19
|
|
12
20
|
# Initialize logger for logging potential issues and operations
|
@@ -33,7 +41,7 @@ def get_attribute_from_instance_or_kwargs(instance, attribute_name, default=-1):
|
|
33
41
|
return default
|
34
42
|
|
35
43
|
def general_wrap(gen_ai_endpoint, version, environment, application_name,
|
36
|
-
tracer, pricing_info,
|
44
|
+
tracer, pricing_info, capture_message_content, metrics, disable_metrics):
|
37
45
|
"""
|
38
46
|
Creates a wrapper around a function call to trace and log its execution metrics.
|
39
47
|
|
@@ -47,7 +55,7 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
|
|
47
55
|
- application_name (str): Name of the Langchain application.
|
48
56
|
- tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
|
49
57
|
- pricing_info (dict): Information about the pricing for internal metrics (currently not used).
|
50
|
-
-
|
58
|
+
- capture_message_content (bool): Flag indicating whether to trace the content of the response.
|
51
59
|
|
52
60
|
Returns:
|
53
61
|
- function: A higher-order function that takes a function 'wrapped' and returns
|
@@ -83,11 +91,11 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
|
|
83
91
|
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
84
92
|
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
85
93
|
gen_ai_endpoint)
|
86
|
-
span.set_attribute(
|
94
|
+
span.set_attribute(DEPLOYMENT_ENVIRONMENT,
|
87
95
|
environment)
|
88
96
|
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
89
97
|
SemanticConvetion.GEN_AI_OPERATION_TYPE_FRAMEWORK)
|
90
|
-
span.set_attribute(
|
98
|
+
span.set_attribute(SERVICE_NAME,
|
91
99
|
application_name)
|
92
100
|
span.set_attribute(SemanticConvetion.GEN_AI_RETRIEVAL_SOURCE,
|
93
101
|
response[0].metadata["source"])
|
@@ -106,7 +114,7 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
|
|
106
114
|
return wrapper
|
107
115
|
|
108
116
|
def hub(gen_ai_endpoint, version, environment, application_name, tracer,
|
109
|
-
pricing_info,
|
117
|
+
pricing_info, capture_message_content, metrics, disable_metrics):
|
110
118
|
"""
|
111
119
|
Creates a wrapper around Langchain hub operations for tracing and logging.
|
112
120
|
|
@@ -121,7 +129,7 @@ def hub(gen_ai_endpoint, version, environment, application_name, tracer,
|
|
121
129
|
- application_name (str): Name of the Langchain application.
|
122
130
|
- tracer (opentelemetry.trace.Tracer): The tracer for OpenTelemetry tracing.
|
123
131
|
- pricing_info (dict): Pricing information for the operation (not currently used).
|
124
|
-
-
|
132
|
+
- capture_message_content (bool): Indicates if the content of the response should be traced.
|
125
133
|
|
126
134
|
Returns:
|
127
135
|
- function: A new function that wraps the original hub operation call with added
|
@@ -157,11 +165,11 @@ def hub(gen_ai_endpoint, version, environment, application_name, tracer,
|
|
157
165
|
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
158
166
|
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
159
167
|
gen_ai_endpoint)
|
160
|
-
span.set_attribute(
|
168
|
+
span.set_attribute(DEPLOYMENT_ENVIRONMENT,
|
161
169
|
environment)
|
162
170
|
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
163
171
|
SemanticConvetion.GEN_AI_OPERATION_TYPE_FRAMEWORK)
|
164
|
-
span.set_attribute(
|
172
|
+
span.set_attribute(SERVICE_NAME,
|
165
173
|
application_name)
|
166
174
|
span.set_attribute(SemanticConvetion.GEN_AI_HUB_OWNER,
|
167
175
|
response.metadata["lc_hub_owner"])
|
@@ -180,149 +188,8 @@ def hub(gen_ai_endpoint, version, environment, application_name, tracer,
|
|
180
188
|
|
181
189
|
return wrapper
|
182
190
|
|
183
|
-
|
184
|
-
|
185
|
-
tracer, pricing_info, trace_content, metrics, disable_metrics):
|
186
|
-
"""
|
187
|
-
Creates a wrapper around a function call to trace and log its execution metrics.
|
188
|
-
|
189
|
-
This function wraps any given function to measure its execution time,
|
190
|
-
log its operation, and trace its execution using OpenTelemetry.
|
191
|
-
|
192
|
-
Parameters:
|
193
|
-
- gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
|
194
|
-
- version (str): The version of the Langchain application.
|
195
|
-
- environment (str): The deployment environment (e.g., 'production', 'development').
|
196
|
-
- application_name (str): Name of the Langchain application.
|
197
|
-
- tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
|
198
|
-
- pricing_info (dict): Information about the pricing for internal metrics (currently not used).
|
199
|
-
- trace_content (bool): Flag indicating whether to trace the content of the response.
|
200
|
-
|
201
|
-
Returns:
|
202
|
-
- function: A higher-order function that takes a function 'wrapped' and returns
|
203
|
-
a new function that wraps 'wrapped' with additional tracing and logging.
|
204
|
-
"""
|
205
|
-
|
206
|
-
async def wrapper(wrapped, instance, args, kwargs):
|
207
|
-
"""
|
208
|
-
An inner wrapper function that executes the wrapped function, measures execution
|
209
|
-
time, and records trace data using OpenTelemetry.
|
210
|
-
|
211
|
-
Parameters:
|
212
|
-
- wrapped (Callable): The original function that this wrapper will execute.
|
213
|
-
- instance (object): The instance to which the wrapped function belongs. This
|
214
|
-
is used for instance methods. For static and classmethods,
|
215
|
-
this may be None.
|
216
|
-
- args (tuple): Positional arguments passed to the wrapped function.
|
217
|
-
- kwargs (dict): Keyword arguments passed to the wrapped function.
|
218
|
-
|
219
|
-
Returns:
|
220
|
-
- The result of the wrapped function call.
|
221
|
-
|
222
|
-
The wrapper initiates a span with the provided tracer, sets various attributes
|
223
|
-
on the span based on the function's execution and response, and ensures
|
224
|
-
errors are handled and logged appropriately.
|
225
|
-
"""
|
226
|
-
with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
|
227
|
-
response = await wrapped(*args, **kwargs)
|
228
|
-
|
229
|
-
try:
|
230
|
-
if args:
|
231
|
-
prompt = str(args[0]) if args[0] is not None else ""
|
232
|
-
else:
|
233
|
-
prompt = ""
|
234
|
-
input_tokens = general_tokens(prompt)
|
235
|
-
output_tokens = general_tokens(response)
|
236
|
-
|
237
|
-
# Calculate cost of the operation
|
238
|
-
cost = get_chat_model_cost(
|
239
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model')),
|
240
|
-
pricing_info, input_tokens, output_tokens
|
241
|
-
)
|
242
|
-
|
243
|
-
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
244
|
-
span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
|
245
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
246
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
247
|
-
gen_ai_endpoint)
|
248
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
|
249
|
-
environment)
|
250
|
-
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
251
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_FRAMEWORK)
|
252
|
-
span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
|
253
|
-
application_name)
|
254
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
|
255
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model')))
|
256
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
|
257
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'temperature')))
|
258
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
|
259
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'top_k')))
|
260
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
|
261
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'top_p')))
|
262
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
|
263
|
-
False)
|
264
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_INPUT_TOKENS,
|
265
|
-
input_tokens)
|
266
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_OUTPUT_TOKENS,
|
267
|
-
output_tokens)
|
268
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
|
269
|
-
input_tokens + output_tokens)
|
270
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
|
271
|
-
cost)
|
272
|
-
if trace_content:
|
273
|
-
span.add_event(
|
274
|
-
name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
|
275
|
-
attributes={
|
276
|
-
SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
|
277
|
-
},
|
278
|
-
)
|
279
|
-
span.add_event(
|
280
|
-
name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
|
281
|
-
attributes={
|
282
|
-
SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response,
|
283
|
-
},
|
284
|
-
)
|
285
|
-
|
286
|
-
span.set_status(Status(StatusCode.OK))
|
287
|
-
|
288
|
-
if disable_metrics is False:
|
289
|
-
attributes = {
|
290
|
-
TELEMETRY_SDK_NAME:
|
291
|
-
"openlit",
|
292
|
-
SemanticConvetion.GEN_AI_APPLICATION_NAME:
|
293
|
-
application_name,
|
294
|
-
SemanticConvetion.GEN_AI_SYSTEM:
|
295
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
|
296
|
-
SemanticConvetion.GEN_AI_ENVIRONMENT:
|
297
|
-
environment,
|
298
|
-
SemanticConvetion.GEN_AI_OPERATION:
|
299
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT,
|
300
|
-
SemanticConvetion.GEN_AI_REQUEST_MODEL:
|
301
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model'))
|
302
|
-
}
|
303
|
-
|
304
|
-
metrics["genai_requests"].add(1, attributes)
|
305
|
-
metrics["genai_total_tokens"].add(
|
306
|
-
input_tokens + output_tokens, attributes
|
307
|
-
)
|
308
|
-
metrics["genai_completion_tokens"].add(output_tokens, attributes)
|
309
|
-
metrics["genai_prompt_tokens"].add(input_tokens, attributes)
|
310
|
-
metrics["genai_cost"].record(cost, attributes)
|
311
|
-
|
312
|
-
# Return original response
|
313
|
-
return response
|
314
|
-
|
315
|
-
except Exception as e:
|
316
|
-
handle_exception(span, e)
|
317
|
-
logger.error("Error in trace creation: %s", e)
|
318
|
-
|
319
|
-
# Return original response
|
320
|
-
return response
|
321
|
-
|
322
|
-
return wrapper
|
323
|
-
|
324
|
-
def llm(gen_ai_endpoint, version, environment, application_name,
|
325
|
-
tracer, pricing_info, trace_content, metrics, disable_metrics):
|
191
|
+
def chat(gen_ai_endpoint, version, environment, application_name,
|
192
|
+
tracer, pricing_info, capture_message_content, metrics, disable_metrics):
|
326
193
|
"""
|
327
194
|
Creates a wrapper around a function call to trace and log its execution metrics.
|
328
195
|
|
@@ -330,13 +197,12 @@ def llm(gen_ai_endpoint, version, environment, application_name,
|
|
330
197
|
log its operation, and trace its execution using OpenTelemetry.
|
331
198
|
|
332
199
|
Parameters:
|
333
|
-
- gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
|
334
200
|
- version (str): The version of the Langchain application.
|
335
201
|
- environment (str): The deployment environment (e.g., 'production', 'development').
|
336
202
|
- application_name (str): Name of the Langchain application.
|
337
203
|
- tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
|
338
204
|
- pricing_info (dict): Information about the pricing for internal metrics (currently not used).
|
339
|
-
-
|
205
|
+
- capture_message_content (bool): Flag indicating whether to trace the content of the response.
|
340
206
|
|
341
207
|
Returns:
|
342
208
|
- function: A higher-order function that takes a function 'wrapped' and returns
|
@@ -363,366 +229,111 @@ def llm(gen_ai_endpoint, version, environment, application_name,
|
|
363
229
|
on the span based on the function's execution and response, and ensures
|
364
230
|
errors are handled and logged appropriately.
|
365
231
|
"""
|
366
|
-
with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
|
367
|
-
response = wrapped(*args, **kwargs)
|
368
|
-
|
369
|
-
try:
|
370
|
-
if args:
|
371
|
-
prompt = str(args[0]) if args[0] is not None else ""
|
372
|
-
else:
|
373
|
-
prompt = ""
|
374
|
-
input_tokens = general_tokens(prompt)
|
375
|
-
output_tokens = general_tokens(response)
|
376
|
-
|
377
|
-
# Calculate cost of the operation
|
378
|
-
cost = get_chat_model_cost(
|
379
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model')),
|
380
|
-
pricing_info, input_tokens, output_tokens
|
381
|
-
)
|
382
|
-
|
383
|
-
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
384
|
-
span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
|
385
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
386
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
387
|
-
gen_ai_endpoint)
|
388
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
|
389
|
-
environment)
|
390
|
-
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
391
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_FRAMEWORK)
|
392
|
-
span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
|
393
|
-
application_name)
|
394
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
|
395
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model')))
|
396
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
|
397
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'temperature')))
|
398
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
|
399
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'top_k')))
|
400
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
|
401
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'top_p')))
|
402
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
|
403
|
-
False)
|
404
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_INPUT_TOKENS,
|
405
|
-
input_tokens)
|
406
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_OUTPUT_TOKENS,
|
407
|
-
output_tokens)
|
408
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
|
409
|
-
input_tokens + output_tokens)
|
410
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
|
411
|
-
cost)
|
412
|
-
if trace_content:
|
413
|
-
span.add_event(
|
414
|
-
name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
|
415
|
-
attributes={
|
416
|
-
SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
|
417
|
-
},
|
418
|
-
)
|
419
|
-
span.add_event(
|
420
|
-
name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
|
421
|
-
attributes={
|
422
|
-
SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response,
|
423
|
-
},
|
424
|
-
)
|
425
|
-
|
426
|
-
span.set_status(Status(StatusCode.OK))
|
427
|
-
|
428
|
-
if disable_metrics is False:
|
429
|
-
attributes = {
|
430
|
-
TELEMETRY_SDK_NAME:
|
431
|
-
"openlit",
|
432
|
-
SemanticConvetion.GEN_AI_APPLICATION_NAME:
|
433
|
-
application_name,
|
434
|
-
SemanticConvetion.GEN_AI_SYSTEM:
|
435
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
|
436
|
-
SemanticConvetion.GEN_AI_ENVIRONMENT:
|
437
|
-
environment,
|
438
|
-
SemanticConvetion.GEN_AI_OPERATION:
|
439
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT,
|
440
|
-
SemanticConvetion.GEN_AI_REQUEST_MODEL:
|
441
|
-
str(get_attribute_from_instance_or_kwargs(instance, 'model'))
|
442
|
-
}
|
443
|
-
|
444
|
-
metrics["genai_requests"].add(1, attributes)
|
445
|
-
metrics["genai_total_tokens"].add(
|
446
|
-
input_tokens + output_tokens, attributes
|
447
|
-
)
|
448
|
-
metrics["genai_completion_tokens"].add(output_tokens, attributes)
|
449
|
-
metrics["genai_prompt_tokens"].add(input_tokens, attributes)
|
450
|
-
metrics["genai_cost"].record(cost, attributes)
|
451
|
-
|
452
|
-
# Return original response
|
453
|
-
return response
|
454
|
-
|
455
|
-
except Exception as e:
|
456
|
-
handle_exception(span, e)
|
457
|
-
logger.error("Error in trace creation: %s", e)
|
458
|
-
|
459
|
-
# Return original response
|
460
|
-
return response
|
461
|
-
|
462
|
-
return wrapper
|
463
|
-
|
464
|
-
def chat(gen_ai_endpoint, version, environment, application_name,
|
465
|
-
tracer, pricing_info, trace_content, metrics, disable_metrics):
|
466
|
-
"""
|
467
|
-
Creates a wrapper around a function call to trace and log its execution metrics.
|
468
|
-
|
469
|
-
This function wraps any given function to measure its execution time,
|
470
|
-
log its operation, and trace its execution using OpenTelemetry.
|
471
|
-
|
472
|
-
Parameters:
|
473
|
-
- gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
|
474
|
-
- version (str): The version of the Langchain application.
|
475
|
-
- environment (str): The deployment environment (e.g., 'production', 'development').
|
476
|
-
- application_name (str): Name of the Langchain application.
|
477
|
-
- tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
|
478
|
-
- pricing_info (dict): Information about the pricing for internal metrics (currently not used).
|
479
|
-
- trace_content (bool): Flag indicating whether to trace the content of the response.
|
480
232
|
|
481
|
-
|
482
|
-
- function: A higher-order function that takes a function 'wrapped' and returns
|
483
|
-
a new function that wraps 'wrapped' with additional tracing and logging.
|
484
|
-
"""
|
233
|
+
server_address, server_port = "NOT_FOUND", "NOT_FOUND"
|
485
234
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
235
|
+
if hasattr(instance, "model_id"):
|
236
|
+
request_model = instance.model_id
|
237
|
+
elif hasattr(instance, "model"):
|
238
|
+
request_model = instance.model
|
239
|
+
elif hasattr(instance, "model_name"):
|
240
|
+
request_model = instance.model_name
|
241
|
+
else:
|
242
|
+
request_model = "NOT_FOUND"
|
490
243
|
|
491
|
-
|
492
|
-
- wrapped (Callable): The original function that this wrapper will execute.
|
493
|
-
- instance (object): The instance to which the wrapped function belongs. This
|
494
|
-
is used for instance methods. For static and classmethods,
|
495
|
-
this may be None.
|
496
|
-
- args (tuple): Positional arguments passed to the wrapped function.
|
497
|
-
- kwargs (dict): Keyword arguments passed to the wrapped function.
|
244
|
+
span_name = f"{SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT} {request_model}"
|
498
245
|
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
The wrapper initiates a span with the provided tracer, sets various attributes
|
503
|
-
on the span based on the function's execution and response, and ensures
|
504
|
-
errors are handled and logged appropriately.
|
505
|
-
"""
|
506
|
-
with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
|
246
|
+
with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
|
247
|
+
start_time = time.time()
|
507
248
|
response = wrapped(*args, **kwargs)
|
249
|
+
end_time = time.time()
|
508
250
|
|
509
251
|
try:
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
252
|
+
# Format 'messages' into a single string
|
253
|
+
message_prompt = kwargs.get("messages", "") or args[0]
|
254
|
+
formatted_messages = []
|
255
|
+
|
256
|
+
for message in message_prompt:
|
257
|
+
# Handle the case where message is a tuple
|
258
|
+
if isinstance(message, tuple) and len(message) == 2:
|
259
|
+
role, content = message
|
260
|
+
# Handle the case where message is a dictionary
|
261
|
+
elif isinstance(message, dict):
|
262
|
+
role = message["role"]
|
263
|
+
content = message["content"]
|
517
264
|
else:
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
if
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
265
|
+
continue
|
266
|
+
|
267
|
+
# Check if the content is a list
|
268
|
+
if isinstance(content, list):
|
269
|
+
content_str = ", ".join(
|
270
|
+
f'{item["type"]}: {item["text"] if "text" in item else item["image_url"]}'
|
271
|
+
if "type" in item else f'text: {item["text"]}'
|
272
|
+
for item in content
|
273
|
+
)
|
274
|
+
formatted_messages.append(f"{role}: {content_str}")
|
275
|
+
else:
|
276
|
+
formatted_messages.append(f"{role}: {content}")
|
277
|
+
|
278
|
+
# Join all formatted messages with newline
|
279
|
+
prompt = "\n".join(formatted_messages)
|
280
|
+
|
281
|
+
input_tokens = general_tokens(str(prompt))
|
282
|
+
output_tokens = general_tokens(str(response))
|
532
283
|
|
533
284
|
# Calculate cost of the operation
|
534
285
|
cost = get_chat_model_cost(
|
535
|
-
|
286
|
+
request_model,
|
536
287
|
pricing_info, input_tokens, output_tokens
|
537
288
|
)
|
538
289
|
|
290
|
+
try:
|
291
|
+
llm_response = response.content
|
292
|
+
except AttributeError:
|
293
|
+
llm_response = response
|
294
|
+
|
295
|
+
# Set base span attribues (OTel Semconv)
|
539
296
|
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
540
|
-
span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
|
541
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
542
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
543
|
-
gen_ai_endpoint)
|
544
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
|
545
|
-
environment)
|
546
297
|
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
547
298
|
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT)
|
548
|
-
span.set_attribute(SemanticConvetion.
|
549
|
-
|
299
|
+
span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
|
300
|
+
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
550
301
|
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
|
551
|
-
|
302
|
+
request_model)
|
303
|
+
span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_MODEL,
|
304
|
+
request_model)
|
552
305
|
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
|
553
306
|
str(getattr(instance, 'temperature', 1)))
|
554
307
|
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
|
555
308
|
str(getattr(instance, 'top_k', 1)))
|
556
309
|
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
|
557
310
|
str(getattr(instance, 'top_p', 1)))
|
558
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
|
559
|
-
False)
|
560
311
|
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_INPUT_TOKENS,
|
561
312
|
input_tokens)
|
562
313
|
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_OUTPUT_TOKENS,
|
563
314
|
output_tokens)
|
564
|
-
span.set_attribute(SemanticConvetion.
|
565
|
-
|
566
|
-
span.set_attribute(SemanticConvetion.
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
},
|
574
|
-
)
|
575
|
-
completion_content = getattr(response, 'content', "")
|
576
|
-
span.add_event(
|
577
|
-
name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
|
578
|
-
attributes={
|
579
|
-
SemanticConvetion.GEN_AI_CONTENT_COMPLETION: completion_content,
|
580
|
-
},
|
581
|
-
)
|
582
|
-
|
583
|
-
span.set_status(Status(StatusCode.OK))
|
584
|
-
|
585
|
-
if disable_metrics is False:
|
586
|
-
attributes = {
|
587
|
-
TELEMETRY_SDK_NAME:
|
588
|
-
"openlit",
|
589
|
-
SemanticConvetion.GEN_AI_APPLICATION_NAME:
|
590
|
-
application_name,
|
591
|
-
SemanticConvetion.GEN_AI_SYSTEM:
|
592
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
|
593
|
-
SemanticConvetion.GEN_AI_ENVIRONMENT:
|
594
|
-
environment,
|
595
|
-
SemanticConvetion.GEN_AI_OPERATION:
|
596
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT,
|
597
|
-
SemanticConvetion.GEN_AI_REQUEST_MODEL:
|
598
|
-
model
|
599
|
-
}
|
600
|
-
|
601
|
-
metrics["genai_requests"].add(1, attributes)
|
602
|
-
metrics["genai_total_tokens"].add(
|
603
|
-
input_tokens + output_tokens, attributes
|
604
|
-
)
|
605
|
-
metrics["genai_completion_tokens"].add(output_tokens, attributes)
|
606
|
-
metrics["genai_prompt_tokens"].add(input_tokens, attributes)
|
607
|
-
metrics["genai_cost"].record(cost, attributes)
|
608
|
-
|
609
|
-
# Return original response
|
610
|
-
return response
|
611
|
-
|
612
|
-
except Exception as e:
|
613
|
-
handle_exception(span, e)
|
614
|
-
logger.error("Error in trace creation: %s", e)
|
615
|
-
|
616
|
-
# Return original response
|
617
|
-
return response
|
618
|
-
|
619
|
-
return wrapper
|
620
|
-
|
621
|
-
def achat(gen_ai_endpoint, version, environment, application_name,
|
622
|
-
tracer, pricing_info, trace_content, metrics, disable_metrics):
|
623
|
-
"""
|
624
|
-
Creates a wrapper around a function call to trace and log its execution metrics.
|
625
|
-
|
626
|
-
This function wraps any given function to measure its execution time,
|
627
|
-
log its operation, and trace its execution using OpenTelemetry.
|
628
|
-
|
629
|
-
Parameters:
|
630
|
-
- gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
|
631
|
-
- version (str): The version of the Langchain application.
|
632
|
-
- environment (str): The deployment environment (e.g., 'production', 'development').
|
633
|
-
- application_name (str): Name of the Langchain application.
|
634
|
-
- tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
|
635
|
-
- pricing_info (dict): Information about the pricing for internal metrics (currently not used).
|
636
|
-
- trace_content (bool): Flag indicating whether to trace the content of the response.
|
637
|
-
|
638
|
-
Returns:
|
639
|
-
- function: A higher-order function that takes a function 'wrapped' and returns
|
640
|
-
a new function that wraps 'wrapped' with additional tracing and logging.
|
641
|
-
"""
|
642
|
-
|
643
|
-
async def wrapper(wrapped, instance, args, kwargs):
|
644
|
-
"""
|
645
|
-
An inner wrapper function that executes the wrapped function, measures execution
|
646
|
-
time, and records trace data using OpenTelemetry.
|
647
|
-
|
648
|
-
Parameters:
|
649
|
-
- wrapped (Callable): The original function that this wrapper will execute.
|
650
|
-
- instance (object): The instance to which the wrapped function belongs. This
|
651
|
-
is used for instance methods. For static and classmethods,
|
652
|
-
this may be None.
|
653
|
-
- args (tuple): Positional arguments passed to the wrapped function.
|
654
|
-
- kwargs (dict): Keyword arguments passed to the wrapped function.
|
655
|
-
|
656
|
-
Returns:
|
657
|
-
- The result of the wrapped function call.
|
658
|
-
|
659
|
-
The wrapper initiates a span with the provided tracer, sets various attributes
|
660
|
-
on the span based on the function's execution and response, and ensures
|
661
|
-
errors are handled and logged appropriately.
|
662
|
-
"""
|
663
|
-
with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
|
664
|
-
response = await wrapped(*args, **kwargs)
|
665
|
-
|
666
|
-
try:
|
667
|
-
prompt = ""
|
668
|
-
if hasattr(response, 'usage_metadata') and response.usage_metadata:
|
669
|
-
token_usage = response.usage_metadata
|
670
|
-
input_tokens = token_usage.get("input_tokens", 0)
|
671
|
-
output_tokens = token_usage.get("output_tokens", 0)
|
672
|
-
if hasattr(instance, "model_id"):
|
673
|
-
model = instance.model_id
|
674
|
-
else:
|
675
|
-
model = instance.model_name
|
676
|
-
prompt = "" if isinstance(args[0], list) else args[0]
|
677
|
-
else:
|
678
|
-
if not isinstance(response, dict) or "output_text" not in response:
|
679
|
-
return response
|
680
|
-
# Fallback: Calculate tokens manually if response_metadata is missing
|
681
|
-
model = "gpt-4o-mini" # Fallback model
|
682
|
-
input_texts = [
|
683
|
-
doc.page_content for doc in response.get("input_documents", [])
|
684
|
-
if isinstance(doc.page_content, str)
|
685
|
-
]
|
686
|
-
input_tokens = sum(general_tokens(text) for text in input_texts)
|
687
|
-
output_text = response.get("output_text", "")
|
688
|
-
output_tokens = general_tokens(output_text)
|
689
|
-
|
690
|
-
# Calculate cost of the operation
|
691
|
-
cost = get_chat_model_cost(
|
692
|
-
model,
|
693
|
-
pricing_info, input_tokens, output_tokens
|
694
|
-
)
|
695
|
-
|
696
|
-
span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
|
697
|
-
span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
|
698
|
-
SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
|
699
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
|
700
|
-
gen_ai_endpoint)
|
701
|
-
span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
|
702
|
-
environment)
|
703
|
-
span.set_attribute(SemanticConvetion.GEN_AI_OPERATION,
|
704
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT)
|
705
|
-
span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
|
315
|
+
span.set_attribute(SemanticConvetion.SERVER_ADDRESS,
|
316
|
+
server_address)
|
317
|
+
span.set_attribute(SemanticConvetion.SERVER_PORT,
|
318
|
+
server_port)
|
319
|
+
|
320
|
+
# Set base span attribues (Extras)
|
321
|
+
span.set_attribute(DEPLOYMENT_ENVIRONMENT,
|
322
|
+
environment)
|
323
|
+
span.set_attribute(SERVICE_NAME,
|
706
324
|
application_name)
|
707
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
|
708
|
-
model)
|
709
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
|
710
|
-
str(getattr(instance, 'temperature',1)))
|
711
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
|
712
|
-
str(getattr(instance, 'top_k',1)))
|
713
|
-
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
|
714
|
-
str(getattr(instance, 'top_p',1)))
|
715
325
|
span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
|
716
326
|
False)
|
717
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_INPUT_TOKENS,
|
718
|
-
input_tokens)
|
719
|
-
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_OUTPUT_TOKENS,
|
720
|
-
output_tokens)
|
721
327
|
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
|
722
328
|
input_tokens + output_tokens)
|
723
329
|
span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
|
724
330
|
cost)
|
725
|
-
|
331
|
+
span.set_attribute(SemanticConvetion.GEN_AI_SERVER_TTFT,
|
332
|
+
end_time - start_time)
|
333
|
+
span.set_attribute(SemanticConvetion.GEN_AI_SDK_VERSION,
|
334
|
+
version)
|
335
|
+
|
336
|
+
if capture_message_content:
|
726
337
|
span.add_event(
|
727
338
|
name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
|
728
339
|
attributes={
|
@@ -732,32 +343,34 @@ def achat(gen_ai_endpoint, version, environment, application_name,
|
|
732
343
|
span.add_event(
|
733
344
|
name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
|
734
345
|
attributes={
|
735
|
-
SemanticConvetion.GEN_AI_CONTENT_COMPLETION:
|
346
|
+
SemanticConvetion.GEN_AI_CONTENT_COMPLETION: llm_response,
|
736
347
|
},
|
737
348
|
)
|
738
349
|
|
739
350
|
span.set_status(Status(StatusCode.OK))
|
740
351
|
|
741
352
|
if disable_metrics is False:
|
742
|
-
attributes =
|
743
|
-
|
744
|
-
|
745
|
-
SemanticConvetion.
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT,
|
753
|
-
SemanticConvetion.GEN_AI_REQUEST_MODEL:
|
754
|
-
model
|
755
|
-
}
|
353
|
+
attributes = create_metrics_attributes(
|
354
|
+
service_name=application_name,
|
355
|
+
deployment_environment=environment,
|
356
|
+
operation=SemanticConvetion.GEN_AI_OPERATION_TYPE_CHAT,
|
357
|
+
system=SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
|
358
|
+
request_model=request_model,
|
359
|
+
server_address=server_address,
|
360
|
+
server_port=server_port,
|
361
|
+
response_model=request_model,
|
362
|
+
)
|
756
363
|
|
757
|
-
metrics["
|
758
|
-
metrics["genai_total_tokens"].add(
|
364
|
+
metrics["genai_client_usage_tokens"].record(
|
759
365
|
input_tokens + output_tokens, attributes
|
760
366
|
)
|
367
|
+
metrics["genai_client_operation_duration"].record(
|
368
|
+
end_time - start_time, attributes
|
369
|
+
)
|
370
|
+
metrics["genai_server_ttft"].record(
|
371
|
+
end_time - start_time, attributes
|
372
|
+
)
|
373
|
+
metrics["genai_requests"].add(1, attributes)
|
761
374
|
metrics["genai_completion_tokens"].add(output_tokens, attributes)
|
762
375
|
metrics["genai_prompt_tokens"].add(input_tokens, attributes)
|
763
376
|
metrics["genai_cost"].record(cost, attributes)
|