lmnr 0.4.17b0__py2.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.
- lmnr/__init__.py +5 -0
- lmnr/cli.py +39 -0
- lmnr/sdk/__init__.py +0 -0
- lmnr/sdk/decorators.py +66 -0
- lmnr/sdk/evaluations.py +354 -0
- lmnr/sdk/laminar.py +403 -0
- lmnr/sdk/log.py +39 -0
- lmnr/sdk/types.py +155 -0
- lmnr/sdk/utils.py +99 -0
- lmnr/traceloop_sdk/.flake8 +12 -0
- lmnr/traceloop_sdk/.python-version +1 -0
- lmnr/traceloop_sdk/__init__.py +89 -0
- lmnr/traceloop_sdk/config/__init__.py +9 -0
- lmnr/traceloop_sdk/decorators/__init__.py +0 -0
- lmnr/traceloop_sdk/decorators/base.py +178 -0
- lmnr/traceloop_sdk/instruments.py +34 -0
- lmnr/traceloop_sdk/tests/__init__.py +1 -0
- lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_and_external_association_properties.yaml +101 -0
- lmnr/traceloop_sdk/tests/cassettes/test_association_properties/test_langchain_association_properties.yaml +99 -0
- lmnr/traceloop_sdk/tests/cassettes/test_manual/test_manual_report.yaml +98 -0
- lmnr/traceloop_sdk/tests/cassettes/test_manual/test_resource_attributes.yaml +98 -0
- lmnr/traceloop_sdk/tests/cassettes/test_privacy_no_prompts/test_simple_workflow.yaml +199 -0
- lmnr/traceloop_sdk/tests/cassettes/test_prompt_management/test_prompt_management.yaml +202 -0
- lmnr/traceloop_sdk/tests/cassettes/test_sdk_initialization/test_resource_attributes.yaml +199 -0
- lmnr/traceloop_sdk/tests/cassettes/test_tasks/test_task_io_serialization_with_langchain.yaml +96 -0
- lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_aworkflow.yaml +98 -0
- lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_simple_workflow.yaml +199 -0
- lmnr/traceloop_sdk/tests/cassettes/test_workflows/test_streaming_workflow.yaml +167 -0
- lmnr/traceloop_sdk/tests/conftest.py +111 -0
- lmnr/traceloop_sdk/tests/test_association_properties.py +229 -0
- lmnr/traceloop_sdk/tests/test_manual.py +48 -0
- lmnr/traceloop_sdk/tests/test_nested_tasks.py +47 -0
- lmnr/traceloop_sdk/tests/test_privacy_no_prompts.py +50 -0
- lmnr/traceloop_sdk/tests/test_sdk_initialization.py +57 -0
- lmnr/traceloop_sdk/tests/test_tasks.py +32 -0
- lmnr/traceloop_sdk/tests/test_workflows.py +262 -0
- lmnr/traceloop_sdk/tracing/__init__.py +1 -0
- lmnr/traceloop_sdk/tracing/attributes.py +9 -0
- lmnr/traceloop_sdk/tracing/content_allow_list.py +24 -0
- lmnr/traceloop_sdk/tracing/context_manager.py +13 -0
- lmnr/traceloop_sdk/tracing/tracing.py +913 -0
- lmnr/traceloop_sdk/utils/__init__.py +26 -0
- lmnr/traceloop_sdk/utils/in_memory_span_exporter.py +61 -0
- lmnr/traceloop_sdk/utils/json_encoder.py +20 -0
- lmnr/traceloop_sdk/utils/package_check.py +8 -0
- lmnr/traceloop_sdk/version.py +1 -0
- lmnr-0.4.17b0.dist-info/LICENSE +75 -0
- lmnr-0.4.17b0.dist-info/METADATA +250 -0
- lmnr-0.4.17b0.dist-info/RECORD +50 -0
- lmnr-0.4.17b0.dist-info/WHEEL +4 -0
@@ -0,0 +1,913 @@
|
|
1
|
+
import atexit
|
2
|
+
import logging
|
3
|
+
import os
|
4
|
+
|
5
|
+
|
6
|
+
from opentelemetry import trace
|
7
|
+
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
8
|
+
OTLPSpanExporter as HTTPExporter,
|
9
|
+
)
|
10
|
+
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
11
|
+
OTLPSpanExporter as GRPCExporter,
|
12
|
+
)
|
13
|
+
from opentelemetry.sdk.resources import Resource
|
14
|
+
from opentelemetry.sdk.trace import TracerProvider, SpanProcessor
|
15
|
+
from opentelemetry.propagators.textmap import TextMapPropagator
|
16
|
+
from opentelemetry.propagate import set_global_textmap
|
17
|
+
from opentelemetry.sdk.trace.export import (
|
18
|
+
SpanExporter,
|
19
|
+
SimpleSpanProcessor,
|
20
|
+
BatchSpanProcessor,
|
21
|
+
)
|
22
|
+
from opentelemetry.trace import get_tracer_provider, ProxyTracerProvider
|
23
|
+
from opentelemetry.context import get_value, attach, set_value
|
24
|
+
from opentelemetry.instrumentation.threading import ThreadingInstrumentor
|
25
|
+
|
26
|
+
# from lmnr.traceloop_sdk import Telemetry
|
27
|
+
from lmnr.traceloop_sdk.instruments import Instruments
|
28
|
+
from lmnr.traceloop_sdk.tracing.attributes import ASSOCIATION_PROPERTIES, SPAN_PATH
|
29
|
+
from lmnr.traceloop_sdk.tracing.content_allow_list import ContentAllowList
|
30
|
+
from lmnr.traceloop_sdk.utils import is_notebook
|
31
|
+
from lmnr.traceloop_sdk.utils.package_check import is_package_installed
|
32
|
+
from typing import Dict, Optional, Set
|
33
|
+
|
34
|
+
|
35
|
+
TRACER_NAME = "lmnr.tracer"
|
36
|
+
EXCLUDED_URLS = """
|
37
|
+
iam.cloud.ibm.com,
|
38
|
+
dataplatform.cloud.ibm.com,
|
39
|
+
ml.cloud.ibm.com,
|
40
|
+
api.openai.com,
|
41
|
+
openai.azure.com,
|
42
|
+
api.anthropic.com,
|
43
|
+
api.cohere.ai,
|
44
|
+
pinecone.io,
|
45
|
+
api.lmnr.ai,
|
46
|
+
posthog.com,
|
47
|
+
sentry.io,
|
48
|
+
bedrock-runtime,
|
49
|
+
googleapis.com,
|
50
|
+
githubusercontent.com,
|
51
|
+
openaipublic.blob.core.windows.net"""
|
52
|
+
|
53
|
+
|
54
|
+
class TracerWrapper(object):
|
55
|
+
resource_attributes: dict = {}
|
56
|
+
enable_content_tracing: bool = True
|
57
|
+
endpoint: str = None
|
58
|
+
headers: Dict[str, str] = {}
|
59
|
+
__tracer_provider: TracerProvider = None
|
60
|
+
|
61
|
+
def __new__(
|
62
|
+
cls,
|
63
|
+
disable_batch=False,
|
64
|
+
processor: Optional[SpanProcessor] = None,
|
65
|
+
propagator: Optional[TextMapPropagator] = None,
|
66
|
+
exporter: Optional[SpanExporter] = None,
|
67
|
+
should_enrich_metrics: bool = True,
|
68
|
+
instruments: Optional[Set[Instruments]] = None,
|
69
|
+
) -> "TracerWrapper":
|
70
|
+
if not hasattr(cls, "instance"):
|
71
|
+
obj = cls.instance = super(TracerWrapper, cls).__new__(cls)
|
72
|
+
if not TracerWrapper.endpoint:
|
73
|
+
return obj
|
74
|
+
|
75
|
+
obj.__resource = Resource(attributes=TracerWrapper.resource_attributes)
|
76
|
+
obj.__tracer_provider = init_tracer_provider(resource=obj.__resource)
|
77
|
+
if processor:
|
78
|
+
# Telemetry().capture("tracer:init", {"processor": "custom"})
|
79
|
+
obj.__spans_processor: SpanProcessor = processor
|
80
|
+
obj.__spans_processor_original_on_start = processor.on_start
|
81
|
+
else:
|
82
|
+
# if exporter:
|
83
|
+
# Telemetry().capture(
|
84
|
+
# "tracer:init",
|
85
|
+
# {
|
86
|
+
# "exporter": "custom",
|
87
|
+
# "processor": "simple" if disable_batch else "batch",
|
88
|
+
# },
|
89
|
+
# )
|
90
|
+
# else:
|
91
|
+
# Telemetry().capture(
|
92
|
+
# "tracer:init",
|
93
|
+
# {
|
94
|
+
# "exporter": TracerWrapper.endpoint,
|
95
|
+
# "processor": "simple" if disable_batch else "batch",
|
96
|
+
# },
|
97
|
+
# )
|
98
|
+
|
99
|
+
obj.__spans_exporter: SpanExporter = (
|
100
|
+
exporter
|
101
|
+
if exporter
|
102
|
+
else init_spans_exporter(
|
103
|
+
TracerWrapper.endpoint, TracerWrapper.headers
|
104
|
+
)
|
105
|
+
)
|
106
|
+
if disable_batch or is_notebook():
|
107
|
+
obj.__spans_processor: SpanProcessor = SimpleSpanProcessor(
|
108
|
+
obj.__spans_exporter
|
109
|
+
)
|
110
|
+
else:
|
111
|
+
obj.__spans_processor: SpanProcessor = BatchSpanProcessor(
|
112
|
+
obj.__spans_exporter
|
113
|
+
)
|
114
|
+
obj.__spans_processor_original_on_start = None
|
115
|
+
|
116
|
+
obj.__spans_processor.on_start = obj._span_processor_on_start
|
117
|
+
obj.__tracer_provider.add_span_processor(obj.__spans_processor)
|
118
|
+
|
119
|
+
if propagator:
|
120
|
+
set_global_textmap(propagator)
|
121
|
+
|
122
|
+
# this makes sure otel context is propagated so we always want it
|
123
|
+
ThreadingInstrumentor().instrument()
|
124
|
+
|
125
|
+
if instruments is None:
|
126
|
+
init_instrumentations(should_enrich_metrics)
|
127
|
+
else:
|
128
|
+
for instrument in instruments:
|
129
|
+
if instrument == Instruments.OPENAI:
|
130
|
+
if not init_openai_instrumentor(should_enrich_metrics):
|
131
|
+
print("Warning: OpenAI library does not exist.")
|
132
|
+
elif instrument == Instruments.ANTHROPIC:
|
133
|
+
if not init_anthropic_instrumentor(should_enrich_metrics):
|
134
|
+
print(
|
135
|
+
"Warning: Anthropic library does not exist."
|
136
|
+
)
|
137
|
+
elif instrument == Instruments.COHERE:
|
138
|
+
if not init_cohere_instrumentor():
|
139
|
+
print("Warning: Cohere library does not exist.")
|
140
|
+
elif instrument == Instruments.PINECONE:
|
141
|
+
if not init_pinecone_instrumentor():
|
142
|
+
print(
|
143
|
+
"Warning: Pinecone library does not exist."
|
144
|
+
)
|
145
|
+
elif instrument == Instruments.CHROMA:
|
146
|
+
if not init_chroma_instrumentor():
|
147
|
+
print("Warning: Chroma library does not exist.")
|
148
|
+
elif instrument == Instruments.GOOGLE_GENERATIVEAI:
|
149
|
+
if not init_google_generativeai_instrumentor():
|
150
|
+
print("Warning: Google Generative AI library does not exist.")
|
151
|
+
elif instrument == Instruments.LANGCHAIN:
|
152
|
+
if not init_langchain_instrumentor():
|
153
|
+
print(
|
154
|
+
"Warning: LangChain library does not exist."
|
155
|
+
)
|
156
|
+
elif instrument == Instruments.MISTRAL:
|
157
|
+
if not init_mistralai_instrumentor():
|
158
|
+
print(
|
159
|
+
"Warning: MistralAI library does not exist."
|
160
|
+
)
|
161
|
+
elif instrument == Instruments.OLLAMA:
|
162
|
+
if not init_ollama_instrumentor():
|
163
|
+
print("Warning: Ollama library does not exist.")
|
164
|
+
elif instrument == Instruments.LLAMA_INDEX:
|
165
|
+
if not init_llama_index_instrumentor():
|
166
|
+
print(
|
167
|
+
"Warning: LlamaIndex library does not exist."
|
168
|
+
)
|
169
|
+
elif instrument == Instruments.MILVUS:
|
170
|
+
if not init_milvus_instrumentor():
|
171
|
+
print("Warning: Milvus library does not exist.")
|
172
|
+
elif instrument == Instruments.TRANSFORMERS:
|
173
|
+
if not init_transformers_instrumentor():
|
174
|
+
print("Warning: Transformers library does not exist.")
|
175
|
+
elif instrument == Instruments.TOGETHER:
|
176
|
+
if not init_together_instrumentor():
|
177
|
+
print(
|
178
|
+
"Warning: TogetherAI library does not exist."
|
179
|
+
)
|
180
|
+
elif instrument == Instruments.REQUESTS:
|
181
|
+
if not init_requests_instrumentor():
|
182
|
+
print(
|
183
|
+
"Warning: Requests library does not exist."
|
184
|
+
)
|
185
|
+
elif instrument == Instruments.URLLIB3:
|
186
|
+
if not init_urllib3_instrumentor():
|
187
|
+
print("Warning: urllib3 library does not exist.")
|
188
|
+
elif instrument == Instruments.PYMYSQL:
|
189
|
+
if not init_pymysql_instrumentor():
|
190
|
+
print("Warning: PyMySQL library does not exist.")
|
191
|
+
elif instrument == Instruments.BEDROCK:
|
192
|
+
if not init_bedrock_instrumentor(should_enrich_metrics):
|
193
|
+
print("Warning: Bedrock library does not exist.")
|
194
|
+
elif instrument == Instruments.REPLICATE:
|
195
|
+
if not init_replicate_instrumentor():
|
196
|
+
print(
|
197
|
+
"Warning: Replicate library does not exist."
|
198
|
+
)
|
199
|
+
elif instrument == Instruments.VERTEXAI:
|
200
|
+
if not init_vertexai_instrumentor():
|
201
|
+
print(
|
202
|
+
"Warning: Vertex AI library does not exist."
|
203
|
+
)
|
204
|
+
elif instrument == Instruments.WATSONX:
|
205
|
+
if not init_watsonx_instrumentor():
|
206
|
+
print("Warning: Watsonx library does not exist.")
|
207
|
+
elif instrument == Instruments.WEAVIATE:
|
208
|
+
if not init_weaviate_instrumentor():
|
209
|
+
print(
|
210
|
+
"Warning: Weaviate library does not exist."
|
211
|
+
)
|
212
|
+
elif instrument == Instruments.ALEPHALPHA:
|
213
|
+
if not init_alephalpha_instrumentor():
|
214
|
+
print("Warning: Aleph Alpha library does not exist.")
|
215
|
+
elif instrument == Instruments.MARQO:
|
216
|
+
if not init_marqo_instrumentor():
|
217
|
+
print("Warning: marqo library does not exist.")
|
218
|
+
elif instrument == Instruments.LANCEDB:
|
219
|
+
if not init_lancedb_instrumentor():
|
220
|
+
print("Warning: LanceDB library does not exist.")
|
221
|
+
elif instrument == Instruments.REDIS:
|
222
|
+
if not init_redis_instrumentor():
|
223
|
+
print("Warning: redis library does not exist.")
|
224
|
+
|
225
|
+
else:
|
226
|
+
print(
|
227
|
+
"Warning: "
|
228
|
+
+ instrument
|
229
|
+
+ " instrumentation does not exist."
|
230
|
+
)
|
231
|
+
print(
|
232
|
+
"Usage:\n"
|
233
|
+
+ "from lmnr.traceloop_sdk.instruments import Instruments\n"
|
234
|
+
+ 'Traceloop.init(app_name="...", instruments=set([Instruments.OPENAI]))'
|
235
|
+
)
|
236
|
+
|
237
|
+
obj.__content_allow_list = ContentAllowList()
|
238
|
+
|
239
|
+
# Force flushes for debug environments (e.g. local development)
|
240
|
+
atexit.register(obj.exit_handler)
|
241
|
+
|
242
|
+
return cls.instance
|
243
|
+
|
244
|
+
def exit_handler(self):
|
245
|
+
self.flush()
|
246
|
+
|
247
|
+
def _span_processor_on_start(self, span, parent_context):
|
248
|
+
span_path = get_value("span_path")
|
249
|
+
if span_path is not None:
|
250
|
+
# This is done redundantly here for most decorated functions
|
251
|
+
# However, need to do this for auto-instrumented libraries.
|
252
|
+
# Then, for auto-instrumented ones, they'll attach
|
253
|
+
# the final part of the name to the span on the backend.
|
254
|
+
span.set_attribute(SPAN_PATH, span_path)
|
255
|
+
|
256
|
+
association_properties = get_value("association_properties")
|
257
|
+
if association_properties is not None:
|
258
|
+
_set_association_properties_attributes(span, association_properties)
|
259
|
+
|
260
|
+
if not self.enable_content_tracing:
|
261
|
+
if self.__content_allow_list.is_allowed(association_properties):
|
262
|
+
attach(set_value("override_enable_content_tracing", True))
|
263
|
+
else:
|
264
|
+
attach(set_value("override_enable_content_tracing", False))
|
265
|
+
|
266
|
+
# Call original on_start method if it exists in custom processor
|
267
|
+
if self.__spans_processor_original_on_start:
|
268
|
+
self.__spans_processor_original_on_start(span, parent_context)
|
269
|
+
|
270
|
+
@staticmethod
|
271
|
+
def set_static_params(
|
272
|
+
resource_attributes: dict,
|
273
|
+
enable_content_tracing: bool,
|
274
|
+
endpoint: str,
|
275
|
+
headers: Dict[str, str],
|
276
|
+
) -> None:
|
277
|
+
TracerWrapper.resource_attributes = resource_attributes
|
278
|
+
TracerWrapper.enable_content_tracing = enable_content_tracing
|
279
|
+
TracerWrapper.endpoint = endpoint
|
280
|
+
TracerWrapper.headers = headers
|
281
|
+
|
282
|
+
@classmethod
|
283
|
+
def verify_initialized(cls) -> bool:
|
284
|
+
if hasattr(cls, "instance"):
|
285
|
+
return True
|
286
|
+
|
287
|
+
if (os.getenv("TRACELOOP_SUPPRESS_WARNINGS") or "false").lower() == "true":
|
288
|
+
return False
|
289
|
+
|
290
|
+
print("Warning: Laminar not initialized, make sure to initialize")
|
291
|
+
return False
|
292
|
+
|
293
|
+
def flush(self):
|
294
|
+
self.__spans_processor.force_flush()
|
295
|
+
|
296
|
+
def get_tracer(self):
|
297
|
+
return self.__tracer_provider.get_tracer(TRACER_NAME)
|
298
|
+
|
299
|
+
|
300
|
+
def set_association_properties(properties: dict) -> None:
|
301
|
+
attach(set_value("association_properties", properties))
|
302
|
+
|
303
|
+
# TODO: When called inside observe decorator, this actually sets the properties on the parent span, not the current one
|
304
|
+
# Then, processor's on_start will assign this to current span
|
305
|
+
span = trace.get_current_span()
|
306
|
+
_set_association_properties_attributes(span, properties)
|
307
|
+
|
308
|
+
|
309
|
+
def update_association_properties(properties: dict) -> None:
|
310
|
+
"""Only adds or updates properties that are not already present"""
|
311
|
+
association_properties = get_value("association_properties") or {}
|
312
|
+
association_properties.update(properties)
|
313
|
+
|
314
|
+
attach(set_value("association_properties", association_properties))
|
315
|
+
|
316
|
+
# TODO: When called inside observe decorator, this actually sets the properties on the parent span, not the current one
|
317
|
+
# Then, processor's on_start will assign this to current span
|
318
|
+
span = trace.get_current_span()
|
319
|
+
_set_association_properties_attributes(span, properties)
|
320
|
+
|
321
|
+
|
322
|
+
def _set_association_properties_attributes(span, properties: dict) -> None:
|
323
|
+
for key, value in properties.items():
|
324
|
+
span.set_attribute(
|
325
|
+
f"{ASSOCIATION_PROPERTIES}.{key}", value
|
326
|
+
)
|
327
|
+
|
328
|
+
|
329
|
+
def get_span_path(span_name: str) -> str:
|
330
|
+
current_span_path = get_value("span_path")
|
331
|
+
span_path = f"{current_span_path}.{span_name}" if current_span_path else span_name
|
332
|
+
return span_path
|
333
|
+
|
334
|
+
|
335
|
+
def set_managed_prompt_tracing_context(
|
336
|
+
key: str,
|
337
|
+
version: int,
|
338
|
+
version_name: str,
|
339
|
+
version_hash: str,
|
340
|
+
template_variables: dict,
|
341
|
+
) -> None:
|
342
|
+
attach(set_value("managed_prompt", True))
|
343
|
+
attach(set_value("prompt_key", key))
|
344
|
+
attach(set_value("prompt_version", version))
|
345
|
+
attach(set_value("prompt_version_name", version_name))
|
346
|
+
attach(set_value("prompt_version_hash", version_hash))
|
347
|
+
attach(set_value("prompt_template_variables", template_variables))
|
348
|
+
|
349
|
+
|
350
|
+
def set_external_prompt_tracing_context(
|
351
|
+
template: str, variables: dict, version: int
|
352
|
+
) -> None:
|
353
|
+
attach(set_value("managed_prompt", False))
|
354
|
+
attach(set_value("prompt_version", version))
|
355
|
+
attach(set_value("prompt_template", template))
|
356
|
+
attach(set_value("prompt_template_variables", variables))
|
357
|
+
|
358
|
+
|
359
|
+
def init_spans_exporter(api_endpoint: str, headers: Dict[str, str]) -> SpanExporter:
|
360
|
+
if "http" in api_endpoint.lower() or "https" in api_endpoint.lower():
|
361
|
+
return HTTPExporter(endpoint=f"{api_endpoint}/v1/traces", headers=headers)
|
362
|
+
else:
|
363
|
+
return GRPCExporter(endpoint=f"{api_endpoint}", headers=headers)
|
364
|
+
|
365
|
+
|
366
|
+
def init_tracer_provider(resource: Resource) -> TracerProvider:
|
367
|
+
provider: TracerProvider = None
|
368
|
+
default_provider: TracerProvider = get_tracer_provider()
|
369
|
+
|
370
|
+
if isinstance(default_provider, ProxyTracerProvider):
|
371
|
+
provider = TracerProvider(resource=resource)
|
372
|
+
trace.set_tracer_provider(provider)
|
373
|
+
elif not hasattr(default_provider, "add_span_processor"):
|
374
|
+
logging.error(
|
375
|
+
"Cannot add span processor to the default provider since it doesn't support it"
|
376
|
+
)
|
377
|
+
return
|
378
|
+
else:
|
379
|
+
provider = default_provider
|
380
|
+
|
381
|
+
return provider
|
382
|
+
|
383
|
+
|
384
|
+
def init_instrumentations(should_enrich_metrics: bool):
|
385
|
+
init_openai_instrumentor(should_enrich_metrics)
|
386
|
+
init_anthropic_instrumentor(should_enrich_metrics)
|
387
|
+
init_cohere_instrumentor()
|
388
|
+
init_pinecone_instrumentor()
|
389
|
+
init_qdrant_instrumentor()
|
390
|
+
init_chroma_instrumentor()
|
391
|
+
init_google_generativeai_instrumentor()
|
392
|
+
init_haystack_instrumentor()
|
393
|
+
init_langchain_instrumentor()
|
394
|
+
init_mistralai_instrumentor()
|
395
|
+
init_ollama_instrumentor()
|
396
|
+
init_llama_index_instrumentor()
|
397
|
+
init_milvus_instrumentor()
|
398
|
+
init_transformers_instrumentor()
|
399
|
+
init_together_instrumentor()
|
400
|
+
init_bedrock_instrumentor(should_enrich_metrics)
|
401
|
+
init_replicate_instrumentor()
|
402
|
+
init_vertexai_instrumentor()
|
403
|
+
init_watsonx_instrumentor()
|
404
|
+
init_weaviate_instrumentor()
|
405
|
+
init_alephalpha_instrumentor()
|
406
|
+
init_marqo_instrumentor()
|
407
|
+
init_lancedb_instrumentor()
|
408
|
+
init_groq_instrumentor()
|
409
|
+
|
410
|
+
# These libraries are not instrumented by default, but if the user wants, he can manually specify them
|
411
|
+
# init_redis_instrumentor()
|
412
|
+
# init_requests_instrumentor()
|
413
|
+
# init_urllib3_instrumentor()
|
414
|
+
# init_pymysql_instrumentor()
|
415
|
+
|
416
|
+
|
417
|
+
def init_openai_instrumentor(should_enrich_metrics: bool):
|
418
|
+
try:
|
419
|
+
if is_package_installed("openai"):
|
420
|
+
# Telemetry().capture("instrumentation:openai:init")
|
421
|
+
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
|
422
|
+
|
423
|
+
instrumentor = OpenAIInstrumentor(
|
424
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
425
|
+
enrich_assistant=should_enrich_metrics,
|
426
|
+
enrich_token_usage=should_enrich_metrics,
|
427
|
+
)
|
428
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
429
|
+
instrumentor.instrument()
|
430
|
+
return True
|
431
|
+
|
432
|
+
except Exception as e:
|
433
|
+
logging.error(f"Error initializing OpenAI instrumentor: {e}")
|
434
|
+
# Telemetry().log_exception(e)
|
435
|
+
return False
|
436
|
+
|
437
|
+
|
438
|
+
def init_anthropic_instrumentor(should_enrich_metrics: bool):
|
439
|
+
try:
|
440
|
+
if is_package_installed("anthropic"):
|
441
|
+
# Telemetry().capture("instrumentation:anthropic:init")
|
442
|
+
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor
|
443
|
+
|
444
|
+
instrumentor = AnthropicInstrumentor(
|
445
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
446
|
+
enrich_token_usage=should_enrich_metrics,
|
447
|
+
)
|
448
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
449
|
+
instrumentor.instrument()
|
450
|
+
return True
|
451
|
+
except Exception as e:
|
452
|
+
logging.error(f"Error initializing Anthropic instrumentor: {e}")
|
453
|
+
# Telemetry().log_exception(e)
|
454
|
+
return False
|
455
|
+
|
456
|
+
|
457
|
+
def init_cohere_instrumentor():
|
458
|
+
try:
|
459
|
+
if is_package_installed("cohere"):
|
460
|
+
# Telemetry().capture("instrumentation:cohere:init")
|
461
|
+
from opentelemetry.instrumentation.cohere import CohereInstrumentor
|
462
|
+
|
463
|
+
instrumentor = CohereInstrumentor(
|
464
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
465
|
+
)
|
466
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
467
|
+
instrumentor.instrument()
|
468
|
+
return True
|
469
|
+
except Exception as e:
|
470
|
+
logging.error(f"Error initializing Cohere instrumentor: {e}")
|
471
|
+
# Telemetry().log_exception(e)
|
472
|
+
return False
|
473
|
+
|
474
|
+
|
475
|
+
def init_pinecone_instrumentor():
|
476
|
+
try:
|
477
|
+
if is_package_installed("pinecone"):
|
478
|
+
# Telemetry().capture("instrumentation:pinecone:init")
|
479
|
+
from opentelemetry.instrumentation.pinecone import PineconeInstrumentor
|
480
|
+
|
481
|
+
instrumentor = PineconeInstrumentor(
|
482
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
483
|
+
)
|
484
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
485
|
+
instrumentor.instrument()
|
486
|
+
return True
|
487
|
+
except Exception as e:
|
488
|
+
logging.error(f"Error initializing Pinecone instrumentor: {e}")
|
489
|
+
# Telemetry().log_exception(e)
|
490
|
+
return False
|
491
|
+
|
492
|
+
|
493
|
+
def init_qdrant_instrumentor():
|
494
|
+
try:
|
495
|
+
if is_package_installed("qdrant_client"):
|
496
|
+
# Telemetry().capture("instrumentation:qdrant:init")
|
497
|
+
from opentelemetry.instrumentation.qdrant import QdrantInstrumentor
|
498
|
+
|
499
|
+
instrumentor = QdrantInstrumentor(
|
500
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
501
|
+
)
|
502
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
503
|
+
instrumentor.instrument()
|
504
|
+
except Exception as e:
|
505
|
+
logging.error(f"Error initializing Qdrant instrumentor: {e}")
|
506
|
+
# Telemetry().log_exception(e)
|
507
|
+
return False
|
508
|
+
|
509
|
+
|
510
|
+
def init_chroma_instrumentor():
|
511
|
+
try:
|
512
|
+
if is_package_installed("chromadb"):
|
513
|
+
# Telemetry().capture("instrumentation:chromadb:init")
|
514
|
+
from opentelemetry.instrumentation.chromadb import ChromaInstrumentor
|
515
|
+
|
516
|
+
instrumentor = ChromaInstrumentor(
|
517
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
518
|
+
)
|
519
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
520
|
+
instrumentor.instrument()
|
521
|
+
return True
|
522
|
+
except Exception as e:
|
523
|
+
logging.error(f"Error initializing Chroma instrumentor: {e}")
|
524
|
+
# Telemetry().log_exception(e)
|
525
|
+
return False
|
526
|
+
|
527
|
+
|
528
|
+
def init_google_generativeai_instrumentor():
|
529
|
+
try:
|
530
|
+
if is_package_installed("google.generativeai"):
|
531
|
+
# Telemetry().capture("instrumentation:gemini:init")
|
532
|
+
from opentelemetry.instrumentation.google_generativeai import (
|
533
|
+
GoogleGenerativeAiInstrumentor,
|
534
|
+
)
|
535
|
+
|
536
|
+
instrumentor = GoogleGenerativeAiInstrumentor(
|
537
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
538
|
+
)
|
539
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
540
|
+
instrumentor.instrument()
|
541
|
+
return True
|
542
|
+
except Exception as e:
|
543
|
+
logging.error(f"Error initializing Gemini instrumentor: {e}")
|
544
|
+
# Telemetry().log_exception(e)
|
545
|
+
return False
|
546
|
+
|
547
|
+
|
548
|
+
def init_haystack_instrumentor():
|
549
|
+
try:
|
550
|
+
if is_package_installed("haystack"):
|
551
|
+
# Telemetry().capture("instrumentation:haystack:init")
|
552
|
+
from opentelemetry.instrumentation.haystack import HaystackInstrumentor
|
553
|
+
|
554
|
+
instrumentor = HaystackInstrumentor(
|
555
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
556
|
+
)
|
557
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
558
|
+
instrumentor.instrument()
|
559
|
+
return True
|
560
|
+
except Exception as e:
|
561
|
+
logging.error(f"Error initializing Haystack instrumentor: {e}")
|
562
|
+
# Telemetry().log_exception(e)
|
563
|
+
return False
|
564
|
+
|
565
|
+
|
566
|
+
def init_langchain_instrumentor():
|
567
|
+
try:
|
568
|
+
if is_package_installed("langchain"):
|
569
|
+
# Telemetry().capture("instrumentation:langchain:init")
|
570
|
+
from opentelemetry.instrumentation.langchain import LangchainInstrumentor
|
571
|
+
|
572
|
+
instrumentor = LangchainInstrumentor(
|
573
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
574
|
+
)
|
575
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
576
|
+
instrumentor.instrument()
|
577
|
+
return True
|
578
|
+
except Exception as e:
|
579
|
+
logging.error(f"Error initializing LangChain instrumentor: {e}")
|
580
|
+
# Telemetry().log_exception(e)
|
581
|
+
return False
|
582
|
+
|
583
|
+
|
584
|
+
def init_mistralai_instrumentor():
|
585
|
+
try:
|
586
|
+
if is_package_installed("mistralai"):
|
587
|
+
# Telemetry().capture("instrumentation:mistralai:init")
|
588
|
+
from opentelemetry.instrumentation.mistralai import MistralAiInstrumentor
|
589
|
+
|
590
|
+
instrumentor = MistralAiInstrumentor(
|
591
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
592
|
+
)
|
593
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
594
|
+
instrumentor.instrument()
|
595
|
+
return True
|
596
|
+
except Exception as e:
|
597
|
+
logging.error(f"Error initializing MistralAI instrumentor: {e}")
|
598
|
+
# Telemetry().log_exception(e)
|
599
|
+
return False
|
600
|
+
|
601
|
+
|
602
|
+
def init_ollama_instrumentor():
|
603
|
+
try:
|
604
|
+
if is_package_installed("ollama"):
|
605
|
+
# Telemetry().capture("instrumentation:ollama:init")
|
606
|
+
from opentelemetry.instrumentation.ollama import OllamaInstrumentor
|
607
|
+
|
608
|
+
instrumentor = OllamaInstrumentor(
|
609
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
610
|
+
)
|
611
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
612
|
+
instrumentor.instrument()
|
613
|
+
return True
|
614
|
+
except Exception as e:
|
615
|
+
logging.error(f"Error initializing Ollama instrumentor: {e}")
|
616
|
+
# Telemetry().log_exception(e)
|
617
|
+
return False
|
618
|
+
|
619
|
+
|
620
|
+
def init_transformers_instrumentor():
|
621
|
+
try:
|
622
|
+
if is_package_installed("transformers"):
|
623
|
+
# Telemetry().capture("instrumentation:transformers:init")
|
624
|
+
from opentelemetry.instrumentation.transformers import (
|
625
|
+
TransformersInstrumentor,
|
626
|
+
)
|
627
|
+
|
628
|
+
instrumentor = TransformersInstrumentor(
|
629
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
630
|
+
)
|
631
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
632
|
+
instrumentor.instrument()
|
633
|
+
return True
|
634
|
+
except Exception as e:
|
635
|
+
logging.error(f"Error initializing Transformers instrumentor: {e}")
|
636
|
+
# Telemetry().log_exception(e)
|
637
|
+
return False
|
638
|
+
|
639
|
+
|
640
|
+
def init_together_instrumentor():
|
641
|
+
try:
|
642
|
+
if is_package_installed("together"):
|
643
|
+
# Telemetry().capture("instrumentation:together:init")
|
644
|
+
from opentelemetry.instrumentation.together import TogetherAiInstrumentor
|
645
|
+
|
646
|
+
instrumentor = TogetherAiInstrumentor(
|
647
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
648
|
+
)
|
649
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
650
|
+
instrumentor.instrument()
|
651
|
+
return True
|
652
|
+
except Exception as e:
|
653
|
+
logging.error(f"Error initializing TogetherAI instrumentor: {e}")
|
654
|
+
# Telemetry().log_exception(e)
|
655
|
+
return False
|
656
|
+
|
657
|
+
|
658
|
+
def init_llama_index_instrumentor():
|
659
|
+
try:
|
660
|
+
if is_package_installed("llama-index") or is_package_installed("llama_index"):
|
661
|
+
# Telemetry().capture("instrumentation:llamaindex:init")
|
662
|
+
from opentelemetry.instrumentation.llamaindex import LlamaIndexInstrumentor
|
663
|
+
|
664
|
+
instrumentor = LlamaIndexInstrumentor(
|
665
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
666
|
+
)
|
667
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
668
|
+
instrumentor.instrument()
|
669
|
+
return True
|
670
|
+
except Exception as e:
|
671
|
+
logging.error(f"Error initializing LlamaIndex instrumentor: {e}")
|
672
|
+
# Telemetry().log_exception(e)
|
673
|
+
return False
|
674
|
+
|
675
|
+
|
676
|
+
def init_milvus_instrumentor():
|
677
|
+
try:
|
678
|
+
if is_package_installed("pymilvus"):
|
679
|
+
# Telemetry().capture("instrumentation:milvus:init")
|
680
|
+
from opentelemetry.instrumentation.milvus import MilvusInstrumentor
|
681
|
+
|
682
|
+
instrumentor = MilvusInstrumentor(
|
683
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
684
|
+
)
|
685
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
686
|
+
instrumentor.instrument()
|
687
|
+
return True
|
688
|
+
except Exception as e:
|
689
|
+
logging.error(f"Error initializing Milvus instrumentor: {e}")
|
690
|
+
# Telemetry().log_exception(e)
|
691
|
+
return False
|
692
|
+
|
693
|
+
|
694
|
+
def init_requests_instrumentor():
|
695
|
+
try:
|
696
|
+
if is_package_installed("requests"):
|
697
|
+
from opentelemetry.instrumentation.requests import RequestsInstrumentor
|
698
|
+
|
699
|
+
instrumentor = RequestsInstrumentor()
|
700
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
701
|
+
instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
|
702
|
+
return True
|
703
|
+
except Exception as e:
|
704
|
+
logging.error(f"Error initializing Requests instrumentor: {e}")
|
705
|
+
# Telemetry().log_exception(e)
|
706
|
+
return False
|
707
|
+
|
708
|
+
|
709
|
+
def init_urllib3_instrumentor():
|
710
|
+
try:
|
711
|
+
if is_package_installed("urllib3"):
|
712
|
+
from opentelemetry.instrumentation.urllib3 import URLLib3Instrumentor
|
713
|
+
|
714
|
+
instrumentor = URLLib3Instrumentor()
|
715
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
716
|
+
instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
|
717
|
+
return True
|
718
|
+
except Exception as e:
|
719
|
+
logging.error(f"Error initializing urllib3 instrumentor: {e}")
|
720
|
+
# Telemetry().log_exception(e)
|
721
|
+
return False
|
722
|
+
|
723
|
+
|
724
|
+
def init_pymysql_instrumentor():
|
725
|
+
try:
|
726
|
+
if is_package_installed("sqlalchemy"):
|
727
|
+
from opentelemetry.instrumentation.sqlalchemy import SQLAlchemyInstrumentor
|
728
|
+
|
729
|
+
instrumentor = SQLAlchemyInstrumentor()
|
730
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
731
|
+
instrumentor.instrument()
|
732
|
+
return True
|
733
|
+
except Exception as e:
|
734
|
+
logging.error(f"Error initializing SQLAlchemy instrumentor: {e}")
|
735
|
+
# Telemetry().log_exception(e)
|
736
|
+
return False
|
737
|
+
|
738
|
+
|
739
|
+
def init_bedrock_instrumentor(should_enrich_metrics: bool):
|
740
|
+
try:
|
741
|
+
if is_package_installed("boto3"):
|
742
|
+
from opentelemetry.instrumentation.bedrock import BedrockInstrumentor
|
743
|
+
|
744
|
+
instrumentor = BedrockInstrumentor(
|
745
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
746
|
+
enrich_token_usage=should_enrich_metrics,
|
747
|
+
)
|
748
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
749
|
+
instrumentor.instrument()
|
750
|
+
return True
|
751
|
+
except Exception as e:
|
752
|
+
logging.error(f"Error initializing Bedrock instrumentor: {e}")
|
753
|
+
# Telemetry().log_exception(e)
|
754
|
+
return False
|
755
|
+
|
756
|
+
|
757
|
+
def init_replicate_instrumentor():
|
758
|
+
try:
|
759
|
+
if is_package_installed("replicate"):
|
760
|
+
# Telemetry().capture("instrumentation:replicate:init")
|
761
|
+
from opentelemetry.instrumentation.replicate import ReplicateInstrumentor
|
762
|
+
|
763
|
+
instrumentor = ReplicateInstrumentor(
|
764
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
765
|
+
)
|
766
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
767
|
+
instrumentor.instrument()
|
768
|
+
return True
|
769
|
+
except Exception as e:
|
770
|
+
logging.error(f"Error initializing Replicate instrumentor: {e}")
|
771
|
+
# Telemetry().log_exception(e)
|
772
|
+
return False
|
773
|
+
|
774
|
+
|
775
|
+
def init_vertexai_instrumentor():
|
776
|
+
try:
|
777
|
+
if is_package_installed("vertexai"):
|
778
|
+
# Telemetry().capture("instrumentation:vertexai:init")
|
779
|
+
from opentelemetry.instrumentation.vertexai import VertexAIInstrumentor
|
780
|
+
|
781
|
+
instrumentor = VertexAIInstrumentor(
|
782
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
783
|
+
)
|
784
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
785
|
+
instrumentor.instrument()
|
786
|
+
return True
|
787
|
+
except Exception as e:
|
788
|
+
logging.warning(f"Error initializing Vertex AI instrumentor: {e}")
|
789
|
+
# Telemetry().log_exception(e)
|
790
|
+
return False
|
791
|
+
|
792
|
+
|
793
|
+
def init_watsonx_instrumentor():
|
794
|
+
try:
|
795
|
+
if is_package_installed("ibm-watsonx-ai") or is_package_installed(
|
796
|
+
"ibm-watson-machine-learning"
|
797
|
+
):
|
798
|
+
# Telemetry().capture("instrumentation:watsonx:init")
|
799
|
+
from opentelemetry.instrumentation.watsonx import WatsonxInstrumentor
|
800
|
+
|
801
|
+
instrumentor = WatsonxInstrumentor(
|
802
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
803
|
+
)
|
804
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
805
|
+
instrumentor.instrument()
|
806
|
+
return True
|
807
|
+
except Exception as e:
|
808
|
+
logging.warning(f"Error initializing Watsonx instrumentor: {e}")
|
809
|
+
# Telemetry().log_exception(e)
|
810
|
+
return False
|
811
|
+
|
812
|
+
|
813
|
+
def init_weaviate_instrumentor():
|
814
|
+
try:
|
815
|
+
if is_package_installed("weaviate"):
|
816
|
+
# Telemetry().capture("instrumentation:weaviate:init")
|
817
|
+
from opentelemetry.instrumentation.weaviate import WeaviateInstrumentor
|
818
|
+
|
819
|
+
instrumentor = WeaviateInstrumentor(
|
820
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
821
|
+
)
|
822
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
823
|
+
instrumentor.instrument()
|
824
|
+
return True
|
825
|
+
except Exception as e:
|
826
|
+
logging.warning(f"Error initializing Weaviate instrumentor: {e}")
|
827
|
+
# Telemetry().log_exception(e)
|
828
|
+
return False
|
829
|
+
|
830
|
+
|
831
|
+
def init_alephalpha_instrumentor():
|
832
|
+
try:
|
833
|
+
if is_package_installed("aleph_alpha_client"):
|
834
|
+
# Telemetry().capture("instrumentation:alephalpha:init")
|
835
|
+
from opentelemetry.instrumentation.alephalpha import AlephAlphaInstrumentor
|
836
|
+
|
837
|
+
instrumentor = AlephAlphaInstrumentor(
|
838
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
839
|
+
)
|
840
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
841
|
+
instrumentor.instrument()
|
842
|
+
return True
|
843
|
+
except Exception as e:
|
844
|
+
logging.error(f"Error initializing Aleph Alpha instrumentor: {e}")
|
845
|
+
# Telemetry().log_exception(e)
|
846
|
+
return False
|
847
|
+
|
848
|
+
|
849
|
+
def init_marqo_instrumentor():
|
850
|
+
try:
|
851
|
+
if is_package_installed("marqo"):
|
852
|
+
# Telemetry().capture("instrumentation:marqo:init")
|
853
|
+
from opentelemetry.instrumentation.marqo import MarqoInstrumentor
|
854
|
+
|
855
|
+
instrumentor = MarqoInstrumentor(
|
856
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
857
|
+
)
|
858
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
859
|
+
instrumentor.instrument()
|
860
|
+
return True
|
861
|
+
except Exception as e:
|
862
|
+
logging.error(f"Error initializing marqo instrumentor: {e}")
|
863
|
+
# Telemetry().log_exception(e)
|
864
|
+
return False
|
865
|
+
|
866
|
+
|
867
|
+
def init_lancedb_instrumentor():
|
868
|
+
try:
|
869
|
+
if is_package_installed("lancedb"):
|
870
|
+
# Telemetry().capture("instrumentation:lancedb:init")
|
871
|
+
from opentelemetry.instrumentation.lancedb import LanceInstrumentor
|
872
|
+
|
873
|
+
instrumentor = LanceInstrumentor(
|
874
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
875
|
+
)
|
876
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
877
|
+
instrumentor.instrument()
|
878
|
+
return True
|
879
|
+
except Exception as e:
|
880
|
+
logging.error(f"Error initializing LanceDB instrumentor: {e}")
|
881
|
+
|
882
|
+
|
883
|
+
def init_redis_instrumentor():
|
884
|
+
try:
|
885
|
+
if is_package_installed("redis"):
|
886
|
+
from opentelemetry.instrumentation.redis import RedisInstrumentor
|
887
|
+
|
888
|
+
instrumentor = RedisInstrumentor()
|
889
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
890
|
+
instrumentor.instrument(excluded_urls=EXCLUDED_URLS)
|
891
|
+
return True
|
892
|
+
except Exception as e:
|
893
|
+
logging.error(f"Error initializing redis instrumentor: {e}")
|
894
|
+
# Telemetry().log_exception(e)
|
895
|
+
return False
|
896
|
+
|
897
|
+
|
898
|
+
def init_groq_instrumentor():
|
899
|
+
try:
|
900
|
+
if is_package_installed("groq"):
|
901
|
+
# Telemetry().capture("instrumentation:groq:init")
|
902
|
+
from opentelemetry.instrumentation.groq import GroqInstrumentor
|
903
|
+
|
904
|
+
instrumentor = GroqInstrumentor(
|
905
|
+
# exception_logger=lambda e: Telemetry().log_exception(e),
|
906
|
+
)
|
907
|
+
if not instrumentor.is_instrumented_by_opentelemetry:
|
908
|
+
instrumentor.instrument()
|
909
|
+
return True
|
910
|
+
except Exception as e:
|
911
|
+
logging.error(f"Error initializing Groq instrumentor: {e}")
|
912
|
+
# Telemetry().log_exception(e)
|
913
|
+
return False
|