lmnr 0.5.2__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. lmnr/__init__.py +7 -2
  2. lmnr/cli.py +10 -8
  3. lmnr/opentelemetry_lib/__init__.py +55 -0
  4. lmnr/{openllmetry_sdk/decorators/base.py → opentelemetry_lib/decorators/__init__.py} +24 -15
  5. lmnr/{openllmetry_sdk → opentelemetry_lib}/opentelemetry/instrumentation/google_genai/utils.py +1 -1
  6. lmnr/opentelemetry_lib/tracing/__init__.py +139 -0
  7. lmnr/opentelemetry_lib/tracing/_instrument_initializers.py +398 -0
  8. lmnr/{openllmetry_sdk → opentelemetry_lib}/tracing/attributes.py +14 -7
  9. lmnr/opentelemetry_lib/tracing/context_properties.py +53 -0
  10. lmnr/opentelemetry_lib/tracing/exporter.py +60 -0
  11. lmnr/opentelemetry_lib/tracing/instruments.py +121 -0
  12. lmnr/opentelemetry_lib/tracing/processor.py +96 -0
  13. lmnr/{openllmetry_sdk/tracing/context_manager.py → opentelemetry_lib/tracing/tracer.py} +6 -1
  14. lmnr/{openllmetry_sdk → opentelemetry_lib}/utils/package_check.py +3 -1
  15. lmnr/sdk/browser/browser_use_otel.py +20 -3
  16. lmnr/sdk/browser/patchright_otel.py +177 -0
  17. lmnr/sdk/browser/playwright_otel.py +16 -7
  18. lmnr/sdk/browser/pw_utils.py +116 -74
  19. lmnr/sdk/browser/rrweb/rrweb.umd.min.cjs +98 -0
  20. lmnr/sdk/client/asynchronous/resources/agent.py +22 -1
  21. lmnr/sdk/client/synchronous/resources/agent.py +23 -1
  22. lmnr/sdk/decorators.py +5 -3
  23. lmnr/sdk/eval_control.py +3 -2
  24. lmnr/sdk/evaluations.py +10 -16
  25. lmnr/sdk/laminar.py +16 -34
  26. lmnr/sdk/types.py +2 -0
  27. lmnr/sdk/utils.py +2 -3
  28. lmnr/version.py +1 -1
  29. {lmnr-0.5.2.dist-info → lmnr-0.6.0.dist-info}/METADATA +65 -63
  30. lmnr-0.6.0.dist-info/RECORD +54 -0
  31. {lmnr-0.5.2.dist-info → lmnr-0.6.0.dist-info}/WHEEL +1 -1
  32. lmnr/openllmetry_sdk/__init__.py +0 -75
  33. lmnr/openllmetry_sdk/config/__init__.py +0 -12
  34. lmnr/openllmetry_sdk/decorators/__init__.py +0 -0
  35. lmnr/openllmetry_sdk/instruments.py +0 -41
  36. lmnr/openllmetry_sdk/tracing/__init__.py +0 -1
  37. lmnr/openllmetry_sdk/tracing/content_allow_list.py +0 -24
  38. lmnr/openllmetry_sdk/tracing/tracing.py +0 -998
  39. lmnr/openllmetry_sdk/utils/in_memory_span_exporter.py +0 -61
  40. lmnr/sdk/browser/rrweb/rrweb.min.js +0 -18
  41. lmnr-0.5.2.dist-info/RECORD +0 -54
  42. /lmnr/{openllmetry_sdk → opentelemetry_lib}/.flake8 +0 -0
  43. /lmnr/{openllmetry_sdk → opentelemetry_lib}/opentelemetry/instrumentation/google_genai/__init__.py +0 -0
  44. /lmnr/{openllmetry_sdk → opentelemetry_lib}/opentelemetry/instrumentation/google_genai/config.py +0 -0
  45. /lmnr/{openllmetry_sdk → opentelemetry_lib}/utils/__init__.py +0 -0
  46. /lmnr/{openllmetry_sdk → opentelemetry_lib}/utils/json_encoder.py +0 -0
  47. {lmnr-0.5.2.dist-info → lmnr-0.6.0.dist-info}/LICENSE +0 -0
  48. {lmnr-0.5.2.dist-info → lmnr-0.6.0.dist-info}/entry_points.txt +0 -0
@@ -1,998 +0,0 @@
1
- import atexit
2
- import copy
3
- import logging
4
- import uuid
5
-
6
- from contextvars import Context
7
- from lmnr.sdk.client.asynchronous.async_client import AsyncLaminarClient
8
- from lmnr.sdk.client.synchronous.sync_client import LaminarClient
9
- from lmnr.sdk.log import VerboseColorfulFormatter
10
- from lmnr.openllmetry_sdk.instruments import Instruments
11
- from lmnr.openllmetry_sdk.tracing.attributes import (
12
- ASSOCIATION_PROPERTIES,
13
- SPAN_IDS_PATH,
14
- SPAN_INSTRUMENTATION_SOURCE,
15
- SPAN_SDK_VERSION,
16
- SPAN_LANGUAGE_VERSION,
17
- SPAN_PATH,
18
- TRACING_LEVEL,
19
- )
20
- from lmnr.openllmetry_sdk.tracing.content_allow_list import ContentAllowList
21
- from lmnr.openllmetry_sdk.utils import is_notebook
22
- from lmnr.openllmetry_sdk.utils.package_check import is_package_installed
23
- from opentelemetry import trace
24
- from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
25
- OTLPSpanExporter as HTTPExporter,
26
- )
27
- from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
28
- OTLPSpanExporter as GRPCExporter,
29
- )
30
- from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import Compression
31
- from opentelemetry.instrumentation.threading import ThreadingInstrumentor
32
- from opentelemetry.context import get_value, attach, get_current, set_value
33
- from opentelemetry.propagate import set_global_textmap
34
- from opentelemetry.propagators.textmap import TextMapPropagator
35
- from opentelemetry.sdk.resources import Resource
36
- from opentelemetry.sdk.trace import TracerProvider, SpanProcessor, Span
37
- from opentelemetry.sdk.trace.export import (
38
- SpanExporter,
39
- SimpleSpanProcessor,
40
- BatchSpanProcessor,
41
- )
42
- from opentelemetry.trace import get_tracer_provider, ProxyTracerProvider
43
-
44
- from typing import Dict, Optional, Set
45
-
46
- from lmnr.version import __version__, PYTHON_VERSION
47
-
48
- module_logger = logging.getLogger(__name__)
49
- console_log_handler = logging.StreamHandler()
50
- console_log_handler.setFormatter(VerboseColorfulFormatter())
51
- module_logger.addHandler(console_log_handler)
52
-
53
-
54
- TRACER_NAME = "lmnr.tracer"
55
- EXCLUDED_URLS = """
56
- iam.cloud.ibm.com,
57
- dataplatform.cloud.ibm.com,
58
- ml.cloud.ibm.com,
59
- api.openai.com,
60
- openai.azure.com,
61
- api.anthropic.com,
62
- api.cohere.ai,
63
- pinecone.io,
64
- api.lmnr.ai,
65
- posthog.com,
66
- sentry.io,
67
- bedrock-runtime,
68
- sagemaker-runtime,
69
- googleapis.com,
70
- githubusercontent.com,
71
- openaipublic.blob.core.windows.net"""
72
-
73
- MAX_EVENTS_OR_ATTRIBUTES_PER_SPAN = 5000
74
-
75
-
76
- class TracerWrapper(object):
77
- resource_attributes: dict = {}
78
- enable_content_tracing: bool = True
79
- endpoint: str = None
80
- headers: Dict[str, str] = {}
81
- __tracer_provider: TracerProvider = None
82
- __logger: logging.Logger = None
83
- __span_id_to_path: dict[int, list[str]] = {}
84
- __span_id_lists: dict[int, list[str]] = {}
85
- __client: LaminarClient = None
86
- __async_client: AsyncLaminarClient = None
87
- __spans_processor: SpanProcessor = None
88
- __spans_exporter: SpanExporter = None
89
-
90
- def __new__(
91
- cls,
92
- disable_batch=False,
93
- processor: Optional[SpanProcessor] = None,
94
- propagator: Optional[TextMapPropagator] = None,
95
- exporter: Optional[SpanExporter] = None,
96
- should_enrich_metrics: bool = False,
97
- instruments: Optional[Set[Instruments]] = None,
98
- base_http_url: Optional[str] = None,
99
- project_api_key: Optional[str] = None,
100
- max_export_batch_size: Optional[int] = None,
101
- ) -> "TracerWrapper":
102
- cls._initialize_logger(cls)
103
- if not hasattr(cls, "instance"):
104
- obj = cls.instance = super(TracerWrapper, cls).__new__(cls)
105
- if not TracerWrapper.endpoint:
106
- return obj
107
-
108
- obj.__client = LaminarClient(
109
- base_url=base_http_url,
110
- project_api_key=project_api_key,
111
- )
112
- obj.__async_client = AsyncLaminarClient(
113
- base_url=base_http_url,
114
- project_api_key=project_api_key,
115
- )
116
-
117
- obj.__resource = Resource(attributes=TracerWrapper.resource_attributes)
118
- obj.__tracer_provider = init_tracer_provider(resource=obj.__resource)
119
- if processor:
120
- obj.__spans_processor = processor
121
- obj.__spans_processor_original_on_start = processor.on_start
122
- else:
123
- obj.__spans_exporter = (
124
- exporter
125
- if exporter
126
- else init_spans_exporter(
127
- TracerWrapper.endpoint, TracerWrapper.headers
128
- )
129
- )
130
- if disable_batch or is_notebook():
131
- obj.__spans_processor = SimpleSpanProcessor(obj.__spans_exporter)
132
- else:
133
- obj.__spans_processor = BatchSpanProcessor(
134
- obj.__spans_exporter,
135
- max_export_batch_size=max_export_batch_size,
136
- )
137
- obj.__spans_processor_original_on_start = None
138
-
139
- obj.__spans_processor.on_start = obj._span_processor_on_start
140
- obj.__tracer_provider.add_span_processor(obj.__spans_processor)
141
-
142
- if propagator:
143
- set_global_textmap(propagator)
144
-
145
- # this makes sure otel context is propagated so we always want it
146
- ThreadingInstrumentor().instrument()
147
-
148
- instrument_set = init_instrumentations(
149
- should_enrich_metrics,
150
- instruments,
151
- client=obj.__client,
152
- async_client=obj.__async_client,
153
- )
154
-
155
- if not instrument_set:
156
- cls.__logger.info(
157
- "No instruments set through Laminar. "
158
- "Only enabling basic OpenTelemetry tracing."
159
- )
160
-
161
- obj.__content_allow_list = ContentAllowList()
162
-
163
- # Force flushes for debug environments (e.g. local development)
164
- atexit.register(obj.exit_handler)
165
-
166
- return cls.instance
167
-
168
- def exit_handler(self):
169
- self.__span_id_to_path = {}
170
- self.flush()
171
-
172
- def _initialize_logger(self):
173
- self.__logger = logging.getLogger(__name__)
174
- console_log_handler = logging.StreamHandler()
175
- console_log_handler.setFormatter(VerboseColorfulFormatter())
176
- self.__logger.addHandler(console_log_handler)
177
-
178
- def _span_processor_on_start(
179
- self, span: Span, parent_context: Optional[Context] = None
180
- ):
181
- span_path_in_context = get_value("span_path", parent_context or get_current())
182
- span_path_in_context = None
183
- parent_span_path = span_path_in_context or (
184
- self.__span_id_to_path.get(span.parent.span_id) if span.parent else None
185
- )
186
- parent_span_ids_path = (
187
- self.__span_id_lists.get(span.parent.span_id, []) if span.parent else []
188
- )
189
- span_path = parent_span_path + [span.name] if parent_span_path else [span.name]
190
- span_ids_path = parent_span_ids_path + [
191
- str(uuid.UUID(int=span.get_span_context().span_id))
192
- ]
193
- span.set_attribute(SPAN_PATH, span_path)
194
- span.set_attribute(SPAN_IDS_PATH, span_ids_path)
195
- set_value("span_path", span_path, get_current())
196
- self.__span_id_to_path[span.get_span_context().span_id] = span_path
197
- self.__span_id_lists[span.get_span_context().span_id] = span_ids_path
198
-
199
- span.set_attribute(SPAN_INSTRUMENTATION_SOURCE, "python")
200
- span.set_attribute(SPAN_SDK_VERSION, __version__)
201
- span.set_attribute(SPAN_LANGUAGE_VERSION, f"python@{PYTHON_VERSION}")
202
-
203
- association_properties = get_value("association_properties")
204
- if association_properties is not None:
205
- _set_association_properties_attributes(span, association_properties)
206
-
207
- if not self.enable_content_tracing:
208
- if self.__content_allow_list.is_allowed(association_properties):
209
- attach(set_value("override_enable_content_tracing", True))
210
- else:
211
- attach(set_value("override_enable_content_tracing", False))
212
-
213
- # Call original on_start method if it exists in custom processor
214
- if self.__spans_processor_original_on_start:
215
- self.__spans_processor_original_on_start(span, parent_context)
216
-
217
- @staticmethod
218
- def set_static_params(
219
- resource_attributes: dict,
220
- enable_content_tracing: bool,
221
- endpoint: str,
222
- headers: Dict[str, str],
223
- ) -> None:
224
- TracerWrapper.resource_attributes = resource_attributes
225
- TracerWrapper.enable_content_tracing = enable_content_tracing
226
- TracerWrapper.endpoint = endpoint
227
- TracerWrapper.headers = headers
228
-
229
- @classmethod
230
- def verify_initialized(cls) -> bool:
231
- return hasattr(cls, "instance")
232
-
233
- @classmethod
234
- def clear(cls):
235
- # Any state cleanup. Now used in between tests
236
- cls.__span_id_to_path = {}
237
- cls.__span_id_lists = {}
238
-
239
- def shutdown(self):
240
- self.__tracer_provider.shutdown()
241
-
242
- def flush(self):
243
- return self.__spans_processor.force_flush()
244
-
245
- def get_tracer(self):
246
- return self.__tracer_provider.get_tracer(TRACER_NAME)
247
-
248
-
249
- def set_association_properties(properties: dict) -> None:
250
- attach(set_value("association_properties", properties))
251
-
252
- span = trace.get_current_span()
253
- _set_association_properties_attributes(span, properties)
254
-
255
-
256
- def get_association_properties(context: Optional[Context] = None) -> dict:
257
- return get_value("association_properties", context) or {}
258
-
259
-
260
- def update_association_properties(
261
- properties: dict,
262
- set_on_current_span: bool = True,
263
- context: Optional[Context] = None,
264
- ) -> None:
265
- """Only adds or updates properties that are not already present"""
266
- association_properties = get_value("association_properties", context) or {}
267
- association_properties.update(properties)
268
-
269
- attach(set_value("association_properties", association_properties, context))
270
-
271
- if set_on_current_span:
272
- span = trace.get_current_span()
273
- _set_association_properties_attributes(span, properties)
274
-
275
-
276
- def remove_association_properties(properties: dict) -> None:
277
- props: dict = copy.copy(get_value("association_properties") or {})
278
- for k in properties.keys():
279
- props.pop(k, None)
280
- set_association_properties(props)
281
-
282
-
283
- def _set_association_properties_attributes(span, properties: dict) -> None:
284
- for key, value in properties.items():
285
- if key == TRACING_LEVEL:
286
- span.set_attribute(f"lmnr.internal.{TRACING_LEVEL}", value)
287
- continue
288
- span.set_attribute(f"{ASSOCIATION_PROPERTIES}.{key}", value)
289
-
290
-
291
- def set_managed_prompt_tracing_context(
292
- key: str,
293
- version: int,
294
- version_name: str,
295
- version_hash: str,
296
- template_variables: dict,
297
- ) -> None:
298
- attach(set_value("managed_prompt", True))
299
- attach(set_value("prompt_key", key))
300
- attach(set_value("prompt_version", version))
301
- attach(set_value("prompt_version_name", version_name))
302
- attach(set_value("prompt_version_hash", version_hash))
303
- attach(set_value("prompt_template_variables", template_variables))
304
-
305
-
306
- def init_spans_exporter(api_endpoint: str, headers: Dict[str, str]) -> SpanExporter:
307
- if "http" in api_endpoint.lower() or "https" in api_endpoint.lower():
308
- return HTTPExporter(endpoint=f"{api_endpoint}/v1/traces", headers=headers)
309
- else:
310
- return GRPCExporter(
311
- endpoint=f"{api_endpoint}", headers=headers, compression=Compression.Gzip
312
- )
313
-
314
-
315
- # TODO: check if it's safer to use the default tracer provider obtained from
316
- # get_tracer_provider()
317
- def init_tracer_provider(resource: Resource) -> TracerProvider:
318
- provider: TracerProvider = None
319
- default_provider: TracerProvider = get_tracer_provider()
320
-
321
- if isinstance(default_provider, ProxyTracerProvider):
322
- provider = TracerProvider(resource=resource)
323
- trace.set_tracer_provider(provider)
324
- elif not hasattr(default_provider, "add_span_processor"):
325
- module_logger.error(
326
- "Cannot add span processor to the default provider since it doesn't support it"
327
- )
328
- return
329
- else:
330
- provider = default_provider
331
-
332
- return provider
333
-
334
-
335
- def init_instrumentations(
336
- should_enrich_metrics: bool,
337
- instruments: Optional[Set[Instruments]] = None,
338
- block_instruments: Optional[Set[Instruments]] = None,
339
- client: Optional[LaminarClient] = None,
340
- async_client: Optional[AsyncLaminarClient] = None,
341
- ):
342
- block_instruments = block_instruments or set()
343
- # These libraries are not instrumented by default,
344
- # but if the user wants, they can manually specify them
345
- default_off_instruments = set(
346
- [
347
- Instruments.REQUESTS,
348
- Instruments.URLLIB3,
349
- Instruments.REDIS,
350
- Instruments.PYMYSQL,
351
- ]
352
- )
353
-
354
- instruments = (
355
- instruments
356
- if instruments is not None
357
- else (set(Instruments) - default_off_instruments)
358
- )
359
-
360
- # Remove any instruments that were explicitly blocked
361
- instruments = instruments - block_instruments
362
-
363
- instrument_set = False
364
- for instrument in instruments:
365
- if instrument == Instruments.ALEPHALPHA:
366
- if init_alephalpha_instrumentor():
367
- instrument_set = True
368
- elif instrument == Instruments.ANTHROPIC:
369
- if init_anthropic_instrumentor(should_enrich_metrics):
370
- instrument_set = True
371
- elif instrument == Instruments.BEDROCK:
372
- if init_bedrock_instrumentor(should_enrich_metrics):
373
- instrument_set = True
374
- elif instrument == Instruments.CHROMA:
375
- if init_chroma_instrumentor():
376
- instrument_set = True
377
- elif instrument == Instruments.COHERE:
378
- if init_cohere_instrumentor():
379
- instrument_set = True
380
- elif instrument == Instruments.GOOGLE_GENERATIVEAI:
381
- if init_google_generativeai_instrumentor():
382
- instrument_set = True
383
- elif instrument == Instruments.GOOGLE_GENAI:
384
- if init_google_genai_instrumentor():
385
- instrument_set = True
386
- elif instrument == Instruments.GROQ:
387
- if init_groq_instrumentor():
388
- instrument_set = True
389
- elif instrument == Instruments.HAYSTACK:
390
- if init_haystack_instrumentor():
391
- instrument_set = True
392
- elif instrument == Instruments.LANCEDB:
393
- if init_lancedb_instrumentor():
394
- instrument_set = True
395
- elif instrument == Instruments.LANGCHAIN:
396
- if init_langchain_instrumentor():
397
- instrument_set = True
398
- elif instrument == Instruments.LLAMA_INDEX:
399
- if init_llama_index_instrumentor():
400
- instrument_set = True
401
- elif instrument == Instruments.MARQO:
402
- if init_marqo_instrumentor():
403
- instrument_set = True
404
- elif instrument == Instruments.MILVUS:
405
- if init_milvus_instrumentor():
406
- instrument_set = True
407
- elif instrument == Instruments.MISTRAL:
408
- if init_mistralai_instrumentor():
409
- instrument_set = True
410
- elif instrument == Instruments.OLLAMA:
411
- if init_ollama_instrumentor():
412
- instrument_set = True
413
- elif instrument == Instruments.OPENAI:
414
- if init_openai_instrumentor(should_enrich_metrics):
415
- instrument_set = True
416
- elif instrument == Instruments.PINECONE:
417
- if init_pinecone_instrumentor():
418
- instrument_set = True
419
- elif instrument == Instruments.PYMYSQL:
420
- if init_pymysql_instrumentor():
421
- instrument_set = True
422
- elif instrument == Instruments.QDRANT:
423
- if init_qdrant_instrumentor():
424
- instrument_set = True
425
- elif instrument == Instruments.REDIS:
426
- if init_redis_instrumentor():
427
- instrument_set = True
428
- elif instrument == Instruments.REPLICATE:
429
- if init_replicate_instrumentor():
430
- instrument_set = True
431
- elif instrument == Instruments.REQUESTS:
432
- if init_requests_instrumentor():
433
- instrument_set = True
434
- elif instrument == Instruments.SAGEMAKER:
435
- if init_sagemaker_instrumentor(should_enrich_metrics):
436
- instrument_set = True
437
- elif instrument == Instruments.TOGETHER:
438
- if init_together_instrumentor():
439
- instrument_set = True
440
- elif instrument == Instruments.TRANSFORMERS:
441
- if init_transformers_instrumentor():
442
- instrument_set = True
443
- elif instrument == Instruments.URLLIB3:
444
- if init_urllib3_instrumentor():
445
- instrument_set = True
446
- elif instrument == Instruments.VERTEXAI:
447
- if init_vertexai_instrumentor():
448
- instrument_set = True
449
- elif instrument == Instruments.WATSONX:
450
- if init_watsonx_instrumentor():
451
- instrument_set = True
452
- elif instrument == Instruments.WEAVIATE:
453
- if init_weaviate_instrumentor():
454
- instrument_set = True
455
- elif instrument == Instruments.PLAYWRIGHT:
456
- if init_playwright_instrumentor(client, async_client):
457
- instrument_set = True
458
- elif instrument == Instruments.BROWSER_USE:
459
- if init_browser_use_instrumentor():
460
- instrument_set = True
461
- else:
462
- module_logger.warning(
463
- f"Warning: {instrument} instrumentation does not exist."
464
- )
465
- module_logger.warning(
466
- "Usage:\n"
467
- "from lmnr import Laminar, Instruments\n"
468
- "Laminar.init(instruments=set([Instruments.OPENAI]))"
469
- )
470
-
471
- return instrument_set
472
-
473
-
474
- def init_browser_use_instrumentor():
475
- try:
476
- if is_package_installed("browser-use"):
477
- from lmnr.sdk.browser.browser_use_otel import BrowserUseInstrumentor
478
-
479
- instrumentor = BrowserUseInstrumentor()
480
- instrumentor.instrument()
481
- return True
482
- except Exception as e:
483
- module_logger.error(f"Error initializing BrowserUse instrumentor: {e}")
484
- return False
485
-
486
-
487
- def init_playwright_instrumentor(
488
- client: LaminarClient, async_client: AsyncLaminarClient
489
- ):
490
- try:
491
- if is_package_installed("playwright"):
492
- from lmnr.sdk.browser.playwright_otel import PlaywrightInstrumentor
493
-
494
- instrumentor = PlaywrightInstrumentor(client, async_client)
495
- instrumentor.instrument()
496
- return True
497
- except Exception as e:
498
- module_logger.error(f"Error initializing Playwright instrumentor: {e}")
499
- return False
500
-
501
-
502
- def init_openai_instrumentor(should_enrich_metrics: bool):
503
- try:
504
- if is_package_installed("openai") and is_package_installed(
505
- "opentelemetry-instrumentation-openai"
506
- ):
507
- from opentelemetry.instrumentation.openai import OpenAIInstrumentor
508
-
509
- instrumentor = OpenAIInstrumentor(
510
- enrich_assistant=should_enrich_metrics,
511
- enrich_token_usage=should_enrich_metrics,
512
- # Default in the package provided is an empty function, which
513
- # results in dropping the image data if we don't explicitly
514
- # set it to None.
515
- upload_base64_image=None,
516
- )
517
- if not instrumentor.is_instrumented_by_opentelemetry:
518
- instrumentor.instrument()
519
- return True
520
-
521
- except Exception as e:
522
- module_logger.error(f"Error initializing OpenAI instrumentor: {e}")
523
- return False
524
-
525
-
526
- def init_anthropic_instrumentor(should_enrich_metrics: bool):
527
- try:
528
- if is_package_installed("anthropic") and is_package_installed(
529
- "opentelemetry-instrumentation-anthropic"
530
- ):
531
- from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
532
-
533
- instrumentor = AnthropicInstrumentor(
534
- enrich_token_usage=should_enrich_metrics,
535
- upload_base64_image=None,
536
- )
537
- if not instrumentor.is_instrumented_by_opentelemetry:
538
- instrumentor.instrument()
539
- return True
540
- except Exception as e:
541
- module_logger.error(f"Error initializing Anthropic instrumentor: {e}")
542
- return False
543
-
544
-
545
- def init_cohere_instrumentor():
546
- try:
547
- if is_package_installed("cohere") and is_package_installed(
548
- "opentelemetry-instrumentation-cohere"
549
- ):
550
- from opentelemetry.instrumentation.cohere import CohereInstrumentor
551
-
552
- instrumentor = CohereInstrumentor()
553
- if not instrumentor.is_instrumented_by_opentelemetry:
554
- instrumentor.instrument()
555
- return True
556
- except Exception as e:
557
- module_logger.error(f"Error initializing Cohere instrumentor: {e}")
558
- return False
559
-
560
-
561
- def init_pinecone_instrumentor():
562
- try:
563
- if is_package_installed("pinecone") and is_package_installed(
564
- "opentelemetry-instrumentation-pinecone"
565
- ):
566
- from opentelemetry.instrumentation.pinecone import PineconeInstrumentor
567
-
568
- instrumentor = PineconeInstrumentor()
569
- if not instrumentor.is_instrumented_by_opentelemetry:
570
- instrumentor.instrument()
571
- return True
572
- except Exception as e:
573
- module_logger.error(f"Error initializing Pinecone instrumentor: {e}")
574
- return False
575
-
576
-
577
- def init_qdrant_instrumentor():
578
- try:
579
- if is_package_installed("qdrant_client") and is_package_installed(
580
- "opentelemetry-instrumentation-qdrant"
581
- ):
582
- from opentelemetry.instrumentation.qdrant import QdrantInstrumentor
583
-
584
- instrumentor = QdrantInstrumentor()
585
- if not instrumentor.is_instrumented_by_opentelemetry:
586
- instrumentor.instrument()
587
- except Exception as e:
588
- module_logger.error(f"Error initializing Qdrant instrumentor: {e}")
589
- return False
590
-
591
-
592
- def init_chroma_instrumentor():
593
- try:
594
- if is_package_installed("chromadb") and is_package_installed(
595
- "opentelemetry-instrumentation-chromadb"
596
- ):
597
- from opentelemetry.instrumentation.chromadb import ChromaInstrumentor
598
-
599
- instrumentor = ChromaInstrumentor()
600
- if not instrumentor.is_instrumented_by_opentelemetry:
601
- instrumentor.instrument()
602
- return True
603
- except Exception as e:
604
- module_logger.error(f"Error initializing Chroma instrumentor: {e}")
605
- return False
606
-
607
-
608
- def init_google_generativeai_instrumentor():
609
- try:
610
- if is_package_installed("google-generativeai") and is_package_installed(
611
- "opentelemetry-instrumentation-google-generativeai"
612
- ):
613
- from opentelemetry.instrumentation.google_generativeai import (
614
- GoogleGenerativeAiInstrumentor,
615
- )
616
-
617
- instrumentor = GoogleGenerativeAiInstrumentor()
618
- if not instrumentor.is_instrumented_by_opentelemetry:
619
- instrumentor.instrument()
620
- return True
621
- except Exception as e:
622
- module_logger.error(f"Error initializing Gemini instrumentor: {e}")
623
- return False
624
-
625
-
626
- def init_google_genai_instrumentor():
627
- try:
628
- if is_package_installed("google-genai"):
629
- # TODO: uncomment this once we migrate to the contrib package
630
- # and is_package_installed(
631
- # "opentelemetry-instrumentation-google-genai"
632
- # ):
633
- # from opentelemetry.instrumentation.google_genai import (
634
- from ..opentelemetry.instrumentation.google_genai import (
635
- GoogleGenAiSdkInstrumentor,
636
- )
637
-
638
- instrumentor = GoogleGenAiSdkInstrumentor()
639
- if not instrumentor.is_instrumented_by_opentelemetry:
640
- instrumentor.instrument()
641
- return True
642
- except Exception as e:
643
- module_logger.error(f"Error initializing Google GenAI instrumentor: {e}")
644
- return False
645
-
646
-
647
- def init_haystack_instrumentor():
648
- try:
649
- if is_package_installed("haystack") and is_package_installed(
650
- "opentelemetry-instrumentation-haystack"
651
- ):
652
- from opentelemetry.instrumentation.haystack import HaystackInstrumentor
653
-
654
- instrumentor = HaystackInstrumentor()
655
- if not instrumentor.is_instrumented_by_opentelemetry:
656
- instrumentor.instrument()
657
- return True
658
- except Exception as e:
659
- module_logger.error(f"Error initializing Haystack instrumentor: {e}")
660
- return False
661
-
662
-
663
- def init_langchain_instrumentor():
664
- try:
665
- if is_package_installed("langchain") and is_package_installed(
666
- "opentelemetry-instrumentation-langchain"
667
- ):
668
- from opentelemetry.instrumentation.langchain import LangchainInstrumentor
669
-
670
- instrumentor = LangchainInstrumentor()
671
- if not instrumentor.is_instrumented_by_opentelemetry:
672
- instrumentor.instrument()
673
- return True
674
- except Exception as e:
675
- # FIXME: silencing this error temporarily, it appears to not be critical
676
- if str(e) != "No module named 'langchain_community'":
677
- module_logger.error(f"Error initializing LangChain instrumentor: {e}")
678
- return False
679
-
680
-
681
- def init_mistralai_instrumentor():
682
- try:
683
- if is_package_installed("mistralai") and is_package_installed(
684
- "opentelemetry-instrumentation-mistralai"
685
- ):
686
- from opentelemetry.instrumentation.mistralai import MistralAiInstrumentor
687
-
688
- instrumentor = MistralAiInstrumentor()
689
- if not instrumentor.is_instrumented_by_opentelemetry:
690
- instrumentor.instrument()
691
- return True
692
- except Exception as e:
693
- module_logger.error(f"Error initializing MistralAI instrumentor: {e}")
694
- return False
695
-
696
-
697
- def init_ollama_instrumentor():
698
- try:
699
- if is_package_installed("ollama") and is_package_installed(
700
- "opentelemetry-instrumentation-ollama"
701
- ):
702
- from opentelemetry.instrumentation.ollama import OllamaInstrumentor
703
-
704
- instrumentor = OllamaInstrumentor()
705
- if not instrumentor.is_instrumented_by_opentelemetry:
706
- instrumentor.instrument()
707
- return True
708
- except Exception as e:
709
- module_logger.error(f"Error initializing Ollama instrumentor: {e}")
710
- return False
711
-
712
-
713
- def init_transformers_instrumentor():
714
- try:
715
- if is_package_installed("transformers") and is_package_installed(
716
- "opentelemetry-instrumentation-transformers"
717
- ):
718
- from opentelemetry.instrumentation.transformers import (
719
- TransformersInstrumentor,
720
- )
721
-
722
- instrumentor = TransformersInstrumentor()
723
- if not instrumentor.is_instrumented_by_opentelemetry:
724
- instrumentor.instrument()
725
- return True
726
- except Exception as e:
727
- module_logger.error(f"Error initializing Transformers instrumentor: {e}")
728
- return False
729
-
730
-
731
- def init_together_instrumentor():
732
- try:
733
- if is_package_installed("together") and is_package_installed(
734
- "opentelemetry-instrumentation-together"
735
- ):
736
- from opentelemetry.instrumentation.together import TogetherAiInstrumentor
737
-
738
- instrumentor = TogetherAiInstrumentor()
739
- if not instrumentor.is_instrumented_by_opentelemetry:
740
- instrumentor.instrument()
741
- return True
742
- except Exception as e:
743
- module_logger.error(f"Error initializing TogetherAI instrumentor: {e}")
744
- return False
745
-
746
-
747
- def init_llama_index_instrumentor():
748
- try:
749
- if (
750
- is_package_installed("llama-index") or is_package_installed("llama_index")
751
- ) and is_package_installed("opentelemetry-instrumentation-llamaindex"):
752
- from opentelemetry.instrumentation.llamaindex import LlamaIndexInstrumentor
753
-
754
- instrumentor = LlamaIndexInstrumentor()
755
- if not instrumentor.is_instrumented_by_opentelemetry:
756
- instrumentor.instrument()
757
- return True
758
- except Exception as e:
759
- module_logger.error(f"Error initializing LlamaIndex instrumentor: {e}")
760
- return False
761
-
762
-
763
- def init_milvus_instrumentor():
764
- try:
765
- if is_package_installed("pymilvus") and is_package_installed(
766
- "opentelemetry-instrumentation-milvus"
767
- ):
768
- from opentelemetry.instrumentation.milvus import MilvusInstrumentor
769
-
770
- instrumentor = MilvusInstrumentor()
771
- if not instrumentor.is_instrumented_by_opentelemetry:
772
- instrumentor.instrument()
773
- return True
774
- except Exception as e:
775
- module_logger.error(f"Error initializing Milvus instrumentor: {e}")
776
- return False
777
-
778
-
779
- def init_requests_instrumentor():
780
- try:
781
- if is_package_installed("requests"):
782
- from opentelemetry.instrumentation.requests import RequestsInstrumentor
783
-
784
- instrumentor = RequestsInstrumentor()
785
- if not instrumentor.is_instrumented_by_opentelemetry:
786
- instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
787
- return True
788
- except Exception as e:
789
- module_logger.error(f"Error initializing Requests instrumentor: {e}")
790
- return False
791
-
792
-
793
- def init_urllib3_instrumentor():
794
- try:
795
- if is_package_installed("urllib3"):
796
- from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
797
-
798
- instrumentor = URLLib3Instrumentor()
799
- if not instrumentor.is_instrumented_by_opentelemetry:
800
- instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
801
- return True
802
- except Exception as e:
803
- module_logger.error(f"Error initializing urllib3 instrumentor: {e}")
804
- return False
805
-
806
-
807
- def init_pymysql_instrumentor():
808
- try:
809
- if is_package_installed("sqlalchemy"):
810
- from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
811
-
812
- instrumentor = SQLAlchemyInstrumentor()
813
- if not instrumentor.is_instrumented_by_opentelemetry:
814
- instrumentor.instrument()
815
- return True
816
- except Exception as e:
817
- module_logger.error(f"Error initializing SQLAlchemy instrumentor: {e}")
818
- return False
819
-
820
-
821
- def init_bedrock_instrumentor(should_enrich_metrics: bool):
822
- try:
823
- if is_package_installed("boto3") and is_package_installed(
824
- "opentelemetry-instrumentation-bedrock"
825
- ):
826
- from opentelemetry.instrumentation.bedrock import BedrockInstrumentor
827
-
828
- instrumentor = BedrockInstrumentor(
829
- enrich_token_usage=should_enrich_metrics,
830
- )
831
- if not instrumentor.is_instrumented_by_opentelemetry:
832
- instrumentor.instrument()
833
- return True
834
- except Exception as e:
835
- module_logger.error(f"Error initializing Bedrock instrumentor: {e}")
836
- return False
837
-
838
-
839
- def init_replicate_instrumentor():
840
- try:
841
- if is_package_installed("replicate") and is_package_installed(
842
- "opentelemetry-instrumentation-replicate"
843
- ):
844
- from opentelemetry.instrumentation.replicate import ReplicateInstrumentor
845
-
846
- instrumentor = ReplicateInstrumentor()
847
- if not instrumentor.is_instrumented_by_opentelemetry:
848
- instrumentor.instrument()
849
- return True
850
- except Exception as e:
851
- module_logger.error(f"Error initializing Replicate instrumentor: {e}")
852
- return False
853
-
854
-
855
- def init_vertexai_instrumentor():
856
- try:
857
- if is_package_installed("vertexai") and is_package_installed(
858
- "opentelemetry-instrumentation-vertexai"
859
- ):
860
- from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
861
-
862
- instrumentor = VertexAIInstrumentor()
863
- if not instrumentor.is_instrumented_by_opentelemetry:
864
- instrumentor.instrument()
865
- return True
866
- except Exception as e:
867
- module_logger.warning(f"Error initializing Vertex AI instrumentor: {e}")
868
- return False
869
-
870
-
871
- def init_watsonx_instrumentor():
872
- try:
873
- if (
874
- is_package_installed("ibm-watsonx-ai")
875
- or is_package_installed("ibm-watson-machine-learning")
876
- ) and is_package_installed("opentelemetry-instrumentation-watsonx"):
877
- from opentelemetry.instrumentation.watsonx import WatsonxInstrumentor
878
-
879
- instrumentor = WatsonxInstrumentor()
880
- if not instrumentor.is_instrumented_by_opentelemetry:
881
- instrumentor.instrument()
882
- return True
883
- except Exception as e:
884
- module_logger.warning(f"Error initializing Watsonx instrumentor: {e}")
885
- return False
886
-
887
-
888
- def init_weaviate_instrumentor():
889
- try:
890
- if is_package_installed("weaviate") and is_package_installed(
891
- "opentelemetry-instrumentation-weaviate"
892
- ):
893
- from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor
894
-
895
- instrumentor = WeaviateInstrumentor()
896
- if not instrumentor.is_instrumented_by_opentelemetry:
897
- instrumentor.instrument()
898
- return True
899
- except Exception as e:
900
- module_logger.warning(f"Error initializing Weaviate instrumentor: {e}")
901
- return False
902
-
903
-
904
- def init_alephalpha_instrumentor():
905
- try:
906
- if is_package_installed("aleph_alpha_client") and is_package_installed(
907
- "opentelemetry-instrumentation-alephalpha"
908
- ):
909
- from opentelemetry.instrumentation.alephalpha import AlephAlphaInstrumentor
910
-
911
- instrumentor = AlephAlphaInstrumentor()
912
- if not instrumentor.is_instrumented_by_opentelemetry:
913
- instrumentor.instrument()
914
- return True
915
- except Exception as e:
916
- module_logger.error(f"Error initializing Aleph Alpha instrumentor: {e}")
917
- return False
918
-
919
-
920
- def init_marqo_instrumentor():
921
- try:
922
- if is_package_installed("marqo") and is_package_installed(
923
- "opentelemetry-instrumentation-marqo"
924
- ):
925
- from opentelemetry.instrumentation.marqo import MarqoInstrumentor
926
-
927
- instrumentor = MarqoInstrumentor()
928
- if not instrumentor.is_instrumented_by_opentelemetry:
929
- instrumentor.instrument()
930
- return True
931
- except Exception as e:
932
- module_logger.error(f"Error initializing marqo instrumentor: {e}")
933
- return False
934
-
935
-
936
- def init_lancedb_instrumentor():
937
- try:
938
- if is_package_installed("lancedb") and is_package_installed(
939
- "opentelemetry-instrumentation-lancedb"
940
- ):
941
- from opentelemetry.instrumentation.lancedb import LanceInstrumentor
942
-
943
- instrumentor = LanceInstrumentor()
944
- if not instrumentor.is_instrumented_by_opentelemetry:
945
- instrumentor.instrument()
946
- return True
947
- except Exception as e:
948
- module_logger.error(f"Error initializing LanceDB instrumentor: {e}")
949
-
950
-
951
- def init_redis_instrumentor():
952
- try:
953
- if is_package_installed("redis") and is_package_installed(
954
- "opentelemetry-instrumentation-redis"
955
- ):
956
- from opentelemetry.instrumentation.redis import RedisInstrumentor
957
-
958
- instrumentor = RedisInstrumentor()
959
- if not instrumentor.is_instrumented_by_opentelemetry:
960
- instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
961
- return True
962
- except Exception as e:
963
- module_logger.error(f"Error initializing redis instrumentor: {e}")
964
- return False
965
-
966
-
967
- def init_groq_instrumentor():
968
- try:
969
- if is_package_installed("groq") and is_package_installed(
970
- "opentelemetry-instrumentation-groq"
971
- ):
972
- from opentelemetry.instrumentation.groq import GroqInstrumentor
973
-
974
- instrumentor = GroqInstrumentor()
975
- if not instrumentor.is_instrumented_by_opentelemetry:
976
- instrumentor.instrument()
977
- return True
978
- except Exception as e:
979
- module_logger.error(f"Error initializing Groq instrumentor: {e}")
980
- return False
981
-
982
-
983
- def init_sagemaker_instrumentor(should_enrich_metrics: bool):
984
- try:
985
- if is_package_installed("boto3") and is_package_installed(
986
- "opentelemetry-instrumentation-sagemaker"
987
- ):
988
- from opentelemetry.instrumentation.sagemaker import SageMakerInstrumentor
989
-
990
- instrumentor = SageMakerInstrumentor(
991
- enrich_token_usage=should_enrich_metrics,
992
- )
993
- if not instrumentor.is_instrumented_by_opentelemetry:
994
- instrumentor.instrument()
995
- return True
996
- except Exception as e:
997
- module_logger.error(f"Error initializing SageMaker instrumentor: {e}")
998
- return False