openlit 1.33.10__py3-none-any.whl → 1.33.12__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.
Files changed (113) hide show
  1. openlit/__helpers.py +125 -88
  2. openlit/__init__.py +38 -11
  3. openlit/instrumentation/ag2/__init__.py +19 -20
  4. openlit/instrumentation/ag2/ag2.py +134 -69
  5. openlit/instrumentation/ai21/__init__.py +22 -21
  6. openlit/instrumentation/ai21/ai21.py +82 -546
  7. openlit/instrumentation/ai21/async_ai21.py +82 -546
  8. openlit/instrumentation/ai21/utils.py +409 -0
  9. openlit/instrumentation/anthropic/__init__.py +16 -16
  10. openlit/instrumentation/anthropic/anthropic.py +61 -353
  11. openlit/instrumentation/anthropic/async_anthropic.py +62 -354
  12. openlit/instrumentation/anthropic/utils.py +251 -0
  13. openlit/instrumentation/assemblyai/__init__.py +2 -2
  14. openlit/instrumentation/assemblyai/assemblyai.py +3 -3
  15. openlit/instrumentation/astra/__init__.py +25 -25
  16. openlit/instrumentation/astra/astra.py +2 -2
  17. openlit/instrumentation/astra/async_astra.py +2 -2
  18. openlit/instrumentation/azure_ai_inference/__init__.py +5 -5
  19. openlit/instrumentation/azure_ai_inference/async_azure_ai_inference.py +8 -8
  20. openlit/instrumentation/azure_ai_inference/azure_ai_inference.py +8 -8
  21. openlit/instrumentation/bedrock/__init__.py +2 -2
  22. openlit/instrumentation/bedrock/bedrock.py +3 -3
  23. openlit/instrumentation/chroma/__init__.py +9 -9
  24. openlit/instrumentation/chroma/chroma.py +2 -2
  25. openlit/instrumentation/cohere/__init__.py +7 -7
  26. openlit/instrumentation/cohere/async_cohere.py +9 -9
  27. openlit/instrumentation/cohere/cohere.py +9 -9
  28. openlit/instrumentation/controlflow/__init__.py +4 -4
  29. openlit/instrumentation/controlflow/controlflow.py +2 -2
  30. openlit/instrumentation/crawl4ai/__init__.py +3 -3
  31. openlit/instrumentation/crawl4ai/async_crawl4ai.py +2 -2
  32. openlit/instrumentation/crawl4ai/crawl4ai.py +2 -2
  33. openlit/instrumentation/crewai/__init__.py +3 -3
  34. openlit/instrumentation/crewai/crewai.py +2 -2
  35. openlit/instrumentation/dynamiq/__init__.py +5 -5
  36. openlit/instrumentation/dynamiq/dynamiq.py +2 -2
  37. openlit/instrumentation/elevenlabs/__init__.py +5 -5
  38. openlit/instrumentation/elevenlabs/async_elevenlabs.py +3 -3
  39. openlit/instrumentation/elevenlabs/elevenlabs.py +3 -3
  40. openlit/instrumentation/embedchain/__init__.py +2 -2
  41. openlit/instrumentation/embedchain/embedchain.py +4 -4
  42. openlit/instrumentation/firecrawl/__init__.py +3 -3
  43. openlit/instrumentation/firecrawl/firecrawl.py +2 -2
  44. openlit/instrumentation/google_ai_studio/__init__.py +3 -3
  45. openlit/instrumentation/google_ai_studio/async_google_ai_studio.py +3 -3
  46. openlit/instrumentation/google_ai_studio/google_ai_studio.py +3 -3
  47. openlit/instrumentation/gpt4all/__init__.py +3 -3
  48. openlit/instrumentation/gpt4all/gpt4all.py +7 -7
  49. openlit/instrumentation/groq/__init__.py +3 -3
  50. openlit/instrumentation/groq/async_groq.py +5 -5
  51. openlit/instrumentation/groq/groq.py +5 -5
  52. openlit/instrumentation/haystack/__init__.py +2 -2
  53. openlit/instrumentation/haystack/haystack.py +2 -2
  54. openlit/instrumentation/julep/__init__.py +7 -7
  55. openlit/instrumentation/julep/async_julep.py +3 -3
  56. openlit/instrumentation/julep/julep.py +3 -3
  57. openlit/instrumentation/langchain/__init__.py +2 -2
  58. openlit/instrumentation/langchain/async_langchain.py +13 -9
  59. openlit/instrumentation/langchain/langchain.py +13 -8
  60. openlit/instrumentation/letta/__init__.py +7 -7
  61. openlit/instrumentation/letta/letta.py +5 -5
  62. openlit/instrumentation/litellm/__init__.py +5 -5
  63. openlit/instrumentation/litellm/async_litellm.py +8 -8
  64. openlit/instrumentation/litellm/litellm.py +8 -8
  65. openlit/instrumentation/llamaindex/__init__.py +2 -2
  66. openlit/instrumentation/llamaindex/llamaindex.py +2 -2
  67. openlit/instrumentation/mem0/__init__.py +2 -2
  68. openlit/instrumentation/mem0/mem0.py +2 -2
  69. openlit/instrumentation/milvus/__init__.py +2 -2
  70. openlit/instrumentation/milvus/milvus.py +2 -2
  71. openlit/instrumentation/mistral/__init__.py +7 -7
  72. openlit/instrumentation/mistral/async_mistral.py +10 -10
  73. openlit/instrumentation/mistral/mistral.py +10 -10
  74. openlit/instrumentation/multion/__init__.py +7 -7
  75. openlit/instrumentation/multion/async_multion.py +5 -5
  76. openlit/instrumentation/multion/multion.py +5 -5
  77. openlit/instrumentation/ollama/__init__.py +11 -9
  78. openlit/instrumentation/ollama/async_ollama.py +71 -465
  79. openlit/instrumentation/ollama/ollama.py +71 -465
  80. openlit/instrumentation/ollama/utils.py +332 -0
  81. openlit/instrumentation/openai/__init__.py +11 -11
  82. openlit/instrumentation/openai/async_openai.py +18 -18
  83. openlit/instrumentation/openai/openai.py +18 -18
  84. openlit/instrumentation/phidata/__init__.py +2 -2
  85. openlit/instrumentation/phidata/phidata.py +2 -2
  86. openlit/instrumentation/pinecone/__init__.py +6 -6
  87. openlit/instrumentation/pinecone/pinecone.py +2 -2
  88. openlit/instrumentation/premai/__init__.py +3 -3
  89. openlit/instrumentation/premai/premai.py +7 -7
  90. openlit/instrumentation/qdrant/__init__.py +2 -2
  91. openlit/instrumentation/qdrant/async_qdrant.py +2 -2
  92. openlit/instrumentation/qdrant/qdrant.py +2 -2
  93. openlit/instrumentation/reka/__init__.py +3 -3
  94. openlit/instrumentation/reka/async_reka.py +3 -3
  95. openlit/instrumentation/reka/reka.py +3 -3
  96. openlit/instrumentation/together/__init__.py +5 -5
  97. openlit/instrumentation/together/async_together.py +8 -8
  98. openlit/instrumentation/together/together.py +8 -8
  99. openlit/instrumentation/transformers/__init__.py +2 -2
  100. openlit/instrumentation/transformers/transformers.py +4 -4
  101. openlit/instrumentation/vertexai/__init__.py +9 -9
  102. openlit/instrumentation/vertexai/async_vertexai.py +4 -4
  103. openlit/instrumentation/vertexai/vertexai.py +4 -4
  104. openlit/instrumentation/vllm/__init__.py +2 -2
  105. openlit/instrumentation/vllm/vllm.py +3 -3
  106. openlit/otel/events.py +85 -0
  107. openlit/otel/tracing.py +3 -13
  108. openlit/semcov/__init__.py +13 -1
  109. {openlit-1.33.10.dist-info → openlit-1.33.12.dist-info}/METADATA +2 -2
  110. openlit-1.33.12.dist-info/RECORD +126 -0
  111. openlit-1.33.10.dist-info/RECORD +0 -122
  112. {openlit-1.33.10.dist-info → openlit-1.33.12.dist-info}/LICENSE +0 -0
  113. {openlit-1.33.10.dist-info → openlit-1.33.12.dist-info}/WHEEL +0 -0
openlit/__helpers.py CHANGED
@@ -11,6 +11,7 @@ import requests
11
11
  import tiktoken
12
12
  from opentelemetry.sdk.resources import SERVICE_NAME, TELEMETRY_SDK_NAME, DEPLOYMENT_ENVIRONMENT
13
13
  from opentelemetry.trace import Status, StatusCode
14
+ from opentelemetry._events import Event
14
15
  from openlit.semcov import SemanticConvetion
15
16
 
16
17
  # Set up logging
@@ -20,12 +21,13 @@ def response_as_dict(response):
20
21
  """
21
22
  Return parsed response as a dict
22
23
  """
24
+
23
25
  # pylint: disable=no-else-return
24
26
  if isinstance(response, dict):
25
27
  return response
26
- if hasattr(response, "model_dump"):
28
+ if hasattr(response, 'model_dump'):
27
29
  return response.model_dump()
28
- elif hasattr(response, "parse"):
30
+ elif hasattr(response, 'parse'):
29
31
  return response_as_dict(response.parse())
30
32
  else:
31
33
  return response
@@ -33,8 +35,8 @@ def response_as_dict(response):
33
35
  def get_env_variable(name, arg_value, error_message):
34
36
  """
35
37
  Retrieve an environment variable if the argument is not provided
36
- and raise an error if both are not set.
37
38
  """
39
+
38
40
  if arg_value is not None:
39
41
  return arg_value
40
42
  value = os.getenv(name)
@@ -46,14 +48,8 @@ def get_env_variable(name, arg_value, error_message):
46
48
  def openai_tokens(text, model):
47
49
  """
48
50
  Calculate the number of tokens a given text would take up for a specified model.
49
-
50
- Args:
51
- text (str): The input text to be encoded.
52
- model (str): The model identifier used for encoding.
53
-
54
- Returns:
55
- int: The number of tokens the text is encoded into.
56
51
  """
52
+
57
53
  try:
58
54
  encoding = tiktoken.encoding_for_model(model)
59
55
  except:
@@ -65,16 +61,9 @@ def openai_tokens(text, model):
65
61
  def general_tokens(text):
66
62
  """
67
63
  Calculate the number of tokens a given text would take up.
68
-
69
- Args:
70
- text (str): The input text to be encoded.
71
- model (str): The model identifier used for encoding.
72
-
73
- Returns:
74
- int: The number of tokens the text is encoded into.
75
64
  """
76
65
 
77
- encoding = tiktoken.get_encoding("gpt2")
66
+ encoding = tiktoken.get_encoding('gpt2')
78
67
 
79
68
  num_tokens = len(encoding.encode(text))
80
69
  return num_tokens
@@ -82,19 +71,11 @@ def general_tokens(text):
82
71
  def get_chat_model_cost(model, pricing_info, prompt_tokens, completion_tokens):
83
72
  """
84
73
  Retrieve the cost of processing for a given model based on prompt and tokens.
85
-
86
- Args:
87
- model (str): The model identifier.
88
- pricing_info (dict): A dictionary containing pricing information for various models.
89
- prompt_tokens (int): Number of tokens in the prompt.
90
- completion_tokens (int): Number of tokens in the completion if applicable.
91
-
92
- Returns:
93
- float: The calculated cost for the operation.
94
74
  """
75
+
95
76
  try:
96
- cost = ((prompt_tokens / 1000) * pricing_info["chat"][model]["promptPrice"]) + \
97
- ((completion_tokens / 1000) * pricing_info["chat"][model]["completionPrice"])
77
+ cost = ((prompt_tokens / 1000) * pricing_info['chat'][model]['promptPrice']) + \
78
+ ((completion_tokens / 1000) * pricing_info['chat'][model]['completionPrice'])
98
79
  except:
99
80
  cost = 0
100
81
  return cost
@@ -102,17 +83,10 @@ def get_chat_model_cost(model, pricing_info, prompt_tokens, completion_tokens):
102
83
  def get_embed_model_cost(model, pricing_info, prompt_tokens):
103
84
  """
104
85
  Retrieve the cost of processing for a given model based on prompt tokens.
105
-
106
- Args:
107
- model (str): The model identifier.
108
- pricing_info (dict): A dictionary containing pricing information for various models.
109
- prompt_tokens (int): Number of tokens in the prompt.
110
-
111
- Returns:
112
- float: The calculated cost for the operation.
113
86
  """
87
+
114
88
  try:
115
- cost = (prompt_tokens / 1000) * pricing_info["embeddings"][model]
89
+ cost = (prompt_tokens / 1000) * pricing_info['embeddings'][model]
116
90
  except:
117
91
  cost = 0
118
92
  return cost
@@ -120,18 +94,10 @@ def get_embed_model_cost(model, pricing_info, prompt_tokens):
120
94
  def get_image_model_cost(model, pricing_info, size, quality):
121
95
  """
122
96
  Retrieve the cost of processing for a given model based on image size and quailty.
123
-
124
- Args:
125
- model (str): The model identifier.
126
- pricing_info (dict): A dictionary containing pricing information for various models.
127
- size (str): Size of the Image.
128
- quality (int): Quality of the Image.
129
-
130
- Returns:
131
- float: The calculated cost for the operation.
132
97
  """
98
+
133
99
  try:
134
- cost = pricing_info["images"][model][quality][size]
100
+ cost = pricing_info['images'][model][quality][size]
135
101
  except:
136
102
  cost = 0
137
103
  return cost
@@ -139,20 +105,13 @@ def get_image_model_cost(model, pricing_info, size, quality):
139
105
  def get_audio_model_cost(model, pricing_info, prompt, duration=None):
140
106
  """
141
107
  Retrieve the cost of processing for a given model based on prompt.
142
-
143
- Args:
144
- model (str): The model identifier.
145
- pricing_info (dict): A dictionary containing pricing information for various models.
146
- prompt (str): Prompt to the LLM Model
147
-
148
- Returns:
149
- float: The calculated cost for the operation.
150
108
  """
109
+
151
110
  try:
152
111
  if prompt:
153
- cost = (len(prompt) / 1000) * pricing_info["audio"][model]
112
+ cost = (len(prompt) / 1000) * pricing_info['audio'][model]
154
113
  else:
155
- cost = duration * pricing_info["audio"][model]
114
+ cost = duration * pricing_info['audio'][model]
156
115
  except:
157
116
  cost = 0
158
117
  return cost
@@ -160,15 +119,10 @@ def get_audio_model_cost(model, pricing_info, prompt, duration=None):
160
119
  def fetch_pricing_info(pricing_json=None):
161
120
  """
162
121
  Fetches pricing information from a specified URL or File Path.
163
-
164
- Args:
165
- pricing_json(str): path or url to the pricing json file
166
-
167
- Returns:
168
- dict: The pricing json
169
122
  """
123
+
170
124
  if pricing_json:
171
- is_url = urlparse(pricing_json).scheme != ""
125
+ is_url = urlparse(pricing_json).scheme != ''
172
126
  if is_url:
173
127
  pricing_url = pricing_json
174
128
  else:
@@ -176,39 +130,36 @@ def fetch_pricing_info(pricing_json=None):
176
130
  with open(pricing_json, mode='r', encoding='utf-8') as f:
177
131
  return json.load(f)
178
132
  except FileNotFoundError:
179
- logger.error("Pricing information file not found: %s", pricing_json)
133
+ logger.error('Pricing information file not found: %s', pricing_json)
180
134
  except json.JSONDecodeError:
181
- logger.error("Error decoding JSON from file: %s", pricing_json)
135
+ logger.error('Error decoding JSON from file: %s', pricing_json)
182
136
  except Exception as file_err:
183
- logger.error("Unexpected error occurred while reading file: %s", file_err)
137
+ logger.error('Unexpected error occurred while reading file: %s', file_err)
184
138
  return {}
185
139
  else:
186
- pricing_url = "https://raw.githubusercontent.com/openlit/openlit/main/assets/pricing.json"
140
+ pricing_url = 'https://raw.githubusercontent.com/openlit/openlit/main/assets/pricing.json'
187
141
  try:
188
142
  # Set a timeout of 10 seconds for both the connection and the read
189
143
  response = requests.get(pricing_url, timeout=20)
190
144
  response.raise_for_status()
191
145
  return response.json()
192
146
  except requests.HTTPError as http_err:
193
- logger.error("HTTP error occured while fetching pricing info: %s", http_err)
147
+ logger.error('HTTP error occured while fetching pricing info: %s', http_err)
194
148
  except Exception as err:
195
- logger.error("Unexpected error occurred while fetching pricing info: %s", err)
149
+ logger.error('Unexpected error occurred while fetching pricing info: %s', err)
196
150
  return {}
197
151
 
198
152
  def handle_exception(span,e):
199
153
  """Handles Exception when LLM Function fails or trace creation fails."""
200
- # Record the exception details within the span
154
+
201
155
  span.record_exception(e)
202
156
  span.set_status(Status(StatusCode.ERROR))
203
157
 
204
158
  def calculate_ttft(timestamps: List[float], start_time: float) -> float:
205
159
  """
206
160
  Calculate the time to the first tokens.
207
-
208
- :param timestamps: List of timestamps for received tokens
209
- :param start_time: The start time of the streaming process
210
- :return: Time to the first tokens
211
161
  """
162
+
212
163
  if timestamps:
213
164
  return timestamps[0] - start_time
214
165
  return 0.0
@@ -216,10 +167,8 @@ def calculate_ttft(timestamps: List[float], start_time: float) -> float:
216
167
  def calculate_tbt(timestamps: List[float]) -> float:
217
168
  """
218
169
  Calculate the average time between tokens.
219
-
220
- :param timestamps: List of timestamps for received tokens
221
- :return: Average time between tokens
222
170
  """
171
+
223
172
  if len(timestamps) > 1:
224
173
  time_diffs = [timestamps[i] - timestamps[i - 1] for i in range(1, len(timestamps))]
225
174
  return sum(time_diffs) / len(time_diffs)
@@ -238,8 +187,9 @@ def create_metrics_attributes(
238
187
  """
239
188
  Returns OTel metrics attributes
240
189
  """
190
+
241
191
  return {
242
- TELEMETRY_SDK_NAME: "openlit",
192
+ TELEMETRY_SDK_NAME: 'openlit',
243
193
  SERVICE_NAME: service_name,
244
194
  DEPLOYMENT_ENVIRONMENT: deployment_environment,
245
195
  SemanticConvetion.GEN_AI_OPERATION: operation,
@@ -258,18 +208,18 @@ def set_server_address_and_port(client_instance: Any,
258
208
  """
259
209
 
260
210
  # Try getting base_url from multiple potential attributes
261
- base_client = getattr(client_instance, "_client", None)
262
- base_url = getattr(base_client, "base_url", None)
211
+ base_client = getattr(client_instance, '_client', None)
212
+ base_url = getattr(base_client, 'base_url', None)
263
213
 
264
214
  if not base_url:
265
215
  # Attempt to get endpoint from instance._config.endpoint if base_url is not set
266
- config = getattr(client_instance, "_config", None)
267
- base_url = getattr(config, "endpoint", None)
216
+ config = getattr(client_instance, '_config', None)
217
+ base_url = getattr(config, 'endpoint', None)
268
218
 
269
219
  if not base_url:
270
220
  # Attempt to get server_url from instance.sdk_configuration.server_url
271
- config = getattr(client_instance, "sdk_configuration", None)
272
- base_url = getattr(config, "server_url", None)
221
+ config = getattr(client_instance, 'sdk_configuration', None)
222
+ base_url = getattr(config, 'server_url', None)
273
223
 
274
224
  if base_url:
275
225
  if isinstance(base_url, str):
@@ -277,11 +227,98 @@ def set_server_address_and_port(client_instance: Any,
277
227
  server_address = url.hostname or default_server_address
278
228
  server_port = url.port if url.port is not None else default_server_port
279
229
  else: # base_url might not be a str; handle as an object.
280
- server_address = getattr(base_url, "host", None) or default_server_address
281
- port_attr = getattr(base_url, "port", None)
230
+ server_address = getattr(base_url, 'host', None) or default_server_address
231
+ port_attr = getattr(base_url, 'port', None)
282
232
  server_port = port_attr if port_attr is not None else default_server_port
283
233
  else: # no base_url or endpoint provided; use defaults.
284
234
  server_address = default_server_address
285
235
  server_port = default_server_port
286
236
 
287
237
  return server_address, server_port
238
+
239
+ def otel_event(name, attributes, body):
240
+ """
241
+ Returns an OpenTelemetry Event object
242
+ """
243
+
244
+ return Event(
245
+ name=name,
246
+ attributes=attributes,
247
+ body=body,
248
+ )
249
+
250
+ def extract_and_format_input(messages):
251
+ """
252
+ Process a list of messages to extract content and categorize
253
+ them into fixed roles like 'user', 'assistant', 'system', 'tool'.
254
+ """
255
+
256
+ fixed_roles = ['user', 'assistant', 'system', 'tool'] # Ensure these are your fixed keys
257
+ # Initialize the dictionary with fixed keys and empty structures
258
+ formatted_messages = {role_key: {'role': '', 'content': ''} for role_key in fixed_roles}
259
+
260
+ for message in messages:
261
+ # Normalize the message structure
262
+ message = response_as_dict(message)
263
+
264
+ # Extract role and content
265
+ role = message.get('role')
266
+ if role not in fixed_roles:
267
+ continue # Skip any role not in our predefined roles
268
+
269
+ content = message.get('content', '')
270
+
271
+ # Prepare content as a string
272
+ if isinstance(content, list):
273
+ content_str = ", ".join(
274
+ f'{item.get("type", "text")}: {extract_text_from_item(item)}'
275
+ for item in content
276
+ )
277
+ else:
278
+ content_str = content
279
+
280
+ # Set the role in the formatted message and concatenate content
281
+ if not formatted_messages[role]['role']:
282
+ formatted_messages[role]['role'] = role
283
+
284
+ if formatted_messages[role]['content']:
285
+ formatted_messages[role]['content'] += ' ' + content_str
286
+ else:
287
+ formatted_messages[role]['content'] = content_str
288
+
289
+ return formatted_messages
290
+
291
+ def extract_text_from_item(item):
292
+ """
293
+ Extract text from inpit message
294
+ """
295
+
296
+ #pylint: disable=no-else-return
297
+ if item.get('type') == 'text':
298
+ return item.get('text', '')
299
+ elif item.get('type') == 'image':
300
+ # Handle image content specifically checking for 'url' or 'base64'
301
+ source = item.get('source', {})
302
+ if isinstance(source, dict):
303
+ if source.get('type') == 'base64':
304
+ # Return the actual base64 data if present
305
+ return source.get('data', '[Missing base64 data]')
306
+ elif source.get('type') == 'url':
307
+ return source.get('url', '[Missing URL]')
308
+ elif item.get('type') == 'image_url':
309
+ # New format: Handle the 'image_url' type
310
+ image_url = item.get('image_url', {})
311
+ if isinstance(image_url, dict):
312
+ return image_url.get('url', '[Missing image URL]')
313
+ return ''
314
+
315
+ # To be removed one the change to log events (from span events) is complete
316
+ def concatenate_all_contents(formatted_messages):
317
+ """
318
+ Concatenate all 'content' fields into a single strin
319
+ """
320
+ return ' '.join(
321
+ message_data['content']
322
+ for message_data in formatted_messages.values()
323
+ if message_data['content']
324
+ )
openlit/__init__.py CHANGED
@@ -21,9 +21,9 @@ from opentelemetry.sdk.resources import SERVICE_NAME, DEPLOYMENT_ENVIRONMENT
21
21
  from openlit.semcov import SemanticConvetion
22
22
  from openlit.otel.tracing import setup_tracing
23
23
  from openlit.otel.metrics import setup_meter
24
+ from openlit.otel.events import setup_events
24
25
  from openlit.__helpers import fetch_pricing_info, get_env_variable
25
26
 
26
-
27
27
  # Instrumentors for various large language models.
28
28
  from openlit.instrumentation.openai import OpenAIInstrumentor
29
29
  from openlit.instrumentation.anthropic import AnthropicInstrumentor
@@ -85,10 +85,11 @@ class OpenlitConfig:
85
85
  application_name (str): Name of the application using openLIT.
86
86
  pricing_info (Dict[str, Any]): Pricing information.
87
87
  tracer (Optional[Any]): Tracer instance for OpenTelemetry.
88
+ event_provider (Optional[Any]): Event logger provider for OpenTelemetry.
88
89
  otlp_endpoint (Optional[str]): Endpoint for OTLP.
89
90
  otlp_headers (Optional[Dict[str, str]]): Headers for OTLP.
90
91
  disable_batch (bool): Flag to disable batch span processing in tracing.
91
- trace_content (bool): Flag to enable or disable tracing of content.
92
+ capture_message_content (bool): Flag to enable or disable tracing of content.
92
93
  """
93
94
 
94
95
  _instance = None
@@ -107,11 +108,12 @@ class OpenlitConfig:
107
108
  cls.application_name = "default"
108
109
  cls.pricing_info = {}
109
110
  cls.tracer = None
111
+ cls.event_provider = None
110
112
  cls.metrics_dict = {}
111
113
  cls.otlp_endpoint = None
112
114
  cls.otlp_headers = None
113
115
  cls.disable_batch = False
114
- cls.trace_content = True
116
+ cls.capture_message_content = True
115
117
  cls.disable_metrics = False
116
118
 
117
119
  @classmethod
@@ -120,10 +122,11 @@ class OpenlitConfig:
120
122
  environment,
121
123
  application_name,
122
124
  tracer,
125
+ event_provider,
123
126
  otlp_endpoint,
124
127
  otlp_headers,
125
128
  disable_batch,
126
- trace_content,
129
+ capture_message_content,
127
130
  metrics_dict,
128
131
  disable_metrics,
129
132
  pricing_json,
@@ -135,22 +138,26 @@ class OpenlitConfig:
135
138
  environment (str): Deployment environment.
136
139
  application_name (str): Application name.
137
140
  tracer: Tracer instance.
141
+ event_provider: Event logger provider instance.
138
142
  meter: Metric Instance
139
143
  otlp_endpoint (str): OTLP endpoint.
140
144
  otlp_headers (Dict[str, str]): OTLP headers.
141
145
  disable_batch (bool): Disable batch span processing flag.
142
- trace_content (bool): Enable or disable content tracing.
146
+ capture_message_content (bool): Enable or disable content tracing.
147
+ metrics_dict: Dictionary of metrics.
148
+ disable_metrics (bool): Flag to disable metrics.
143
149
  pricing_json(str): path or url to the pricing json file
144
150
  """
145
151
  cls.environment = environment
146
152
  cls.application_name = application_name
147
153
  cls.pricing_info = fetch_pricing_info(pricing_json)
148
154
  cls.tracer = tracer
155
+ cls.event_provider = event_provider
149
156
  cls.metrics_dict = metrics_dict
150
157
  cls.otlp_endpoint = otlp_endpoint
151
158
  cls.otlp_headers = otlp_headers
152
159
  cls.disable_batch = disable_batch
153
- cls.trace_content = trace_content
160
+ cls.capture_message_content = capture_message_content
154
161
  cls.disable_metrics = disable_metrics
155
162
 
156
163
 
@@ -187,8 +194,9 @@ def instrument_if_available(
187
194
  environment=config.environment,
188
195
  application_name=config.application_name,
189
196
  tracer=config.tracer,
197
+ event_provider=config.event_provider,
190
198
  pricing_info=config.pricing_info,
191
- trace_content=config.trace_content,
199
+ capture_message_content=config.capture_message_content,
192
200
  metrics_dict=config.metrics_dict,
193
201
  disable_metrics=config.disable_metrics,
194
202
  )
@@ -207,10 +215,11 @@ def init(
207
215
  environment="default",
208
216
  application_name="default",
209
217
  tracer=None,
218
+ event_logger=None,
210
219
  otlp_endpoint=None,
211
220
  otlp_headers=None,
212
221
  disable_batch=False,
213
- trace_content=True,
222
+ capture_message_content=True,
214
223
  disabled_instrumentors=None,
215
224
  meter=None,
216
225
  disable_metrics=False,
@@ -227,11 +236,12 @@ def init(
227
236
  environment (str): Deployment environment.
228
237
  application_name (str): Application name.
229
238
  tracer: Tracer instance (Optional).
239
+ event_logger: EventLoggerProvider instance (Optional).
230
240
  meter: OpenTelemetry Metrics Instance (Optional).
231
241
  otlp_endpoint (str): OTLP endpoint for exporter (Optional).
232
242
  otlp_headers (Dict[str, str]): OTLP headers for exporter (Optional).
233
243
  disable_batch (bool): Flag to disable batch span processing (Optional).
234
- trace_content (bool): Flag to trace content (Optional).
244
+ capture_message_content (bool): Flag to trace content (Optional).
235
245
  disabled_instrumentors (List[str]): Optional. List of instrumentor names to disable.
236
246
  disable_metrics (bool): Flag to disable metrics (Optional).
237
247
  pricing_json(str): File path or url to the pricing json (Optional).
@@ -308,9 +318,22 @@ def init(
308
318
  )
309
319
 
310
320
  if not tracer:
311
- logger.error("openLIT tracing setup failed. Tracing will not be available.")
321
+ logger.error("OpenLIT tracing setup failed. Tracing will not be available.")
312
322
  return
313
323
 
324
+ # Setup events based on the provided or default configuration.
325
+ event_provider = setup_events(
326
+ application_name=application_name,
327
+ environment=environment,
328
+ event_logger=event_logger,
329
+ otlp_endpoint=None,
330
+ otlp_headers=None,
331
+ disable_batch=disable_batch,
332
+ )
333
+
334
+ if not event_provider:
335
+ logger.error("OpenLIT events setup failed. Events will not be available")
336
+
314
337
  # Setup meter and receive metrics_dict instead of meter.
315
338
  metrics_dict, err = setup_meter(
316
339
  application_name=application_name,
@@ -326,15 +349,19 @@ def init(
326
349
  )
327
350
  return
328
351
 
352
+ if os.getenv("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", "").lower == "false":
353
+ capture_message_content=False
354
+
329
355
  # Update global configuration with the provided settings.
330
356
  config.update_config(
331
357
  environment,
332
358
  application_name,
333
359
  tracer,
360
+ event_provider,
334
361
  otlp_endpoint,
335
362
  otlp_headers,
336
363
  disable_batch,
337
- trace_content,
364
+ capture_message_content,
338
365
  metrics_dict,
339
366
  disable_metrics,
340
367
  pricing_json,
@@ -1,4 +1,3 @@
1
- # pylint: disable=useless-return, bad-staticmethod-argument, disable=duplicate-code
2
1
  """Initializer of Auto Instrumentation of AG2 Functions"""
3
2
 
4
3
  from typing import Collection
@@ -7,10 +6,10 @@ from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
7
6
  from wrapt import wrap_function_wrapper
8
7
 
9
8
  from openlit.instrumentation.ag2.ag2 import (
10
- wrap_ag2
9
+ conversable_agent, agent_run
11
10
  )
12
11
 
13
- _instruments = ("ag2 >= 0.3.2",)
12
+ _instruments = ('ag2 >= 0.3.2',)
14
13
 
15
14
  class AG2Instrumentor(BaseInstrumentor):
16
15
  """
@@ -21,30 +20,30 @@ class AG2Instrumentor(BaseInstrumentor):
21
20
  return _instruments
22
21
 
23
22
  def _instrument(self, **kwargs):
24
- application_name = kwargs.get("application_name", "default_application")
25
- environment = kwargs.get("environment", "default_environment")
26
- tracer = kwargs.get("tracer")
27
- metrics = kwargs.get("metrics_dict")
28
- pricing_info = kwargs.get("pricing_info", {})
29
- trace_content = kwargs.get("trace_content", False)
30
- disable_metrics = kwargs.get("disable_metrics")
31
- version = importlib.metadata.version("ag2")
23
+ application_name = kwargs.get('application_name', 'default_application')
24
+ environment = kwargs.get('environment', 'default_environment')
25
+ tracer = kwargs.get('tracer')
26
+ event_provider = kwargs.get('event_provider')
27
+ metrics = kwargs.get('metrics_dict')
28
+ pricing_info = kwargs.get('pricing_info', {})
29
+ capture_message_content = kwargs.get('capture_message_content', False)
30
+ disable_metrics = kwargs.get('disable_metrics')
31
+ version = importlib.metadata.version('ag2')
32
32
 
33
33
  wrap_function_wrapper(
34
- "autogen.agentchat.conversable_agent",
35
- "ConversableAgent.initiate_chat",
36
- wrap_ag2("ag2.initiate_chat", version, environment, application_name,
37
- tracer, pricing_info, trace_content, metrics, disable_metrics),
34
+ 'autogen.agentchat.conversable_agent',
35
+ 'ConversableAgent.__init__',
36
+ conversable_agent(version, environment, application_name,
37
+ tracer, event_provider, pricing_info, capture_message_content, metrics, disable_metrics),
38
38
  )
39
39
 
40
40
  wrap_function_wrapper(
41
- "autogen.agentchat.conversable_agent",
42
- "ConversableAgent.generate_reply",
43
- wrap_ag2("ag2.generate_reply", version, environment, application_name,
44
- tracer, pricing_info, trace_content, metrics, disable_metrics),
41
+ 'autogen.agentchat.conversable_agent',
42
+ 'ConversableAgent.run',
43
+ agent_run(version, environment, application_name,
44
+ tracer, event_provider, pricing_info, capture_message_content, metrics, disable_metrics),
45
45
  )
46
46
 
47
-
48
47
  def _uninstrument(self, **kwargs):
49
48
  # Proper uninstrumentation logic to revert patched methods
50
49
  pass