openlit 1.18.1__py3-none-any.whl → 1.19.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.
@@ -5,7 +5,14 @@ import importlib.metadata
5
5
  from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
6
6
  from wrapt import wrap_function_wrapper
7
7
 
8
- from openlit.instrumentation.langchain.langchain import general_wrap, hub, llm, allm
8
+ from openlit.instrumentation.langchain.langchain import (
9
+ general_wrap,
10
+ hub,
11
+ llm,
12
+ allm,
13
+ chat,
14
+ achat
15
+ )
9
16
 
10
17
  _instruments = ("langchain >= 0.1.20",)
11
18
 
@@ -52,6 +59,18 @@ WRAPPED_METHODS = [
52
59
  "endpoint": "langchain.llm",
53
60
  "wrapper": allm,
54
61
  },
62
+ {
63
+ "package": "langchain_core.language_models.chat_models",
64
+ "object": "BaseChatModel.invoke",
65
+ "endpoint": "langchain.chat_models",
66
+ "wrapper": chat,
67
+ },
68
+ {
69
+ "package": "langchain_core.language_models.chat_models",
70
+ "object": "BaseChatModel.ainvoke",
71
+ "endpoint": "langchain.chat_models",
72
+ "wrapper": achat,
73
+ },
55
74
  ]
56
75
 
57
76
  class LangChainInstrumentor(BaseInstrumentor):
@@ -66,6 +85,8 @@ class LangChainInstrumentor(BaseInstrumentor):
66
85
  tracer = kwargs.get("tracer")
67
86
  pricing_info = kwargs.get("pricing_info")
68
87
  trace_content = kwargs.get("trace_content")
88
+ metrics = kwargs.get("metrics_dict")
89
+ disable_metrics = kwargs.get("disable_metrics")
69
90
  version = importlib.metadata.version("langchain")
70
91
 
71
92
  for wrapped_method in WRAPPED_METHODS:
@@ -77,7 +98,7 @@ class LangChainInstrumentor(BaseInstrumentor):
77
98
  wrap_package,
78
99
  wrap_object,
79
100
  wrapper(gen_ai_endpoint, version, environment, application_name,
80
- tracer, pricing_info, trace_content),
101
+ tracer, pricing_info, trace_content, metrics, disable_metrics),
81
102
  )
82
103
 
83
104
  @staticmethod
@@ -1,4 +1,4 @@
1
- # pylint: disable=duplicate-code, broad-exception-caught, too-many-statements, unused-argument
1
+ # pylint: disable=duplicate-code, broad-exception-caught, too-many-statements, unused-argument, unused-import
2
2
  """
3
3
  Module for monitoring Langchain applications.
4
4
  """
@@ -6,14 +6,14 @@ Module for monitoring Langchain applications.
6
6
  import logging
7
7
  from opentelemetry.trace import SpanKind, Status, StatusCode
8
8
  from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
9
- from openlit.__helpers import handle_exception
9
+ from openlit.__helpers import handle_exception, get_chat_model_cost, general_tokens
10
10
  from openlit.semcov import SemanticConvetion
11
11
 
12
12
  # Initialize logger for logging potential issues and operations
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
15
  def general_wrap(gen_ai_endpoint, version, environment, application_name,
16
- tracer, pricing_info, trace_content):
16
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
17
17
  """
18
18
  Creates a wrapper around a function call to trace and log its execution metrics.
19
19
 
@@ -86,7 +86,7 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
86
86
  return wrapper
87
87
 
88
88
  def hub(gen_ai_endpoint, version, environment, application_name, tracer,
89
- pricing_info, trace_content):
89
+ pricing_info, trace_content, metrics, disable_metrics):
90
90
  """
91
91
  Creates a wrapper around Langchain hub operations for tracing and logging.
92
92
 
@@ -162,7 +162,7 @@ def hub(gen_ai_endpoint, version, environment, application_name, tracer,
162
162
 
163
163
 
164
164
  def allm(gen_ai_endpoint, version, environment, application_name,
165
- tracer, pricing_info, trace_content):
165
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
166
166
  """
167
167
  Creates a wrapper around a function call to trace and log its execution metrics.
168
168
 
@@ -207,6 +207,16 @@ def allm(gen_ai_endpoint, version, environment, application_name,
207
207
  response = await wrapped(*args, **kwargs)
208
208
 
209
209
  try:
210
+ prompt = args[0] or ""
211
+ # input_tokens = general_tokens(prompt)
212
+ # output_tokens = general_tokens(response)
213
+
214
+ # # Calculate cost of the operation
215
+ # cost = get_chat_model_cost(
216
+ # str(getattr(instance, 'model')),
217
+ # pricing_info, input_tokens, output_tokens
218
+ # )
219
+
210
220
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
211
221
  span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
212
222
  SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
@@ -226,13 +236,56 @@ def allm(gen_ai_endpoint, version, environment, application_name,
226
236
  str(getattr(instance, 'top_k')))
227
237
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
228
238
  str(getattr(instance, 'top_p')))
239
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
240
+ False)
241
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
242
+ # input_tokens)
243
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
244
+ # output_tokens)
245
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
246
+ # input_tokens + output_tokens)
247
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
248
+ # cost)
229
249
  if trace_content:
230
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
231
- args[0])
232
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
233
- response)
250
+ span.add_event(
251
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
252
+ attributes={
253
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
254
+ },
255
+ )
256
+ span.add_event(
257
+ name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
258
+ attributes={
259
+ SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response,
260
+ },
261
+ )
262
+
234
263
  span.set_status(Status(StatusCode.OK))
235
264
 
265
+ # if disable_metrics is False:
266
+ # attributes = {
267
+ # TELEMETRY_SDK_NAME:
268
+ # "openlit",
269
+ # SemanticConvetion.GEN_AI_APPLICATION_NAME:
270
+ # application_name,
271
+ # SemanticConvetion.GEN_AI_SYSTEM:
272
+ # SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
273
+ # SemanticConvetion.GEN_AI_ENVIRONMENT:
274
+ # environment,
275
+ # SemanticConvetion.GEN_AI_TYPE:
276
+ # SemanticConvetion.GEN_AI_TYPE_CHAT,
277
+ # SemanticConvetion.GEN_AI_REQUEST_MODEL:
278
+ # str(getattr(instance, 'model'))
279
+ # }
280
+
281
+ # metrics["genai_requests"].add(1, attributes)
282
+ # metrics["genai_total_tokens"].add(
283
+ # input_tokens + output_tokens, attributes
284
+ # )
285
+ # metrics["genai_completion_tokens"].add(output_tokens, attributes)
286
+ # metrics["genai_prompt_tokens"].add(input_tokens, attributes)
287
+ # metrics["genai_cost"].record(cost, attributes)
288
+
236
289
  # Return original response
237
290
  return response
238
291
 
@@ -246,7 +299,7 @@ def allm(gen_ai_endpoint, version, environment, application_name,
246
299
  return wrapper
247
300
 
248
301
  def llm(gen_ai_endpoint, version, environment, application_name,
249
- tracer, pricing_info, trace_content):
302
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
250
303
  """
251
304
  Creates a wrapper around a function call to trace and log its execution metrics.
252
305
 
@@ -291,6 +344,16 @@ def llm(gen_ai_endpoint, version, environment, application_name,
291
344
  response = wrapped(*args, **kwargs)
292
345
 
293
346
  try:
347
+ prompt = args[0] or ""
348
+ # input_tokens = general_tokens(prompt)
349
+ # output_tokens = general_tokens(response)
350
+
351
+ # # Calculate cost of the operation
352
+ # cost = get_chat_model_cost(
353
+ # str(getattr(instance, 'model')),
354
+ # pricing_info, input_tokens, output_tokens
355
+ # )
356
+
294
357
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
295
358
  span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
296
359
  SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
@@ -310,13 +373,332 @@ def llm(gen_ai_endpoint, version, environment, application_name,
310
373
  str(getattr(instance, 'top_k')))
311
374
  span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
312
375
  str(getattr(instance, 'top_p')))
376
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
377
+ False)
378
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
379
+ # input_tokens)
380
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
381
+ # output_tokens)
382
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
383
+ # input_tokens + output_tokens)
384
+ # span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
385
+ # cost)
386
+ if trace_content:
387
+ span.add_event(
388
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
389
+ attributes={
390
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
391
+ },
392
+ )
393
+ span.add_event(
394
+ name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
395
+ attributes={
396
+ SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response,
397
+ },
398
+ )
399
+
400
+ span.set_status(Status(StatusCode.OK))
401
+
402
+ # if disable_metrics is False:
403
+ # attributes = {
404
+ # TELEMETRY_SDK_NAME:
405
+ # "openlit",
406
+ # SemanticConvetion.GEN_AI_APPLICATION_NAME:
407
+ # application_name,
408
+ # SemanticConvetion.GEN_AI_SYSTEM:
409
+ # SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
410
+ # SemanticConvetion.GEN_AI_ENVIRONMENT:
411
+ # environment,
412
+ # SemanticConvetion.GEN_AI_TYPE:
413
+ # SemanticConvetion.GEN_AI_TYPE_CHAT,
414
+ # SemanticConvetion.GEN_AI_REQUEST_MODEL:
415
+ # str(getattr(instance, 'model'))
416
+ # }
417
+
418
+ # metrics["genai_requests"].add(1, attributes)
419
+ # metrics["genai_total_tokens"].add(
420
+ # input_tokens + output_tokens, attributes
421
+ # )
422
+ # metrics["genai_completion_tokens"].add(output_tokens, attributes)
423
+ # metrics["genai_prompt_tokens"].add(input_tokens, attributes)
424
+ # metrics["genai_cost"].record(cost, attributes)
425
+
426
+ # Return original response
427
+ return response
428
+
429
+ except Exception as e:
430
+ handle_exception(span, e)
431
+ logger.error("Error in trace creation: %s", e)
432
+
433
+ # Return original response
434
+ return response
435
+
436
+ return wrapper
437
+
438
+ def chat(gen_ai_endpoint, version, environment, application_name,
439
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
440
+ """
441
+ Creates a wrapper around a function call to trace and log its execution metrics.
442
+
443
+ This function wraps any given function to measure its execution time,
444
+ log its operation, and trace its execution using OpenTelemetry.
445
+
446
+ Parameters:
447
+ - gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
448
+ - version (str): The version of the Langchain application.
449
+ - environment (str): The deployment environment (e.g., 'production', 'development').
450
+ - application_name (str): Name of the Langchain application.
451
+ - tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
452
+ - pricing_info (dict): Information about the pricing for internal metrics (currently not used).
453
+ - trace_content (bool): Flag indicating whether to trace the content of the response.
454
+
455
+ Returns:
456
+ - function: A higher-order function that takes a function 'wrapped' and returns
457
+ a new function that wraps 'wrapped' with additional tracing and logging.
458
+ """
459
+
460
+ def wrapper(wrapped, instance, args, kwargs):
461
+ """
462
+ An inner wrapper function that executes the wrapped function, measures execution
463
+ time, and records trace data using OpenTelemetry.
464
+
465
+ Parameters:
466
+ - wrapped (Callable): The original function that this wrapper will execute.
467
+ - instance (object): The instance to which the wrapped function belongs. This
468
+ is used for instance methods. For static and classmethods,
469
+ this may be None.
470
+ - args (tuple): Positional arguments passed to the wrapped function.
471
+ - kwargs (dict): Keyword arguments passed to the wrapped function.
472
+
473
+ Returns:
474
+ - The result of the wrapped function call.
475
+
476
+ The wrapper initiates a span with the provided tracer, sets various attributes
477
+ on the span based on the function's execution and response, and ensures
478
+ errors are handled and logged appropriately.
479
+ """
480
+ with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
481
+ response = wrapped(*args, **kwargs)
482
+
483
+ try:
484
+ input_tokens = response.response_metadata["prompt_eval_count"] or 0
485
+ output_tokens = response.response_metadata["eval_count"] or 0
486
+
487
+ # Calculate cost of the operation
488
+ cost = get_chat_model_cost(
489
+ str(getattr(instance, 'model')),
490
+ pricing_info, input_tokens, output_tokens
491
+ )
492
+
493
+ span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
494
+ span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
495
+ SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
496
+ span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
497
+ gen_ai_endpoint)
498
+ span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
499
+ environment)
500
+ span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
501
+ SemanticConvetion.GEN_AI_TYPE_CHAT)
502
+ span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
503
+ application_name)
504
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
505
+ str(getattr(instance, 'model')))
506
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
507
+ str(getattr(instance, 'temperature')))
508
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
509
+ str(getattr(instance, 'top_k')))
510
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
511
+ str(getattr(instance, 'top_p')))
512
+ span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
513
+ [response.response_metadata["done_reason"]])
514
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
515
+ False)
516
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
517
+ input_tokens)
518
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
519
+ output_tokens)
520
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
521
+ input_tokens + output_tokens)
522
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
523
+ cost)
313
524
  if trace_content:
314
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_PROMPT,
315
- args[0])
316
- span.set_attribute(SemanticConvetion.GEN_AI_CONTENT_COMPLETION,
317
- response)
525
+ span.add_event(
526
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
527
+ attributes={
528
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: args[0],
529
+ },
530
+ )
531
+ span.add_event(
532
+ name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
533
+ attributes={
534
+ SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response.content,
535
+ },
536
+ )
537
+
318
538
  span.set_status(Status(StatusCode.OK))
319
539
 
540
+ if disable_metrics is False:
541
+ attributes = {
542
+ TELEMETRY_SDK_NAME:
543
+ "openlit",
544
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
545
+ application_name,
546
+ SemanticConvetion.GEN_AI_SYSTEM:
547
+ SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
548
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
549
+ environment,
550
+ SemanticConvetion.GEN_AI_TYPE:
551
+ SemanticConvetion.GEN_AI_TYPE_CHAT,
552
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
553
+ str(getattr(instance, 'model'))
554
+ }
555
+
556
+ metrics["genai_requests"].add(1, attributes)
557
+ metrics["genai_total_tokens"].add(
558
+ input_tokens + output_tokens, attributes
559
+ )
560
+ metrics["genai_completion_tokens"].add(output_tokens, attributes)
561
+ metrics["genai_prompt_tokens"].add(input_tokens, attributes)
562
+ metrics["genai_cost"].record(cost, attributes)
563
+
564
+ # Return original response
565
+ return response
566
+
567
+ except Exception as e:
568
+ handle_exception(span, e)
569
+ logger.error("Error in trace creation: %s", e)
570
+
571
+ # Return original response
572
+ return response
573
+
574
+ return wrapper
575
+
576
+ def achat(gen_ai_endpoint, version, environment, application_name,
577
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
578
+ """
579
+ Creates a wrapper around a function call to trace and log its execution metrics.
580
+
581
+ This function wraps any given function to measure its execution time,
582
+ log its operation, and trace its execution using OpenTelemetry.
583
+
584
+ Parameters:
585
+ - gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
586
+ - version (str): The version of the Langchain application.
587
+ - environment (str): The deployment environment (e.g., 'production', 'development').
588
+ - application_name (str): Name of the Langchain application.
589
+ - tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
590
+ - pricing_info (dict): Information about the pricing for internal metrics (currently not used).
591
+ - trace_content (bool): Flag indicating whether to trace the content of the response.
592
+
593
+ Returns:
594
+ - function: A higher-order function that takes a function 'wrapped' and returns
595
+ a new function that wraps 'wrapped' with additional tracing and logging.
596
+ """
597
+
598
+ async def wrapper(wrapped, instance, args, kwargs):
599
+ """
600
+ An inner wrapper function that executes the wrapped function, measures execution
601
+ time, and records trace data using OpenTelemetry.
602
+
603
+ Parameters:
604
+ - wrapped (Callable): The original function that this wrapper will execute.
605
+ - instance (object): The instance to which the wrapped function belongs. This
606
+ is used for instance methods. For static and classmethods,
607
+ this may be None.
608
+ - args (tuple): Positional arguments passed to the wrapped function.
609
+ - kwargs (dict): Keyword arguments passed to the wrapped function.
610
+
611
+ Returns:
612
+ - The result of the wrapped function call.
613
+
614
+ The wrapper initiates a span with the provided tracer, sets various attributes
615
+ on the span based on the function's execution and response, and ensures
616
+ errors are handled and logged appropriately.
617
+ """
618
+ with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
619
+ response = await wrapped(*args, **kwargs)
620
+
621
+ try:
622
+ input_tokens = response.response_metadata["prompt_eval_count"] or 0
623
+ output_tokens = response.response_metadata["eval_count"] or 0
624
+
625
+ # Calculate cost of the operation
626
+ cost = get_chat_model_cost(
627
+ str(getattr(instance, 'model')),
628
+ pricing_info, input_tokens, output_tokens
629
+ )
630
+
631
+ span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
632
+ span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
633
+ SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN)
634
+ span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
635
+ gen_ai_endpoint)
636
+ span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
637
+ environment)
638
+ span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
639
+ SemanticConvetion.GEN_AI_TYPE_CHAT)
640
+ span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
641
+ application_name)
642
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
643
+ str(getattr(instance, 'model')))
644
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
645
+ str(getattr(instance, 'temperature')))
646
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_K,
647
+ str(getattr(instance, 'top_k')))
648
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
649
+ str(getattr(instance, 'top_p')))
650
+ span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_FINISH_REASON,
651
+ [response.response_metadata["done_reason"]])
652
+ span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
653
+ False)
654
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
655
+ input_tokens)
656
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
657
+ output_tokens)
658
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
659
+ input_tokens + output_tokens)
660
+ span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
661
+ cost)
662
+ if trace_content:
663
+ span.add_event(
664
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
665
+ attributes={
666
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: args[0],
667
+ },
668
+ )
669
+ span.add_event(
670
+ name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
671
+ attributes={
672
+ SemanticConvetion.GEN_AI_CONTENT_COMPLETION: response.content,
673
+ },
674
+ )
675
+
676
+ span.set_status(Status(StatusCode.OK))
677
+
678
+ if disable_metrics is False:
679
+ attributes = {
680
+ TELEMETRY_SDK_NAME:
681
+ "openlit",
682
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
683
+ application_name,
684
+ SemanticConvetion.GEN_AI_SYSTEM:
685
+ SemanticConvetion.GEN_AI_SYSTEM_LANGCHAIN,
686
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
687
+ environment,
688
+ SemanticConvetion.GEN_AI_TYPE:
689
+ SemanticConvetion.GEN_AI_TYPE_CHAT,
690
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
691
+ str(getattr(instance, 'model'))
692
+ }
693
+
694
+ metrics["genai_requests"].add(1, attributes)
695
+ metrics["genai_total_tokens"].add(
696
+ input_tokens + output_tokens, attributes
697
+ )
698
+ metrics["genai_completion_tokens"].add(output_tokens, attributes)
699
+ metrics["genai_prompt_tokens"].add(input_tokens, attributes)
700
+ metrics["genai_cost"].record(cost, attributes)
701
+
320
702
  # Return original response
321
703
  return response
322
704
 
@@ -9,10 +9,10 @@ from openlit.instrumentation.mistral.mistral import chat, chat_stream, embedding
9
9
  from openlit.instrumentation.mistral.async_mistral import async_chat, async_chat_stream
10
10
  from openlit.instrumentation.mistral.async_mistral import async_embeddings
11
11
 
12
- _instruments = ("mistralai >= 0.1.0",)
12
+ _instruments = ("mistralai >= 1.0.0",)
13
13
 
14
14
  class MistralInstrumentor(BaseInstrumentor):
15
- """An instrumentor for Azure Mistral's client library."""
15
+ """An instrumentor for Mistral's client library."""
16
16
 
17
17
  def instrumentation_dependencies(self) -> Collection[str]:
18
18
  return _instruments
@@ -27,50 +27,50 @@ class MistralInstrumentor(BaseInstrumentor):
27
27
  disable_metrics = kwargs.get("disable_metrics")
28
28
  version = importlib.metadata.version("mistralai")
29
29
 
30
- #sync
30
+ # sync
31
31
  wrap_function_wrapper(
32
- "mistralai.client",
33
- "MistralClient.chat",
32
+ "mistralai.chat",
33
+ "Chat.complete",
34
34
  chat("mistral.chat", version, environment, application_name,
35
35
  tracer, pricing_info, trace_content, metrics, disable_metrics),
36
36
  )
37
37
 
38
- #sync
38
+ # sync
39
39
  wrap_function_wrapper(
40
- "mistralai.client",
41
- "MistralClient.chat_stream",
40
+ "mistralai.chat",
41
+ "Chat.stream",
42
42
  chat_stream("mistral.chat", version, environment, application_name,
43
43
  tracer, pricing_info, trace_content, metrics, disable_metrics),
44
44
  )
45
45
 
46
- #sync
46
+ # sync
47
47
  wrap_function_wrapper(
48
- "mistralai.client",
49
- "MistralClient.embeddings",
48
+ "mistralai.embeddings",
49
+ "Embeddings.create",
50
50
  embeddings("mistral.embeddings", version, environment, application_name,
51
51
  tracer, pricing_info, trace_content, metrics, disable_metrics),
52
52
  )
53
53
 
54
54
  # Async
55
55
  wrap_function_wrapper(
56
- "mistralai.async_client",
57
- "MistralAsyncClient.chat",
56
+ "mistralai.chat",
57
+ "Chat.complete_async",
58
58
  async_chat("mistral.chat", version, environment, application_name,
59
59
  tracer, pricing_info, trace_content, metrics, disable_metrics),
60
60
  )
61
61
 
62
- #sync
62
+ # Async
63
63
  wrap_function_wrapper(
64
- "mistralai.async_client",
65
- "MistralAsyncClient.chat_stream",
64
+ "mistralai.chat",
65
+ "Chat.stream_async",
66
66
  async_chat_stream("mistral.chat", version, environment, application_name,
67
67
  tracer, pricing_info, trace_content, metrics, disable_metrics),
68
68
  )
69
69
 
70
70
  #sync
71
71
  wrap_function_wrapper(
72
- "mistralai.async_client",
73
- "MistralAsyncClient.embeddings",
72
+ "mistralai.embeddings",
73
+ "Embeddings.create_async",
74
74
  async_embeddings("mistral.embeddings", version, environment, application_name,
75
75
  tracer, pricing_info, trace_content, metrics, disable_metrics),
76
76
  )
@@ -56,8 +56,8 @@ def async_chat(gen_ai_endpoint, version, environment, application_name,
56
56
  message_prompt = kwargs.get('messages', "")
57
57
  formatted_messages = []
58
58
  for message in message_prompt:
59
- role = message.role
60
- content = message.content
59
+ role = message["role"]
60
+ content = message["content"]
61
61
 
62
62
  if isinstance(content, list):
63
63
  content_str = ", ".join(
@@ -207,14 +207,14 @@ def async_chat_stream(gen_ai_endpoint, version, environment, application_name,
207
207
  llmresponse = ""
208
208
 
209
209
  # Loop through streaming events capturing relevant details
210
- async for event in wrapped(*args, **kwargs):
211
- response_id = event.id
212
- llmresponse += event.choices[0].delta.content
213
- if event.usage is not None:
214
- prompt_tokens = event.usage.prompt_tokens
215
- completion_tokens = event.usage.completion_tokens
216
- total_tokens = event.usage.total_tokens
217
- finish_reason = event.choices[0].finish_reason
210
+ async for event in await wrapped(*args, **kwargs):
211
+ response_id = event.data.id
212
+ llmresponse += event.data.choices[0].delta.content
213
+ if event.data.usage is not None:
214
+ prompt_tokens = event.data.usage.prompt_tokens
215
+ completion_tokens = event.data.usage.completion_tokens
216
+ total_tokens = event.data.usage.total_tokens
217
+ finish_reason = event.data.choices[0].finish_reason
218
218
  yield event
219
219
 
220
220
  # Handling exception ensure observability without disrupting operation
@@ -223,8 +223,8 @@ def async_chat_stream(gen_ai_endpoint, version, environment, application_name,
223
223
  message_prompt = kwargs.get('messages', "")
224
224
  formatted_messages = []
225
225
  for message in message_prompt:
226
- role = message.role
227
- content = message.content
226
+ role = message["role"]
227
+ content = message["content"]
228
228
 
229
229
  if isinstance(content, list):
230
230
  content_str = ", ".join(
@@ -364,7 +364,7 @@ def async_embeddings(gen_ai_endpoint, version, environment, application_name,
364
364
 
365
365
  try:
366
366
  # Get prompt from kwargs and store as a single string
367
- prompt = ', '.join(kwargs.get('input', []))
367
+ prompt = ', '.join(kwargs.get('inputs', []))
368
368
 
369
369
  # Calculate cost of the operation
370
370
  cost = get_embed_model_cost(kwargs.get('model', "mistral-embed"),
@@ -55,8 +55,8 @@ def chat(gen_ai_endpoint, version, environment, application_name,
55
55
  message_prompt = kwargs.get('messages', "")
56
56
  formatted_messages = []
57
57
  for message in message_prompt:
58
- role = message.role
59
- content = message.content
58
+ role = message["role"]
59
+ content = message["content"]
60
60
 
61
61
  if isinstance(content, list):
62
62
  content_str = ", ".join(
@@ -207,13 +207,13 @@ def chat_stream(gen_ai_endpoint, version, environment, application_name,
207
207
 
208
208
  # Loop through streaming events capturing relevant details
209
209
  for event in wrapped(*args, **kwargs):
210
- response_id = event.id
211
- llmresponse += event.choices[0].delta.content
212
- if event.usage is not None:
213
- prompt_tokens = event.usage.prompt_tokens
214
- completion_tokens = event.usage.completion_tokens
215
- total_tokens = event.usage.total_tokens
216
- finish_reason = event.choices[0].finish_reason
210
+ response_id = event.data.id
211
+ llmresponse += event.data.choices[0].delta.content
212
+ if event.data.usage is not None:
213
+ prompt_tokens = event.data.usage.prompt_tokens
214
+ completion_tokens = event.data.usage.completion_tokens
215
+ total_tokens = event.data.usage.total_tokens
216
+ finish_reason = event.data.choices[0].finish_reason
217
217
  yield event
218
218
 
219
219
  # Handling exception ensure observability without disrupting operation
@@ -222,8 +222,8 @@ def chat_stream(gen_ai_endpoint, version, environment, application_name,
222
222
  message_prompt = kwargs.get('messages', "")
223
223
  formatted_messages = []
224
224
  for message in message_prompt:
225
- role = message.role
226
- content = message.content
225
+ role = message["role"]
226
+ content = message["content"]
227
227
 
228
228
  if isinstance(content, list):
229
229
  content_str = ", ".join(
@@ -363,7 +363,7 @@ def embeddings(gen_ai_endpoint, version, environment, application_name,
363
363
 
364
364
  try:
365
365
  # Get prompt from kwargs and store as a single string
366
- prompt = ', '.join(kwargs.get('input', []))
366
+ prompt = ', '.join(kwargs.get('inputs', []))
367
367
 
368
368
  # Calculate cost of the operation
369
369
  cost = get_embed_model_cost(kwargs.get('model', "mistral-embed"),
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openlit
3
- Version: 1.18.1
4
- Summary: OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications, facilitating the integration of observability into your GenAI-driven projects
3
+ Version: 1.19.0
4
+ Summary: OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications and GPUs, facilitating the integration of observability into your GenAI-driven projects
5
5
  Home-page: https://github.com/openlit/openlit/tree/main/openlit/python
6
- Keywords: OpenTelemetry,otel,otlp,llm,tracing,openai,anthropic,claude,cohere,llm monitoring,observability,monitoring,gpt,Generative AI,chatGPT
6
+ Keywords: OpenTelemetry,otel,otlp,llm,tracing,openai,anthropic,claude,cohere,llm monitoring,observability,monitoring,gpt,Generative AI,chatGPT,gpu
7
7
  Author: OpenLIT
8
8
  Requires-Python: >=3.7.1,<4.0.0
9
9
  Classifier: Programming Language :: Python :: 3
@@ -61,14 +61,15 @@ This project adheres to the [Semantic Conventions](https://github.com/open-telem
61
61
  | [✅ Anthropic](https://docs.openlit.io/latest/integrations/anthropic) | [✅ Qdrant](https://docs.openlit.io/latest/integrations/qdrant) | [✅ LlamaIndex](https://docs.openlit.io/latest/integrations/llama-index) | |
62
62
  | [✅ GPT4All](https://docs.openlit.io/latest/integrations/gpt4all) | [✅ Milvus](https://docs.openlit.io/latest/integrations/milvus) | [✅ Haystack](https://docs.openlit.io/latest/integrations/haystack) | |
63
63
  | [✅ Cohere](https://docs.openlit.io/latest/integrations/cohere) | | [✅ EmbedChain](https://docs.openlit.io/latest/integrations/embedchain) | |
64
- | [✅ Mistral](https://docs.openlit.io/latest/integrations/mistral) | | | |
65
- | [✅ Azure OpenAI](https://docs.openlit.io/latest/integrations/azure-openai) | | | |
66
- | [✅ HuggingFace Transformers](https://docs.openlit.io/latest/integrations/huggingface) | | | |
67
- | [✅ Amazon Bedrock](https://docs.openlit.io/latest/integrations/bedrock) | | | |
64
+ | [✅ Mistral](https://docs.openlit.io/latest/integrations/mistral) | | [✅ Guardrails](https://docs.openlit.io/latest/integrations/guardrails) | |
65
+ | [✅ Azure OpenAI](https://docs.openlit.io/latest/integrations/azure-openai) | | | |
66
+ | [✅ HuggingFace Transformers](https://docs.openlit.io/latest/integrations/huggingface) | | | |
67
+ | [✅ Amazon Bedrock](https://docs.openlit.io/latest/integrations/bedrock) | | | |
68
68
  | [✅ Vertex AI](https://docs.openlit.io/latest/integrations/vertexai) | | | |
69
69
  | [✅ Groq](https://docs.openlit.io/latest/integrations/groq) | | | |
70
70
  | [✅ ElevenLabs](https://docs.openlit.io/latest/integrations/elevenlabs) | | | |
71
71
  | [✅ vLLM](https://docs.openlit.io/latest/integrations/vllm) | | | |
72
+ | [✅ OLA Krutrim](https://docs.openlit.io/latest/integrations/krutrim) | | | |
72
73
 
73
74
  ## Supported Destinations
74
75
  - [✅ OpenTelemetry Collector](https://docs.openlit.io/latest/connections/otelcol)
@@ -77,8 +78,10 @@ This project adheres to the [Semantic Conventions](https://github.com/open-telem
77
78
  - [✅ Grafana Cloud](https://docs.openlit.io/latest/connections/grafanacloud)
78
79
  - [✅ New Relic](https://docs.openlit.io/latest/connections/new-relic)
79
80
  - [✅ Elastic](https://docs.openlit.io/latest/connections/elastic)
81
+ - [✅ HyperDX](https://docs.openlit.io/latest/connections/hyperdx)
80
82
  - [✅ DataDog](https://docs.openlit.io/latest/connections/datadog)
81
83
  - [✅ SigNoz](https://docs.openlit.io/latest/connections/signoz)
84
+ - [✅ OneUptime](https://docs.openlit.io/latest/connections/oneuptime)
82
85
  - [✅ Dynatrace](https://docs.openlit.io/latest/connections/dynatrace)
83
86
  - [✅ OpenObserve](https://docs.openlit.io/latest/connections/openobserve)
84
87
  - [✅ Highlight.io](https://docs.openlit.io/latest/connections/highlight)
@@ -22,15 +22,15 @@ openlit/instrumentation/groq/async_groq.py,sha256=myob-d9V66YiNmkFd9rtmMaXjlLiSM
22
22
  openlit/instrumentation/groq/groq.py,sha256=m4gFPbYzjUUIgjXZ0Alu2Zy1HcO5takCFA2XFnkcGVo,19975
23
23
  openlit/instrumentation/haystack/__init__.py,sha256=QK6XxxZUHX8vMv2Crk7rNBOc64iOOBLhJGL_lPlAZ8s,1758
24
24
  openlit/instrumentation/haystack/haystack.py,sha256=oQIZiDhdp3gnJnhYQ1OouJMc9YT0pQ-_31cmNuopa68,3891
25
- openlit/instrumentation/langchain/__init__.py,sha256=19C7YGSF-6u5VlvKkThNS4zZqvxw-fQfRsKufZ9onfk,2881
26
- openlit/instrumentation/langchain/langchain.py,sha256=xGiRb3Z_fY1PU09hfSBFt6ipfYJIQrwFFm5HEDaawOY,16243
25
+ openlit/instrumentation/langchain/__init__.py,sha256=0AI2Dnqw81IcJw3jM--gGkv_HRh2GtosOGJjvOpw7Zk,3431
26
+ openlit/instrumentation/langchain/langchain.py,sha256=7K-m35sS3yTu9IklRo6n9LCcymeg6OyIYKrMzMG_uDQ,35730
27
27
  openlit/instrumentation/llamaindex/__init__.py,sha256=vPtK65G6b-TwJERowVRUVl7f_nBSlFdwPBtpg8dOGos,1977
28
28
  openlit/instrumentation/llamaindex/llamaindex.py,sha256=uiIigbwhonSbJWA7LpgOVI1R4kxxPODS1K5wyHIQ4hM,4048
29
29
  openlit/instrumentation/milvus/__init__.py,sha256=qi1yfmMrvkDtnrN_6toW8qC9BRL78bq7ayWpObJ8Bq4,2961
30
30
  openlit/instrumentation/milvus/milvus.py,sha256=qhKIoggBAJhRctRrBYz69AcvXH-eh7oBn_l9WfxpAjI,9121
31
- openlit/instrumentation/mistral/__init__.py,sha256=zJCIpFWRbsYrvooOJYuqwyuKeSOQLWbyXWCObL-Snks,3156
32
- openlit/instrumentation/mistral/async_mistral.py,sha256=WXU46nbe61IglfGehrwdprMVB6hNiuqqmJHE3XvvP0E,22192
33
- openlit/instrumentation/mistral/mistral.py,sha256=DC-wLIypokPEEAbVSKX5sytv94DY2QDnk12401e5vq8,22039
31
+ openlit/instrumentation/mistral/__init__.py,sha256=niWn0gYNOTPS5zoTjtCciDqQVj-iJehnpdh7ElB-H9w,3088
32
+ openlit/instrumentation/mistral/async_mistral.py,sha256=l-kcaGPrX3sqPH-RXWo6ope0Ui3nUvExNJ4KX9QgDMY,22246
33
+ openlit/instrumentation/mistral/mistral.py,sha256=Q7MMRvVFsM8o0_ebZ0EfnhGjs16SJSnmu-oE798gYMQ,22087
34
34
  openlit/instrumentation/ollama/__init__.py,sha256=cOax8PiypDuo_FC4WvDCYBRo7lH5nV9xU92h7k-eZbg,3812
35
35
  openlit/instrumentation/ollama/async_ollama.py,sha256=7lbikD-I9k8VL63idqj3VMEfiEKJmFNUPR8Xb6g2phQ,31366
36
36
  openlit/instrumentation/ollama/ollama.py,sha256=lBt1d3rFnF1tFbfdOccwjEafHnmTAUGsiOKSHku6Fkw,31277
@@ -53,7 +53,7 @@ openlit/instrumentation/vllm/vllm.py,sha256=lDzM7F5pgxvh8nKL0dcKB4TD0Mc9wXOWeXOs
53
53
  openlit/otel/metrics.py,sha256=O7NoaDz0bY19mqpE4-0PcKwEe-B-iJFRgOCaanAuZAc,4291
54
54
  openlit/otel/tracing.py,sha256=vL1ifMbARPBpqK--yXYsCM6y5dSu5LFIKqkhZXtYmUc,3712
55
55
  openlit/semcov/__init__.py,sha256=EvoNOKtc7UKwLZ3Gp0-B1zwmeTcAIbx8O7wvAw8wXP4,7498
56
- openlit-1.18.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
57
- openlit-1.18.1.dist-info/METADATA,sha256=l-nXpcuMqzXPGB-IiwqWhvkjq-pW4lsK_8Q5_rH3uoo,14334
58
- openlit-1.18.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
59
- openlit-1.18.1.dist-info/RECORD,,
56
+ openlit-1.19.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
57
+ openlit-1.19.0.dist-info/METADATA,sha256=7P2h2TmPkrD-DTeqa0qqaC_oiqp8LdcEZ-pjuVepCjY,14746
58
+ openlit-1.19.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
59
+ openlit-1.19.0.dist-info/RECORD,,