openlit 1.29.0__tar.gz → 1.29.3__tar.gz

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.
Files changed (78) hide show
  1. {openlit-1.29.0 → openlit-1.29.3}/PKG-INFO +1 -1
  2. {openlit-1.29.0 → openlit-1.29.3}/pyproject.toml +1 -1
  3. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/__init__.py +3 -1
  4. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/openai/async_openai.py +183 -144
  5. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/qdrant/__init__.py +141 -1
  6. openlit-1.29.0/src/openlit/instrumentation/qdrant/qdrant.py → openlit-1.29.3/src/openlit/instrumentation/qdrant/async_qdrant.py +12 -3
  7. openlit-1.29.3/src/openlit/instrumentation/qdrant/qdrant.py +274 -0
  8. {openlit-1.29.0 → openlit-1.29.3}/LICENSE +0 -0
  9. {openlit-1.29.0 → openlit-1.29.3}/README.md +0 -0
  10. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/__helpers.py +0 -0
  11. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/__init__.py +0 -0
  12. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/all.py +0 -0
  13. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/bias_detection.py +0 -0
  14. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/hallucination.py +0 -0
  15. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/toxicity.py +0 -0
  16. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/evals/utils.py +0 -0
  17. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/__init__.py +0 -0
  18. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/all.py +0 -0
  19. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/prompt_injection.py +0 -0
  20. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/restrict_topic.py +0 -0
  21. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/sensitive_topic.py +0 -0
  22. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/guard/utils.py +0 -0
  23. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/anthropic/__init__.py +0 -0
  24. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/anthropic/anthropic.py +0 -0
  25. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/anthropic/async_anthropic.py +0 -0
  26. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/azure_ai_inference/__init__.py +0 -0
  27. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +0 -0
  28. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +0 -0
  29. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/bedrock/__init__.py +0 -0
  30. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/bedrock/bedrock.py +0 -0
  31. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/chroma/__init__.py +0 -0
  32. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/chroma/chroma.py +0 -0
  33. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/cohere/__init__.py +0 -0
  34. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/cohere/cohere.py +0 -0
  35. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/elevenlabs/__init__.py +0 -0
  36. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/elevenlabs/async_elevenlabs.py +0 -0
  37. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/elevenlabs/elevenlabs.py +0 -0
  38. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/embedchain/__init__.py +0 -0
  39. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/embedchain/embedchain.py +0 -0
  40. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/google_ai_studio/__init__.py +0 -0
  41. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +0 -0
  42. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/google_ai_studio/google_ai_studio.py +0 -0
  43. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/gpt4all/__init__.py +0 -0
  44. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/gpt4all/gpt4all.py +0 -0
  45. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/gpu/__init__.py +0 -0
  46. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/groq/__init__.py +0 -0
  47. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/groq/async_groq.py +0 -0
  48. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/groq/groq.py +0 -0
  49. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/haystack/__init__.py +0 -0
  50. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/haystack/haystack.py +0 -0
  51. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/langchain/__init__.py +0 -0
  52. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/langchain/langchain.py +0 -0
  53. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/llamaindex/__init__.py +0 -0
  54. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/llamaindex/llamaindex.py +0 -0
  55. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/milvus/__init__.py +0 -0
  56. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/milvus/milvus.py +0 -0
  57. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/mistral/__init__.py +0 -0
  58. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/mistral/async_mistral.py +0 -0
  59. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/mistral/mistral.py +0 -0
  60. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/ollama/__init__.py +0 -0
  61. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/ollama/async_ollama.py +0 -0
  62. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/ollama/ollama.py +0 -0
  63. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/openai/__init__.py +0 -0
  64. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/openai/async_azure_openai.py +0 -0
  65. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/openai/azure_openai.py +0 -0
  66. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/openai/openai.py +0 -0
  67. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/pinecone/__init__.py +0 -0
  68. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/pinecone/pinecone.py +0 -0
  69. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/transformers/__init__.py +0 -0
  70. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/transformers/transformers.py +0 -0
  71. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/vertexai/__init__.py +0 -0
  72. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/vertexai/async_vertexai.py +0 -0
  73. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/vertexai/vertexai.py +0 -0
  74. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/vllm/__init__.py +0 -0
  75. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/instrumentation/vllm/vllm.py +0 -0
  76. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/otel/metrics.py +0 -0
  77. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/otel/tracing.py +0 -0
  78. {openlit-1.29.0 → openlit-1.29.3}/src/openlit/semcov/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: openlit
3
- Version: 1.29.0
3
+ Version: 1.29.3
4
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
6
  Keywords: OpenTelemetry,otel,otlp,llm,tracing,openai,anthropic,claude,cohere,llm monitoring,observability,monitoring,gpt,Generative AI,chatGPT,gpu
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "openlit"
3
- version = "1.29.0"
3
+ version = "1.29.3"
4
4
  description = "OpenTelemetry-native Auto instrumentation library for monitoring LLM Applications and GPUs, facilitating the integration of observability into your GenAI-driven projects"
5
5
  authors = ["OpenLIT"]
6
6
  repository = "https://github.com/openlit/openlit/tree/main/openlit/python"
@@ -350,7 +350,8 @@ def get_prompt(url=None, name=None, api_key=None, prompt_id=None,
350
350
  'version': version,
351
351
  'shouldCompile': should_compile,
352
352
  'variables': variables,
353
- 'metaProperties': meta_properties
353
+ 'metaProperties': meta_properties,
354
+ 'source': 'python-sdk'
354
355
  }
355
356
 
356
357
  # Remove None values from payload
@@ -401,6 +402,7 @@ def get_secrets(url=None, api_key=None, key=None, tags=None, should_set_env=None
401
402
  payload = {
402
403
  'key': key,
403
404
  'tags': tags,
405
+ 'source': 'python-sdk'
404
406
  }
405
407
 
406
408
  # Remove None values from payload
@@ -31,10 +31,179 @@ def async_chat_completions(gen_ai_endpoint, version, environment, application_na
31
31
  A function that wraps the chat completions method to add telemetry.
32
32
  """
33
33
 
34
+ class TracedAsyncStream:
35
+ """
36
+ Wrapper for streaming responses to collect metrics and trace data.
37
+ Wraps the 'openai.AsyncStream' response to collect message IDs and aggregated response.
38
+
39
+ This class implements the '__aiter__' and '__anext__' methods that
40
+ handle asynchronous streaming responses.
41
+
42
+ This class also implements '__aenter__' and '__aexit__' methods that
43
+ handle asynchronous context management protocol.
44
+ """
45
+ def __init__(
46
+ self,
47
+ wrapped,
48
+ span,
49
+ *args,
50
+ **kwargs,
51
+ ):
52
+ self.__wrapped__ = wrapped
53
+ self._span = span
54
+ # Placeholder for aggregating streaming response
55
+ self._llmresponse = ""
56
+ self._response_id = ""
57
+
58
+ self._args = args
59
+ self._kwargs = kwargs
60
+
61
+ async def __aenter__(self):
62
+ await self.__wrapped__.__aenter__()
63
+ return self
64
+
65
+ async def __aexit__(self, exc_type, exc_value, traceback):
66
+ await self.__wrapped__.__aexit__(exc_type, exc_value, traceback)
67
+
68
+ def __aiter__(self):
69
+ return self
70
+
71
+ async def __anext__(self):
72
+ try:
73
+ chunk = await self.__wrapped__.__anext__()
74
+ # Collect message IDs and aggregated response from events
75
+ if len(chunk.choices) > 0:
76
+ # pylint: disable=line-too-long
77
+ if hasattr(chunk.choices[0], "delta") and hasattr(chunk.choices[0].delta, "content"):
78
+ content = chunk.choices[0].delta.content
79
+ if content:
80
+ self._llmresponse += content
81
+ self._response_id = chunk.id
82
+ return chunk
83
+ except StopAsyncIteration:
84
+ # Handling exception ensure observability without disrupting operation
85
+ try:
86
+ # Format 'messages' into a single string
87
+ message_prompt = self._kwargs.get("messages", "")
88
+ formatted_messages = []
89
+ for message in message_prompt:
90
+ role = message["role"]
91
+ content = message["content"]
92
+
93
+ if isinstance(content, list):
94
+ content_str = ", ".join(
95
+ # pylint: disable=line-too-long
96
+ f'{item["type"]}: {item["text"] if "text" in item else item["image_url"]}'
97
+ if "type" in item else f'text: {item["text"]}'
98
+ for item in content
99
+ )
100
+ formatted_messages.append(f"{role}: {content_str}")
101
+ else:
102
+ formatted_messages.append(f"{role}: {content}")
103
+ prompt = "\n".join(formatted_messages)
104
+
105
+ # Calculate tokens using input prompt and aggregated response
106
+ prompt_tokens = openai_tokens(prompt,
107
+ self._kwargs.get("model", "gpt-3.5-turbo"))
108
+ completion_tokens = openai_tokens(self._llmresponse,
109
+ self._kwargs.get("model", "gpt-3.5-turbo"))
110
+
111
+ # Calculate cost of the operation
112
+ cost = get_chat_model_cost(self._kwargs.get("model", "gpt-3.5-turbo"),
113
+ pricing_info, prompt_tokens,
114
+ completion_tokens)
115
+
116
+ # Set Span attributes
117
+ self._span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
118
+ self._span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
119
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI)
120
+ self._span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
121
+ SemanticConvetion.GEN_AI_TYPE_CHAT)
122
+ self._span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
123
+ gen_ai_endpoint)
124
+ self._span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_ID,
125
+ self._response_id)
126
+ self._span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
127
+ environment)
128
+ self._span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
129
+ application_name)
130
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
131
+ self._kwargs.get("model", "gpt-3.5-turbo"))
132
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
133
+ self._kwargs.get("user", ""))
134
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
135
+ self._kwargs.get("top_p", 1.0))
136
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
137
+ self._kwargs.get("max_tokens", -1))
138
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
139
+ self._kwargs.get("temperature", 1.0))
140
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_PRESENCE_PENALTY,
141
+ self._kwargs.get("presence_penalty", 0.0))
142
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_FREQUENCY_PENALTY,
143
+ self._kwargs.get("frequency_penalty", 0.0))
144
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_SEED,
145
+ self._kwargs.get("seed", ""))
146
+ self._span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
147
+ True)
148
+ self._span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
149
+ prompt_tokens)
150
+ self._span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
151
+ completion_tokens)
152
+ self._span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
153
+ prompt_tokens + completion_tokens)
154
+ self._span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
155
+ cost)
156
+ if trace_content:
157
+ self._span.add_event(
158
+ name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
159
+ attributes={
160
+ SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
161
+ },
162
+ )
163
+ self._span.add_event(
164
+ name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
165
+ attributes={
166
+ SemanticConvetion.GEN_AI_CONTENT_COMPLETION: self._llmresponse,
167
+ },
168
+ )
169
+
170
+ self._span.set_status(Status(StatusCode.OK))
171
+
172
+ if disable_metrics is False:
173
+ attributes = {
174
+ TELEMETRY_SDK_NAME:
175
+ "openlit",
176
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
177
+ application_name,
178
+ SemanticConvetion.GEN_AI_SYSTEM:
179
+ SemanticConvetion.GEN_AI_SYSTEM_OPENAI,
180
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
181
+ environment,
182
+ SemanticConvetion.GEN_AI_TYPE:
183
+ SemanticConvetion.GEN_AI_TYPE_CHAT,
184
+ SemanticConvetion.GEN_AI_REQUEST_MODEL:
185
+ self._kwargs.get("model", "gpt-3.5-turbo")
186
+ }
187
+
188
+ metrics["genai_requests"].add(1, attributes)
189
+ metrics["genai_total_tokens"].add(
190
+ prompt_tokens + completion_tokens, attributes
191
+ )
192
+ metrics["genai_completion_tokens"].add(completion_tokens, attributes)
193
+ metrics["genai_prompt_tokens"].add(prompt_tokens, attributes)
194
+ metrics["genai_cost"].record(cost, attributes)
195
+
196
+ except Exception as e:
197
+ handle_exception(self._span, e)
198
+ logger.error("Error in trace creation: %s", e)
199
+ finally:
200
+ self._span.end()
201
+ raise
202
+
34
203
  async def wrapper(wrapped, instance, args, kwargs):
35
204
  """
36
205
  Wraps the 'chat.completions' API call to add telemetry.
37
-
206
+
38
207
  This collects metrics such as execution time, cost, and token usage, and handles errors
39
208
  gracefully, adding details to the trace for observability.
40
209
 
@@ -54,140 +223,10 @@ def async_chat_completions(gen_ai_endpoint, version, environment, application_na
54
223
  # pylint: disable=no-else-return
55
224
  if streaming:
56
225
  # Special handling for streaming response to accommodate the nature of data flow
57
- async def stream_generator():
58
- with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
59
- # Placeholder for aggregating streaming response
60
- llmresponse = ""
61
-
62
- # Loop through streaming events capturing relevant details
63
- async for chunk in await wrapped(*args, **kwargs):
64
- # Collect message IDs and aggregated response from events
65
- if len(chunk.choices) > 0:
66
- # pylint: disable=line-too-long
67
- if hasattr(chunk.choices[0], "delta") and hasattr(chunk.choices[0].delta, "content"):
68
- content = chunk.choices[0].delta.content
69
- if content:
70
- llmresponse += content
71
- yield chunk
72
- response_id = chunk.id
73
-
74
- # Handling exception ensure observability without disrupting operation
75
- try:
76
- # Format 'messages' into a single string
77
- message_prompt = kwargs.get("messages", "")
78
- formatted_messages = []
79
- for message in message_prompt:
80
- role = message["role"]
81
- content = message["content"]
82
-
83
- if isinstance(content, list):
84
- content_str = ", ".join(
85
- # pylint: disable=line-too-long
86
- f'{item["type"]}: {item["text"] if "text" in item else item["image_url"]}'
87
- if "type" in item else f'text: {item["text"]}'
88
- for item in content
89
- )
90
- formatted_messages.append(f"{role}: {content_str}")
91
- else:
92
- formatted_messages.append(f"{role}: {content}")
93
- prompt = "\n".join(formatted_messages)
94
-
95
- # Calculate tokens using input prompt and aggregated response
96
- prompt_tokens = openai_tokens(prompt,
97
- kwargs.get("model", "gpt-3.5-turbo"))
98
- completion_tokens = openai_tokens(llmresponse,
99
- kwargs.get("model", "gpt-3.5-turbo"))
226
+ awaited_wrapped = await wrapped(*args, **kwargs)
227
+ span = tracer.start_span(gen_ai_endpoint, kind=SpanKind.CLIENT)
100
228
 
101
- # Calculate cost of the operation
102
- cost = get_chat_model_cost(kwargs.get("model", "gpt-3.5-turbo"),
103
- pricing_info, prompt_tokens,
104
- completion_tokens)
105
-
106
- # Set Span attributes
107
- span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
108
- span.set_attribute(SemanticConvetion.GEN_AI_SYSTEM,
109
- SemanticConvetion.GEN_AI_SYSTEM_OPENAI)
110
- span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
111
- SemanticConvetion.GEN_AI_TYPE_CHAT)
112
- span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
113
- gen_ai_endpoint)
114
- span.set_attribute(SemanticConvetion.GEN_AI_RESPONSE_ID,
115
- response_id)
116
- span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
117
- environment)
118
- span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
119
- application_name)
120
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MODEL,
121
- kwargs.get("model", "gpt-3.5-turbo"))
122
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_USER,
123
- kwargs.get("user", ""))
124
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TOP_P,
125
- kwargs.get("top_p", 1.0))
126
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_MAX_TOKENS,
127
- kwargs.get("max_tokens", -1))
128
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_TEMPERATURE,
129
- kwargs.get("temperature", 1.0))
130
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_PRESENCE_PENALTY,
131
- kwargs.get("presence_penalty", 0.0))
132
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_FREQUENCY_PENALTY,
133
- kwargs.get("frequency_penalty", 0.0))
134
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_SEED,
135
- kwargs.get("seed", ""))
136
- span.set_attribute(SemanticConvetion.GEN_AI_REQUEST_IS_STREAM,
137
- True)
138
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_PROMPT_TOKENS,
139
- prompt_tokens)
140
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COMPLETION_TOKENS,
141
- completion_tokens)
142
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_TOTAL_TOKENS,
143
- prompt_tokens + completion_tokens)
144
- span.set_attribute(SemanticConvetion.GEN_AI_USAGE_COST,
145
- cost)
146
- if trace_content:
147
- span.add_event(
148
- name=SemanticConvetion.GEN_AI_CONTENT_PROMPT_EVENT,
149
- attributes={
150
- SemanticConvetion.GEN_AI_CONTENT_PROMPT: prompt,
151
- },
152
- )
153
- span.add_event(
154
- name=SemanticConvetion.GEN_AI_CONTENT_COMPLETION_EVENT,
155
- attributes={
156
- SemanticConvetion.GEN_AI_CONTENT_COMPLETION: llmresponse,
157
- },
158
- )
159
-
160
- span.set_status(Status(StatusCode.OK))
161
-
162
- if disable_metrics is False:
163
- attributes = {
164
- TELEMETRY_SDK_NAME:
165
- "openlit",
166
- SemanticConvetion.GEN_AI_APPLICATION_NAME:
167
- application_name,
168
- SemanticConvetion.GEN_AI_SYSTEM:
169
- SemanticConvetion.GEN_AI_SYSTEM_OPENAI,
170
- SemanticConvetion.GEN_AI_ENVIRONMENT:
171
- environment,
172
- SemanticConvetion.GEN_AI_TYPE:
173
- SemanticConvetion.GEN_AI_TYPE_CHAT,
174
- SemanticConvetion.GEN_AI_REQUEST_MODEL:
175
- kwargs.get("model", "gpt-3.5-turbo")
176
- }
177
-
178
- metrics["genai_requests"].add(1, attributes)
179
- metrics["genai_total_tokens"].add(
180
- prompt_tokens + completion_tokens, attributes
181
- )
182
- metrics["genai_completion_tokens"].add(completion_tokens, attributes)
183
- metrics["genai_prompt_tokens"].add(prompt_tokens, attributes)
184
- metrics["genai_cost"].record(cost, attributes)
185
-
186
- except Exception as e:
187
- handle_exception(span, e)
188
- logger.error("Error in trace creation: %s", e)
189
-
190
- return stream_generator()
229
+ return TracedAsyncStream(awaited_wrapped, span)
191
230
 
192
231
  # Handling for non-streaming responses
193
232
  else:
@@ -363,7 +402,7 @@ def async_embedding(gen_ai_endpoint, version, environment, application_name,
363
402
  tracer, pricing_info, trace_content, metrics, disable_metrics):
364
403
  """
365
404
  Generates a telemetry wrapper for embeddings to collect metrics.
366
-
405
+
367
406
  Args:
368
407
  gen_ai_endpoint: Endpoint identifier for logging and tracing.
369
408
  version: Version of the monitoring package.
@@ -372,7 +411,7 @@ def async_embedding(gen_ai_endpoint, version, environment, application_name,
372
411
  tracer: OpenTelemetry tracer for creating spans.
373
412
  pricing_info: Information used for calculating the cost of OpenAI usage.
374
413
  trace_content: Flag indicating whether to trace the actual content.
375
-
414
+
376
415
  Returns:
377
416
  A function that wraps the embeddings method to add telemetry.
378
417
  """
@@ -475,7 +514,7 @@ def async_finetune(gen_ai_endpoint, version, environment, application_name,
475
514
  tracer, pricing_info, trace_content, metrics, disable_metrics):
476
515
  """
477
516
  Generates a telemetry wrapper for fine-tuning jobs to collect metrics.
478
-
517
+
479
518
  Args:
480
519
  gen_ai_endpoint: Endpoint identifier for logging and tracing.
481
520
  version: Version of the monitoring package.
@@ -484,7 +523,7 @@ def async_finetune(gen_ai_endpoint, version, environment, application_name,
484
523
  tracer: OpenTelemetry tracer for creating spans.
485
524
  pricing_info: Information used for calculating the cost of OpenAI usage.
486
525
  trace_content: Flag indicating whether to trace the actual content.
487
-
526
+
488
527
  Returns:
489
528
  A function that wraps the fine tuning creation method to add telemetry.
490
529
  """
@@ -564,7 +603,7 @@ def async_image_generate(gen_ai_endpoint, version, environment, application_name
564
603
  tracer, pricing_info, trace_content, metrics, disable_metrics):
565
604
  """
566
605
  Generates a telemetry wrapper for image generation to collect metrics.
567
-
606
+
568
607
  Args:
569
608
  gen_ai_endpoint: Endpoint identifier for logging and tracing.
570
609
  version: Version of the monitoring package.
@@ -573,7 +612,7 @@ def async_image_generate(gen_ai_endpoint, version, environment, application_name
573
612
  tracer: OpenTelemetry tracer for creating spans.
574
613
  pricing_info: Information used for calculating the cost of OpenAI image generation.
575
614
  trace_content: Flag indicating whether to trace the input prompt and generated images.
576
-
615
+
577
616
  Returns:
578
617
  A function that wraps the image generation method to add telemetry.
579
618
  """
@@ -694,7 +733,7 @@ def async_image_variatons(gen_ai_endpoint, version, environment, application_nam
694
733
  tracer, pricing_info, trace_content, metrics, disable_metrics):
695
734
  """
696
735
  Generates a telemetry wrapper for creating image variations to collect metrics.
697
-
736
+
698
737
  Args:
699
738
  gen_ai_endpoint: Endpoint identifier for logging and tracing.
700
739
  version: Version of the monitoring package.
@@ -703,7 +742,7 @@ def async_image_variatons(gen_ai_endpoint, version, environment, application_nam
703
742
  tracer: OpenTelemetry tracer for creating spans.
704
743
  pricing_info: Information used for calculating the cost of generating image variations.
705
744
  trace_content: Flag indicating whether to trace the input image and generated variations.
706
-
745
+
707
746
  Returns:
708
747
  A function that wraps the image variations creation method to add telemetry.
709
748
  """
@@ -813,7 +852,7 @@ def async_audio_create(gen_ai_endpoint, version, environment, application_name,
813
852
  tracer, pricing_info, trace_content, metrics, disable_metrics):
814
853
  """
815
854
  Generates a telemetry wrapper for creating speech audio to collect metrics.
816
-
855
+
817
856
  Args:
818
857
  gen_ai_endpoint: Endpoint identifier for logging and tracing.
819
858
  version: Version of the monitoring package.
@@ -822,7 +861,7 @@ def async_audio_create(gen_ai_endpoint, version, environment, application_name,
822
861
  tracer: OpenTelemetry tracer for creating spans.
823
862
  pricing_info: Information used for calculating the cost of generating speech audio.
824
863
  trace_content: Flag indicating whether to trace the input text and generated audio.
825
-
864
+
826
865
  Returns:
827
866
  A function that wraps the speech audio creation method to add telemetry.
828
867
  """
@@ -6,6 +6,7 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
6
6
  from wrapt import wrap_function_wrapper
7
7
 
8
8
  from openlit.instrumentation.qdrant.qdrant import general_wrap
9
+ from openlit.instrumentation.qdrant.async_qdrant import async_general_wrap
9
10
 
10
11
  _instruments = ("qdrant-client >= 1.9.0",)
11
12
 
@@ -118,7 +119,146 @@ WRAPPED_METHODS = [
118
119
  "object": "QdrantClient.recommend",
119
120
  "endpoint": "qdrant.recommend",
120
121
  "wrapper": general_wrap,
121
- }
122
+ },
123
+ {
124
+
125
+ "package": "qdrant_client",
126
+ "object": "QdrantClient.create_payload_index",
127
+ "endpoint": "qdrant.create_payload_index",
128
+ "wrapper": general_wrap,
129
+ },
130
+ {
131
+
132
+ "package": "qdrant_client",
133
+ "object": "QdrantClient.query_points",
134
+ "endpoint": "qdrant.query_points",
135
+ "wrapper": general_wrap,
136
+ },
137
+
138
+ # Async Client
139
+ {
140
+ "package": "qdrant_client",
141
+ "object": "AsyncQdrantClient.create_collection",
142
+ "endpoint": "qdrant.create_collection",
143
+ "wrapper": async_general_wrap,
144
+ },
145
+ {
146
+ "package": "qdrant_client",
147
+ "object": "AsyncQdrantClient.delete_collection",
148
+ "endpoint": "qdrant.delete_collection",
149
+ "wrapper": async_general_wrap,
150
+ },
151
+ {
152
+ "package": "qdrant_client",
153
+ "object": "AsyncQdrantClient.update_collection",
154
+ "endpoint": "qdrant.update_collection",
155
+ "wrapper": async_general_wrap,
156
+ },
157
+ {
158
+ "package": "qdrant_client",
159
+ "object": "AsyncQdrantClient.upload_collection",
160
+ "endpoint": "qdrant.upload_collection",
161
+ "wrapper": async_general_wrap,
162
+ },
163
+ {
164
+ "package": "qdrant_client",
165
+ "object": "AsyncQdrantClient.upsert",
166
+ "endpoint": "qdrant.upsert",
167
+ "wrapper": async_general_wrap,
168
+ },
169
+ {
170
+ "package": "qdrant_client",
171
+ "object": "AsyncQdrantClient.set_payload",
172
+ "endpoint": "qdrant.set_payload",
173
+ "wrapper": async_general_wrap,
174
+ },
175
+ {
176
+ "package": "qdrant_client",
177
+ "object": "AsyncQdrantClient.overwrite_payload",
178
+ "endpoint": "qdrant.overwrite_payload",
179
+ "wrapper": async_general_wrap,
180
+ },
181
+ {
182
+ "package": "qdrant_client",
183
+ "object": "AsyncQdrantClient.clear_payload",
184
+ "endpoint": "qdrant.clear_payload",
185
+ "wrapper": async_general_wrap,
186
+ },
187
+ {
188
+ "package": "qdrant_client",
189
+ "object": "AsyncQdrantClient.delete_payload",
190
+ "endpoint": "qdrant.delete_payload",
191
+ "wrapper": async_general_wrap,
192
+ },
193
+ {
194
+ "package": "qdrant_client",
195
+ "object": "AsyncQdrantClient.upload_points",
196
+ "endpoint": "qdrant.upload_points",
197
+ "wrapper": async_general_wrap,
198
+ },
199
+ {
200
+ "package": "qdrant_client",
201
+ "object": "AsyncQdrantClient.update_vectors",
202
+ "endpoint": "qdrant.update_vectors",
203
+ "wrapper": async_general_wrap,
204
+ },
205
+ {
206
+ "package": "qdrant_client",
207
+ "object": "AsyncQdrantClient.delete_vectors",
208
+ "endpoint": "qdrant.delete_vectors",
209
+ "wrapper": async_general_wrap,
210
+ },
211
+ {
212
+ "package": "qdrant_client",
213
+ "object": "AsyncQdrantClient.delete",
214
+ "endpoint": "qdrant.delete",
215
+ "wrapper": async_general_wrap,
216
+ },
217
+ {
218
+ "package": "qdrant_client",
219
+ "object": "AsyncQdrantClient.retrieve",
220
+ "endpoint": "qdrant.retrieve",
221
+ "wrapper": async_general_wrap,
222
+ },
223
+ {
224
+ "package": "qdrant_client",
225
+ "object": "AsyncQdrantClient.scroll",
226
+ "endpoint": "qdrant.scroll",
227
+ "wrapper": async_general_wrap,
228
+ },
229
+ {
230
+ "package": "qdrant_client",
231
+ "object": "AsyncQdrantClient.search",
232
+ "endpoint": "qdrant.search",
233
+ "wrapper": async_general_wrap,
234
+ },
235
+ {
236
+ "package": "qdrant_client",
237
+ "object": "AsyncQdrantClient.search_groups",
238
+ "endpoint": "qdrant.search_groups",
239
+ "wrapper": async_general_wrap,
240
+ },
241
+ {
242
+
243
+ "package": "qdrant_client",
244
+ "object": "AsyncQdrantClient.recommend",
245
+ "endpoint": "qdrant.recommend",
246
+ "wrapper": async_general_wrap,
247
+ },
248
+ {
249
+
250
+ "package": "qdrant_client",
251
+ "object": "AsyncQdrantClient.create_payload_index",
252
+ "endpoint": "qdrant.create_payload_index",
253
+ "wrapper": async_general_wrap,
254
+ },
255
+ {
256
+
257
+ "package": "qdrant_client",
258
+ "object": "AsyncQdrantClient.query_points",
259
+ "endpoint": "qdrant.query_points",
260
+ "wrapper": async_general_wrap,
261
+ },
122
262
  ]
123
263
 
124
264
  class QdrantInstrumentor(BaseInstrumentor):
@@ -24,7 +24,7 @@ def object_count(obj):
24
24
 
25
25
  return cnt
26
26
 
27
- def general_wrap(gen_ai_endpoint, version, environment, application_name,
27
+ def async_general_wrap(gen_ai_endpoint, version, environment, application_name,
28
28
  tracer, pricing_info, trace_content, metrics, disable_metrics):
29
29
  """
30
30
  Creates a wrapper around a function call to trace and log its execution metrics.
@@ -46,7 +46,7 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
46
46
  a new function that wraps 'wrapped' with additional tracing and logging.
47
47
  """
48
48
 
49
- def wrapper(wrapped, instance, args, kwargs):
49
+ async def wrapper(wrapped, instance, args, kwargs):
50
50
  """
51
51
  An inner wrapper function that executes the wrapped function, measures execution
52
52
  time, and records trace data using OpenTelemetry.
@@ -67,7 +67,7 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
67
67
  errors are handled and logged appropriately.
68
68
  """
69
69
  with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
70
- response = wrapped(*args, **kwargs)
70
+ response = await wrapped(*args, **kwargs)
71
71
 
72
72
  try:
73
73
  span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
@@ -226,6 +226,15 @@ def general_wrap(gen_ai_endpoint, version, environment, application_name,
226
226
  span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
227
227
  object_count(kwargs.get("points_selector")))
228
228
 
229
+ elif gen_ai_endpoint == "qdrant.create_payload_index":
230
+ db_operation = SemanticConvetion.DB_OPERATION_CREATE_INDEX
231
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
232
+ SemanticConvetion.DB_OPERATION_CREATE_INDEX)
233
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
234
+ kwargs.get("collection_name", ""))
235
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
236
+ str(kwargs.get("query", "")))
237
+
229
238
  span.set_status(Status(StatusCode.OK))
230
239
 
231
240
  if disable_metrics is False:
@@ -0,0 +1,274 @@
1
+ # pylint: disable=duplicate-code, broad-exception-caught, too-many-statements, unused-argument, possibly-used-before-assignment, too-many-branches
2
+ """
3
+ Module for monitoring Qdrant.
4
+ """
5
+
6
+ import logging
7
+ from opentelemetry.trace import SpanKind, Status, StatusCode
8
+ from opentelemetry.sdk.resources import TELEMETRY_SDK_NAME
9
+ from openlit.__helpers import handle_exception
10
+ from openlit.semcov import SemanticConvetion
11
+
12
+ # Initialize logger for logging potential issues and operations
13
+ logger = logging.getLogger(__name__)
14
+
15
+ def object_count(obj):
16
+ """
17
+ Counts Length of object if it exists, Else returns None
18
+ """
19
+ try:
20
+ cnt = len(obj)
21
+ # pylint: disable=bare-except
22
+ except:
23
+ cnt = 0
24
+
25
+ return cnt
26
+
27
+ def general_wrap(gen_ai_endpoint, version, environment, application_name,
28
+ tracer, pricing_info, trace_content, metrics, disable_metrics):
29
+ """
30
+ Creates a wrapper around a function call to trace and log its execution metrics.
31
+
32
+ This function wraps any given function to measure its execution time,
33
+ log its operation, and trace its execution using OpenTelemetry.
34
+
35
+ Parameters:
36
+ - gen_ai_endpoint (str): A descriptor or name for the endpoint being traced.
37
+ - version (str): The version of the Langchain application.
38
+ - environment (str): The deployment environment (e.g., 'production', 'development').
39
+ - application_name (str): Name of the Langchain application.
40
+ - tracer (opentelemetry.trace.Tracer): The tracer object used for OpenTelemetry tracing.
41
+ - pricing_info (dict): Information about the pricing for internal metrics (currently not used).
42
+ - trace_content (bool): Flag indicating whether to trace the content of the response.
43
+
44
+ Returns:
45
+ - function: A higher-order function that takes a function 'wrapped' and returns
46
+ a new function that wraps 'wrapped' with additional tracing and logging.
47
+ """
48
+
49
+ def wrapper(wrapped, instance, args, kwargs):
50
+ """
51
+ An inner wrapper function that executes the wrapped function, measures execution
52
+ time, and records trace data using OpenTelemetry.
53
+
54
+ Parameters:
55
+ - wrapped (Callable): The original function that this wrapper will execute.
56
+ - instance (object): The instance to which the wrapped function belongs. This
57
+ is used for instance methods. For static and classmethods,
58
+ this may be None.
59
+ - args (tuple): Positional arguments passed to the wrapped function.
60
+ - kwargs (dict): Keyword arguments passed to the wrapped function.
61
+
62
+ Returns:
63
+ - The result of the wrapped function call.
64
+
65
+ The wrapper initiates a span with the provided tracer, sets various attributes
66
+ on the span based on the function's execution and response, and ensures
67
+ errors are handled and logged appropriately.
68
+ """
69
+ with tracer.start_as_current_span(gen_ai_endpoint, kind= SpanKind.CLIENT) as span:
70
+ response = wrapped(*args, **kwargs)
71
+
72
+ try:
73
+ span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
74
+ span.set_attribute(SemanticConvetion.GEN_AI_ENDPOINT,
75
+ gen_ai_endpoint)
76
+ span.set_attribute(SemanticConvetion.GEN_AI_ENVIRONMENT,
77
+ environment)
78
+ span.set_attribute(SemanticConvetion.GEN_AI_APPLICATION_NAME,
79
+ application_name)
80
+ span.set_attribute(SemanticConvetion.GEN_AI_TYPE,
81
+ SemanticConvetion.GEN_AI_TYPE_VECTORDB)
82
+ span.set_attribute(SemanticConvetion.DB_SYSTEM,
83
+ SemanticConvetion.DB_SYSTEM_QDRANT)
84
+
85
+ if gen_ai_endpoint == "qdrant.create_collection":
86
+ db_operation = SemanticConvetion.DB_OPERATION_CREATE_COLLECTION
87
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
88
+ SemanticConvetion.DB_OPERATION_CREATE_COLLECTION)
89
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
90
+ kwargs.get("collection_name", ""))
91
+
92
+ elif gen_ai_endpoint == "qdrant.upload_collection":
93
+ db_operation = SemanticConvetion.DB_OPERATION_CREATE_COLLECTION
94
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
95
+ SemanticConvetion.DB_OPERATION_CREATE_COLLECTION)
96
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
97
+ kwargs.get("collection_name", ""))
98
+
99
+ elif gen_ai_endpoint == "qdrant.delete_collection":
100
+ db_operation = SemanticConvetion.DB_OPERATION_DELETE_COLLECTION
101
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
102
+ SemanticConvetion.DB_OPERATION_DELETE_COLLECTION)
103
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
104
+ kwargs.get("collection_name", ""))
105
+
106
+ elif gen_ai_endpoint == "qdrant.update_collection":
107
+ db_operation = SemanticConvetion.DB_OPERATION_UPDATE_COLLECTION
108
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
109
+ SemanticConvetion.DB_OPERATION_UPDATE_COLLECTION)
110
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
111
+ kwargs.get("collection_name", ""))
112
+
113
+ elif gen_ai_endpoint == "qdrant.set_payload":
114
+ db_operation = SemanticConvetion.DB_OPERATION_ADD
115
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
116
+ SemanticConvetion.DB_OPERATION_ADD)
117
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
118
+ kwargs.get("collection_name", ""))
119
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
120
+ response.status)
121
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
122
+ object_count(kwargs.get("points", [])))
123
+ span.set_attribute(SemanticConvetion.DB_PAYLOAD_COUNT,
124
+ object_count(kwargs.get("payload", [])))
125
+
126
+ elif gen_ai_endpoint == "qdrant.retrieve":
127
+ db_operation = SemanticConvetion.DB_OPERATION_QUERY
128
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
129
+ SemanticConvetion.DB_OPERATION_QUERY)
130
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
131
+ kwargs.get("collection_name", ""))
132
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
133
+ str(kwargs.get("ids", "")))
134
+
135
+ elif gen_ai_endpoint == "qdrant.scroll":
136
+ db_operation = SemanticConvetion.DB_OPERATION_QUERY
137
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
138
+ SemanticConvetion.DB_OPERATION_QUERY)
139
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
140
+ kwargs.get("collection_name", ""))
141
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
142
+ str(kwargs.get("scroll_filter", "")))
143
+
144
+ elif gen_ai_endpoint in ["qdrant.search", "qdrant.search_groups"]:
145
+ db_operation = SemanticConvetion.DB_OPERATION_QUERY
146
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
147
+ SemanticConvetion.DB_OPERATION_QUERY)
148
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
149
+ kwargs.get("collection_name", ""))
150
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
151
+ str(kwargs.get("query_vector", "")))
152
+
153
+ elif gen_ai_endpoint == "qdrant.recommend":
154
+ db_operation = SemanticConvetion.DB_OPERATION_QUERY
155
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
156
+ SemanticConvetion.DB_OPERATION_QUERY)
157
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
158
+ kwargs.get("collection_name", ""))
159
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
160
+ "positive:" + str(kwargs.get("positive", "")) +
161
+ " negative:" + str(kwargs.get("negative", "")))
162
+
163
+ elif gen_ai_endpoint == "qdrant.upload_points":
164
+ db_operation = SemanticConvetion.DB_OPERATION_ADD
165
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
166
+ SemanticConvetion.DB_OPERATION_ADD)
167
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
168
+ kwargs.get("collection_name", ""))
169
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
170
+ object_count(kwargs.get("points")))
171
+
172
+ elif gen_ai_endpoint == "qdrant.update_vectors":
173
+ db_operation = SemanticConvetion.DB_OPERATION_UPDATE
174
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
175
+ SemanticConvetion.DB_OPERATION_UPDATE)
176
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
177
+ kwargs.get("collection_name", ""))
178
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
179
+ response.status)
180
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
181
+ object_count(kwargs.get("points")))
182
+
183
+ elif gen_ai_endpoint == "qdrant.overwrite_payload":
184
+ db_operation = SemanticConvetion.DB_OPERATION_UPDATE
185
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
186
+ SemanticConvetion.DB_OPERATION_UPDATE)
187
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
188
+ kwargs.get("collection_name", ""))
189
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
190
+ response.status)
191
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
192
+ object_count(kwargs.get("points")))
193
+ span.set_attribute(SemanticConvetion.DB_PAYLOAD_COUNT,
194
+ object_count(kwargs.get("payload")))
195
+
196
+ elif gen_ai_endpoint == "qdrant.upsert":
197
+ db_operation = SemanticConvetion.DB_OPERATION_UPSERT
198
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
199
+ kwargs.get("collection_name", ""))
200
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
201
+ SemanticConvetion.DB_OPERATION_UPSERT)
202
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
203
+ response.status)
204
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
205
+ object_count(kwargs.get("points")))
206
+
207
+ elif gen_ai_endpoint in ["qdrant.delete_payload", "qdrant.delete_vectors"]:
208
+ db_operation = SemanticConvetion.DB_OPERATION_DELETE
209
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
210
+ SemanticConvetion.DB_OPERATION_DELETE)
211
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
212
+ kwargs.get("collection_name", ""))
213
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
214
+ response.status)
215
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
216
+ object_count(kwargs.get("points")))
217
+
218
+ elif gen_ai_endpoint in ["qdrant.clear_payload", "qdrant.delete"]:
219
+ db_operation = SemanticConvetion.DB_OPERATION_DELETE
220
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
221
+ SemanticConvetion.DB_OPERATION_DELETE)
222
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
223
+ kwargs.get("collection_name", ""))
224
+ span.set_attribute(SemanticConvetion.DB_OPERATION_STATUS,
225
+ response.status)
226
+ span.set_attribute(SemanticConvetion.DB_VECTOR_COUNT,
227
+ object_count(kwargs.get("points_selector")))
228
+
229
+ elif gen_ai_endpoint == "qdrant.create_payload_index":
230
+ db_operation = SemanticConvetion.DB_OPERATION_CREATE_INDEX
231
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
232
+ SemanticConvetion.DB_OPERATION_CREATE_INDEX)
233
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
234
+ kwargs.get("collection_name", ""))
235
+
236
+ elif gen_ai_endpoint == "qdrant.query_points":
237
+ db_operation = SemanticConvetion.DB_OPERATION_QUERY
238
+ span.set_attribute(SemanticConvetion.DB_OPERATION,
239
+ SemanticConvetion.DB_OPERATION_QUERY)
240
+ span.set_attribute(SemanticConvetion.DB_COLLECTION_NAME,
241
+ kwargs.get("collection_name", ""))
242
+ span.set_attribute(SemanticConvetion.DB_STATEMENT,
243
+ str(kwargs.get("query", "")))
244
+
245
+ span.set_status(Status(StatusCode.OK))
246
+
247
+ if disable_metrics is False:
248
+ attributes = {
249
+ TELEMETRY_SDK_NAME:
250
+ "openlit",
251
+ SemanticConvetion.GEN_AI_APPLICATION_NAME:
252
+ application_name,
253
+ SemanticConvetion.DB_SYSTEM:
254
+ SemanticConvetion.DB_SYSTEM_QDRANT,
255
+ SemanticConvetion.GEN_AI_ENVIRONMENT:
256
+ environment,
257
+ SemanticConvetion.GEN_AI_TYPE:
258
+ SemanticConvetion.GEN_AI_TYPE_VECTORDB,
259
+ SemanticConvetion.DB_OPERATION:
260
+ db_operation
261
+ }
262
+
263
+ metrics["db_requests"].add(1, attributes)
264
+
265
+ return response
266
+
267
+ except Exception as e:
268
+ handle_exception(span, e)
269
+ logger.error("Error in trace creation: %s", e)
270
+
271
+ # Return original response
272
+ return response
273
+
274
+ return wrapper
File without changes
File without changes