openlit 1.34.25__py3-none-any.whl → 1.34.27__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.
@@ -1,179 +1,52 @@
1
- # pylint: disable=duplicate-code, broad-exception-caught, too-many-statements, unused-argument, possibly-used-before-assignment, too-many-branches
2
1
  """
3
- Module for monitoring Milvus.
2
+ Module for monitoring Milvus API calls.
4
3
  """
5
4
 
6
- import logging
7
- from opentelemetry.trace import SpanKind, Status, StatusCode
8
- from opentelemetry.sdk.resources import SERVICE_NAME, TELEMETRY_SDK_NAME, DEPLOYMENT_ENVIRONMENT
5
+ import time
6
+ from opentelemetry.trace import SpanKind
7
+ from opentelemetry import context as context_api
9
8
  from openlit.__helpers import handle_exception
10
- from openlit.semcov import SemanticConvention
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
9
+ from openlit.instrumentation.milvus.utils import (
10
+ process_milvus_response,
11
+ DB_OPERATION_MAP,
12
+ set_server_address_and_port,
13
+ )
26
14
 
27
15
  def general_wrap(gen_ai_endpoint, version, environment, application_name,
28
- tracer, pricing_info, capture_message_content, metrics, disable_metrics):
16
+ tracer, pricing_info, capture_message_content, metrics, disable_metrics):
29
17
  """
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
- - capture_message_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.
18
+ Generates a telemetry wrapper for Milvus function calls.
47
19
  """
48
-
49
20
  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:
21
+ # CRITICAL: Suppression check
22
+ if context_api.get_value(context_api._SUPPRESS_INSTRUMENTATION_KEY):
23
+ return wrapped(*args, **kwargs)
24
+
25
+ # Get server address and port using the standard helper
26
+ server_address, server_port = set_server_address_and_port(instance)
27
+
28
+ db_operation = DB_OPERATION_MAP.get(gen_ai_endpoint, "unknown")
29
+ if db_operation == "create_collection":
30
+ collection_name = kwargs.get("collection_name") or (args[0] if args else "unknown")
31
+ else:
32
+ collection_name = kwargs.get("collection_name", "unknown")
33
+ span_name = f"{db_operation} {collection_name}"
34
+
35
+ with tracer.start_as_current_span(span_name, kind=SpanKind.CLIENT) as span:
36
+ start_time = time.time()
70
37
  response = wrapped(*args, **kwargs)
71
38
 
72
39
  try:
73
- span.set_attribute(TELEMETRY_SDK_NAME, "openlit")
74
- span.set_attribute(SemanticConvention.GEN_AI_ENDPOINT,
75
- gen_ai_endpoint)
76
- span.set_attribute(DEPLOYMENT_ENVIRONMENT,
77
- environment)
78
- span.set_attribute(SERVICE_NAME,
79
- application_name)
80
- span.set_attribute(SemanticConvention.GEN_AI_OPERATION,
81
- SemanticConvention.GEN_AI_OPERATION_TYPE_VECTORDB)
82
- span.set_attribute(SemanticConvention.DB_SYSTEM_NAME,
83
- SemanticConvention.DB_SYSTEM_MILVUS)
84
-
85
- if gen_ai_endpoint == "milvus.create_collection":
86
- db_operation = SemanticConvention.DB_OPERATION_CREATE_COLLECTION
87
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
88
- SemanticConvention.DB_OPERATION_CREATE_COLLECTION)
89
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
90
- kwargs.get("collection_name", ""))
91
- span.set_attribute(SemanticConvention.DB_COLLECTION_DIMENSION,
92
- kwargs.get("dimension", ""))
93
-
94
- elif gen_ai_endpoint == "milvus.drop_collection":
95
- db_operation = SemanticConvention.DB_OPERATION_DELETE_COLLECTION
96
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
97
- SemanticConvention.DB_OPERATION_DELETE_COLLECTION)
98
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
99
- kwargs.get("collection_name", ""))
100
-
101
- elif gen_ai_endpoint == "milvus.insert":
102
- db_operation = SemanticConvention.DB_OPERATION_ADD
103
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
104
- SemanticConvention.DB_OPERATION_ADD)
105
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
106
- kwargs.get("collection_name", ""))
107
- span.set_attribute(SemanticConvention.DB_VECTOR_COUNT,
108
- object_count(kwargs.get("data")))
109
- span.set_attribute(SemanticConvention.DB_OPERATION_COST,
110
- response["cost"])
111
-
112
- elif gen_ai_endpoint == "milvus.search":
113
- db_operation = SemanticConvention.DB_OPERATION_QUERY
114
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
115
- SemanticConvention.DB_OPERATION_QUERY)
116
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
117
- kwargs.get("collection_name", ""))
118
- span.set_attribute(SemanticConvention.DB_STATEMENT,
119
- str(kwargs.get("data")))
120
-
121
- elif gen_ai_endpoint in ["milvus.query", "milvus.get"]:
122
- db_operation = SemanticConvention.DB_OPERATION_QUERY
123
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
124
- SemanticConvention.DB_OPERATION_QUERY)
125
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
126
- kwargs.get("collection_name", ""))
127
- span.set_attribute(SemanticConvention.DB_STATEMENT,
128
- str(kwargs.get("output_fields")))
129
-
130
- elif gen_ai_endpoint == "milvus.upsert":
131
- db_operation = SemanticConvention.DB_OPERATION_ADD
132
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
133
- SemanticConvention.DB_OPERATION_UPSERT)
134
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
135
- kwargs.get("collection_name", ""))
136
- span.set_attribute(SemanticConvention.DB_VECTOR_COUNT,
137
- object_count(kwargs.get("data")))
138
- span.set_attribute(SemanticConvention.DB_OPERATION_COST,
139
- response["cost"])
140
-
141
- elif gen_ai_endpoint == "milvus.delete":
142
- db_operation = SemanticConvention.DB_OPERATION_DELETE
143
- span.set_attribute(SemanticConvention.DB_OPERATION_NAME,
144
- SemanticConvention.DB_OPERATION_DELETE)
145
- span.set_attribute(SemanticConvention.DB_COLLECTION_NAME,
146
- kwargs.get("collection_name", ""))
147
- span.set_attribute(SemanticConvention.DB_FILTER,
148
- str(kwargs.get("filter", "")))
149
-
150
- span.set_status(Status(StatusCode.OK))
151
-
152
- if disable_metrics is False:
153
- attributes = {
154
- TELEMETRY_SDK_NAME:
155
- "openlit",
156
- SERVICE_NAME:
157
- application_name,
158
- SemanticConvention.DB_SYSTEM_NAME:
159
- SemanticConvention.DB_SYSTEM_MILVUS,
160
- DEPLOYMENT_ENVIRONMENT:
161
- environment,
162
- SemanticConvention.GEN_AI_OPERATION:
163
- SemanticConvention.GEN_AI_OPERATION_TYPE_VECTORDB,
164
- SemanticConvention.DB_OPERATION_NAME:
165
- db_operation
166
- }
167
-
168
- metrics["db_requests"].add(1, attributes)
169
-
170
- return response
40
+ # Process response and generate telemetry
41
+ response = process_milvus_response(
42
+ response, db_operation, server_address, server_port,
43
+ environment, application_name, metrics, start_time, span,
44
+ capture_message_content, disable_metrics, version, instance, args, **kwargs
45
+ )
171
46
 
172
47
  except Exception as e:
173
48
  handle_exception(span, e)
174
- logger.error("Error in trace creation: %s", e)
175
49
 
176
- # Return original response
177
- return response
50
+ return response
178
51
 
179
52
  return wrapper
@@ -0,0 +1,276 @@
1
+ """
2
+ Utility functions for Milvus instrumentation.
3
+ """
4
+
5
+ import time
6
+ from urllib.parse import urlparse
7
+ from opentelemetry.trace import Status, StatusCode
8
+ from openlit.__helpers import (
9
+ common_db_span_attributes,
10
+ record_db_metrics,
11
+ )
12
+ from openlit.semcov import SemanticConvention
13
+
14
+ # Operation mapping for simple span naming
15
+ DB_OPERATION_MAP = {
16
+ "milvus.create_collection": SemanticConvention.DB_OPERATION_CREATE_COLLECTION,
17
+ "milvus.drop_collection": SemanticConvention.DB_OPERATION_DELETE_COLLECTION,
18
+ "milvus.insert": SemanticConvention.DB_OPERATION_INSERT,
19
+ "milvus.upsert": SemanticConvention.DB_OPERATION_UPSERT,
20
+ "milvus.search": SemanticConvention.DB_OPERATION_SEARCH,
21
+ "milvus.query": SemanticConvention.DB_OPERATION_QUERY,
22
+ "milvus.get": SemanticConvention.DB_OPERATION_GET,
23
+ "milvus.delete": SemanticConvention.DB_OPERATION_DELETE,
24
+ }
25
+
26
+ def object_count(obj):
27
+ """
28
+ Counts length of object if it exists, else returns 0.
29
+ """
30
+ return len(obj) if obj else 0
31
+
32
+ def set_server_address_and_port(instance):
33
+ """
34
+ Extracts server address and port from Milvus client instance.
35
+
36
+ Args:
37
+ instance: Milvus client instance
38
+
39
+ Returns:
40
+ tuple: (server_address, server_port)
41
+ """
42
+ server_address = "localhost"
43
+ server_port = 19530 # Default Milvus port
44
+
45
+ # Try getting uri from multiple potential attributes
46
+ client_config = getattr(instance, "_client_config", None)
47
+ if client_config:
48
+ uri = getattr(client_config, "uri", None)
49
+ if uri and isinstance(uri, str):
50
+ if uri.startswith(("http://", "https://")):
51
+ try:
52
+ parsed = urlparse(uri)
53
+ server_address = parsed.hostname or server_address
54
+ server_port = parsed.port or server_port
55
+ except Exception:
56
+ pass
57
+ else:
58
+ # Handle cases like "localhost:19530" or just "localhost"
59
+ if ":" in uri:
60
+ parts = uri.split(":")
61
+ server_address = parts[0]
62
+ try:
63
+ server_port = int(parts[1])
64
+ except (ValueError, IndexError):
65
+ pass
66
+ else:
67
+ server_address = uri
68
+
69
+ return server_address, server_port
70
+
71
+ def common_milvus_logic(scope, environment, application_name,
72
+ metrics, capture_message_content, disable_metrics, version,
73
+ instance=None, endpoint=None):
74
+ """
75
+ Process Milvus database request and generate telemetry.
76
+
77
+ Args:
78
+ scope: Scope object containing span, response, and operation details
79
+ environment: Deployment environment
80
+ application_name: Name of the application
81
+ metrics: Metrics dictionary for recording telemetry
82
+ capture_message_content: Flag to capture message content
83
+ disable_metrics: Flag to disable metrics collection
84
+ version: Version of the Milvus client
85
+ instance: Milvus client instance
86
+ endpoint: Operation endpoint for differentiation
87
+ """
88
+ scope._end_time = time.time()
89
+
90
+ # Set common database span attributes using helper
91
+ common_db_span_attributes(scope, SemanticConvention.DB_SYSTEM_MILVUS,
92
+ scope._server_address, scope._server_port, environment, application_name, version)
93
+
94
+ # Set DB operation specific attributes
95
+ scope._span.set_attribute(SemanticConvention.DB_OPERATION_NAME, scope._db_operation)
96
+ scope._span.set_attribute(SemanticConvention.DB_CLIENT_OPERATION_DURATION,
97
+ scope._end_time - scope._start_time)
98
+
99
+ if scope._db_operation == SemanticConvention.DB_OPERATION_CREATE_COLLECTION:
100
+ collection_name = scope._kwargs.get("collection_name", "unknown")
101
+
102
+ # Standard database attributes
103
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
104
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_DIMENSION,
105
+ scope._kwargs.get("dimension", -1))
106
+
107
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
108
+ f"{scope._db_operation} {collection_name} "
109
+ f"dimension={scope._kwargs.get('dimension', 'None')}")
110
+
111
+ elif scope._db_operation == SemanticConvention.DB_OPERATION_DELETE_COLLECTION:
112
+ collection_name = scope._kwargs.get("collection_name", "unknown")
113
+
114
+ # Standard database attributes
115
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
116
+
117
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
118
+ f"{scope._db_operation} {collection_name}")
119
+
120
+ elif scope._db_operation == SemanticConvention.DB_OPERATION_INSERT:
121
+ collection_name = scope._kwargs.get("collection_name", "unknown")
122
+ data = scope._kwargs.get("data", [])
123
+
124
+ # Standard database attributes
125
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
126
+ scope._span.set_attribute(SemanticConvention.DB_VECTOR_COUNT, object_count(data))
127
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_TEXT, str(data))
128
+
129
+ # Response metrics
130
+ if scope._response and scope._response.get("insert_count"):
131
+ scope._span.set_attribute(SemanticConvention.DB_RESPONSE_RETURNED_ROWS,
132
+ scope._response["insert_count"])
133
+
134
+ if scope._response and scope._response.get("cost"):
135
+ scope._span.set_attribute(SemanticConvention.DB_OPERATION_COST,
136
+ scope._response["cost"])
137
+
138
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
139
+ f"{scope._db_operation} {collection_name} "
140
+ f"data_count={object_count(data)}")
141
+
142
+ elif scope._db_operation == SemanticConvention.DB_OPERATION_UPSERT:
143
+ collection_name = scope._kwargs.get("collection_name", "unknown")
144
+ data = scope._kwargs.get("data", [])
145
+
146
+ # Standard database attributes
147
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
148
+ scope._span.set_attribute(SemanticConvention.DB_VECTOR_COUNT, object_count(data))
149
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_TEXT, str(data))
150
+
151
+ # Response metrics
152
+ if scope._response and scope._response.get("upsert_count"):
153
+ scope._span.set_attribute(SemanticConvention.DB_RESPONSE_RETURNED_ROWS,
154
+ scope._response["upsert_count"])
155
+
156
+ if scope._response and scope._response.get("cost"):
157
+ scope._span.set_attribute(SemanticConvention.DB_OPERATION_COST,
158
+ scope._response["cost"])
159
+
160
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
161
+ f"{scope._db_operation} {collection_name} "
162
+ f"data_count={object_count(data)}")
163
+
164
+ elif scope._db_operation == SemanticConvention.DB_OPERATION_SEARCH:
165
+ collection_name = scope._kwargs.get("collection_name", "unknown")
166
+ data = scope._kwargs.get("data", [])
167
+
168
+ # Standard database attributes
169
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
170
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_TEXT, str(data))
171
+ scope._span.set_attribute(SemanticConvention.DB_VECTOR_QUERY_TOP_K,
172
+ scope._kwargs.get("limit", -1))
173
+
174
+ # Search specific attributes
175
+ scope._span.set_attribute(SemanticConvention.DB_FILTER,
176
+ str(scope._kwargs.get("filter", "")))
177
+
178
+ # Response metrics
179
+ if scope._response and isinstance(scope._response, list):
180
+ scope._span.set_attribute(SemanticConvention.DB_RESPONSE_RETURNED_ROWS,
181
+ len(scope._response))
182
+
183
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
184
+ f"{scope._db_operation} {collection_name} "
185
+ f"data={str(data)[:100]}... "
186
+ f"limit={scope._kwargs.get('limit', 'None')}")
187
+
188
+ elif scope._db_operation in [SemanticConvention.DB_OPERATION_QUERY, SemanticConvention.DB_OPERATION_GET]:
189
+ collection_name = scope._kwargs.get("collection_name", "unknown")
190
+ output_fields = scope._kwargs.get("output_fields", [])
191
+
192
+ # Standard database attributes
193
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
194
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_TEXT, str(output_fields))
195
+
196
+ # Query specific attributes
197
+ scope._span.set_attribute(SemanticConvention.DB_FILTER,
198
+ str(scope._kwargs.get("filter", "")))
199
+
200
+ # Response metrics
201
+ if scope._response and isinstance(scope._response, list):
202
+ scope._span.set_attribute(SemanticConvention.DB_RESPONSE_RETURNED_ROWS,
203
+ len(scope._response))
204
+
205
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
206
+ f"{scope._db_operation} {collection_name} "
207
+ f"output_fields={output_fields} "
208
+ f"filter={scope._kwargs.get('filter', 'None')}")
209
+
210
+ elif scope._db_operation == SemanticConvention.DB_OPERATION_DELETE:
211
+ collection_name = scope._kwargs.get("collection_name", "unknown")
212
+
213
+ # Standard database attributes
214
+ scope._span.set_attribute(SemanticConvention.DB_COLLECTION_NAME, collection_name)
215
+ scope._span.set_attribute(SemanticConvention.DB_FILTER,
216
+ str(scope._kwargs.get("filter", "")))
217
+
218
+ # Response metrics
219
+ if scope._response and scope._response.get("delete_count"):
220
+ scope._span.set_attribute(SemanticConvention.DB_RESPONSE_RETURNED_ROWS,
221
+ scope._response["delete_count"])
222
+
223
+ scope._span.set_attribute(SemanticConvention.DB_QUERY_SUMMARY,
224
+ f"{scope._db_operation} {collection_name} "
225
+ f"filter={scope._kwargs.get('filter', 'None')}")
226
+
227
+ scope._span.set_status(Status(StatusCode.OK))
228
+
229
+ # Record metrics using helper
230
+ if not disable_metrics:
231
+ record_db_metrics(metrics, SemanticConvention.DB_SYSTEM_MILVUS,
232
+ scope._server_address, scope._server_port, environment, application_name,
233
+ scope._start_time, scope._end_time)
234
+
235
+ def process_milvus_response(response, db_operation, server_address, server_port,
236
+ environment, application_name, metrics, start_time, span,
237
+ capture_message_content, disable_metrics, version, instance, args, **kwargs):
238
+ """
239
+ Process Milvus response and generate telemetry.
240
+
241
+ Args:
242
+ response: Response from Milvus operation
243
+ db_operation: Database operation type
244
+ server_address: Server address
245
+ server_port: Server port
246
+ environment: Deployment environment
247
+ application_name: Application name
248
+ metrics: Metrics dictionary
249
+ start_time: Start time of the operation
250
+ span: OpenTelemetry span
251
+ capture_message_content: Flag to capture message content
252
+ disable_metrics: Flag to disable metrics
253
+ version: Milvus client version
254
+ instance: Milvus client instance
255
+ args: Positional arguments
256
+ **kwargs: Keyword arguments
257
+
258
+ Returns:
259
+ Original response
260
+ """
261
+
262
+ # Create a scope object to hold all the context
263
+ scope = type("GenericScope", (), {})()
264
+ scope._response = response
265
+ scope._db_operation = db_operation
266
+ scope._server_address = server_address
267
+ scope._server_port = server_port
268
+ scope._start_time = start_time
269
+ scope._span = span
270
+ scope._kwargs = kwargs
271
+
272
+ # Process the response using common logic
273
+ common_milvus_logic(scope, environment, application_name,
274
+ metrics, capture_message_content, disable_metrics, version, instance)
275
+
276
+ return response