monocle-apptrace 0.3.1__py3-none-any.whl → 0.4.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.
Potentially problematic release.
This version of monocle-apptrace might be problematic. Click here for more details.
- monocle_apptrace/exporters/aws/s3_exporter.py +3 -1
- monocle_apptrace/exporters/azure/blob_exporter.py +2 -2
- monocle_apptrace/exporters/base_exporter.py +10 -4
- monocle_apptrace/exporters/file_exporter.py +19 -4
- monocle_apptrace/exporters/monocle_exporters.py +3 -3
- monocle_apptrace/exporters/okahu/okahu_exporter.py +5 -2
- monocle_apptrace/instrumentation/common/constants.py +9 -5
- monocle_apptrace/instrumentation/common/instrumentor.py +24 -13
- monocle_apptrace/instrumentation/common/span_handler.py +79 -38
- monocle_apptrace/instrumentation/common/utils.py +90 -54
- monocle_apptrace/instrumentation/common/wrapper.py +193 -40
- monocle_apptrace/instrumentation/common/wrapper_method.py +13 -6
- monocle_apptrace/instrumentation/metamodel/aiohttp/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +66 -0
- monocle_apptrace/instrumentation/metamodel/aiohttp/entities/http.py +51 -0
- monocle_apptrace/instrumentation/metamodel/aiohttp/methods.py +13 -0
- monocle_apptrace/instrumentation/metamodel/flask/_helper.py +8 -3
- monocle_apptrace/instrumentation/metamodel/flask/entities/http.py +0 -1
- monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +17 -4
- monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +1 -1
- monocle_apptrace/instrumentation/metamodel/haystack/methods.py +8 -1
- monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +1 -1
- monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +13 -9
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +1 -1
- monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +14 -0
- monocle_apptrace/instrumentation/metamodel/openai/_helper.py +26 -5
- monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +184 -26
- monocle_apptrace/instrumentation/metamodel/openai/methods.py +6 -6
- monocle_apptrace/instrumentation/metamodel/requests/_helper.py +1 -1
- monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +55 -5
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +13 -33
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +24 -20
- monocle_apptrace/instrumentation/metamodel/teamsai/methods.py +54 -8
- {monocle_apptrace-0.3.1.dist-info → monocle_apptrace-0.4.0.dist-info}/METADATA +22 -18
- {monocle_apptrace-0.3.1.dist-info → monocle_apptrace-0.4.0.dist-info}/RECORD +38 -34
- {monocle_apptrace-0.3.1.dist-info → monocle_apptrace-0.4.0.dist-info}/WHEEL +0 -0
- {monocle_apptrace-0.3.1.dist-info → monocle_apptrace-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {monocle_apptrace-0.3.1.dist-info → monocle_apptrace-0.4.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import logging, json
|
|
2
2
|
import os
|
|
3
|
+
import traceback
|
|
3
4
|
from typing import Callable, Generic, Optional, TypeVar, Mapping
|
|
4
|
-
import threading, asyncio
|
|
5
5
|
|
|
6
6
|
from opentelemetry.context import attach, detach, get_current, get_value, set_value, Context
|
|
7
|
-
from opentelemetry.trace import NonRecordingSpan, Span
|
|
7
|
+
from opentelemetry.trace import NonRecordingSpan, Span
|
|
8
8
|
from opentelemetry.trace.propagation import _SPAN_KEY
|
|
9
9
|
from opentelemetry.sdk.trace import id_generator, TracerProvider
|
|
10
|
-
from opentelemetry.propagate import
|
|
10
|
+
from opentelemetry.propagate import extract
|
|
11
11
|
from opentelemetry import baggage
|
|
12
12
|
from monocle_apptrace.instrumentation.common.constants import MONOCLE_SCOPE_NAME_PREFIX, SCOPE_METHOD_FILE, SCOPE_CONFIG_PATH, llm_type_map, MONOCLE_SDK_VERSION, ADD_NEW_WORKFLOW
|
|
13
13
|
from importlib.metadata import version
|
|
@@ -17,7 +17,6 @@ U = TypeVar('U')
|
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger(__name__)
|
|
19
19
|
|
|
20
|
-
monocle_tracer_provider: TracerProvider = None
|
|
21
20
|
embedding_model_context = {}
|
|
22
21
|
scope_id_generator = id_generator.RandomIdGenerator()
|
|
23
22
|
http_scopes:dict[str:str] = {}
|
|
@@ -43,14 +42,6 @@ class MonocleSpanException(Exception):
|
|
|
43
42
|
"""String representation of the exception."""
|
|
44
43
|
return f"[Monocle Span Error: {self.message} {self.status}"
|
|
45
44
|
|
|
46
|
-
def set_tracer_provider(tracer_provider: TracerProvider):
|
|
47
|
-
global monocle_tracer_provider
|
|
48
|
-
monocle_tracer_provider = tracer_provider
|
|
49
|
-
|
|
50
|
-
def get_tracer_provider() -> TracerProvider:
|
|
51
|
-
global monocle_tracer_provider
|
|
52
|
-
return monocle_tracer_provider
|
|
53
|
-
|
|
54
45
|
def set_span_attribute(span, name, value):
|
|
55
46
|
if value is not None:
|
|
56
47
|
if value != "":
|
|
@@ -93,7 +84,12 @@ def with_tracer_wrapper(func):
|
|
|
93
84
|
except Exception as e:
|
|
94
85
|
logger.error("Exception in attaching parent context: %s", e)
|
|
95
86
|
|
|
96
|
-
|
|
87
|
+
if traceback.extract_stack().__len__() > 2:
|
|
88
|
+
filename, line_number, _, _ = traceback.extract_stack()[-2]
|
|
89
|
+
source_path = f"{filename}:{line_number}"
|
|
90
|
+
else:
|
|
91
|
+
source_path = ""
|
|
92
|
+
val = func(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs)
|
|
97
93
|
return val
|
|
98
94
|
|
|
99
95
|
return wrapper
|
|
@@ -240,6 +236,13 @@ def set_scopes_from_baggage(baggage_context:Context):
|
|
|
240
236
|
scope_name = scope_key[len(MONOCLE_SCOPE_NAME_PREFIX):]
|
|
241
237
|
set_scope(scope_name, scope_value)
|
|
242
238
|
|
|
239
|
+
def get_parent_span() -> Span:
|
|
240
|
+
parent_span: Span = None
|
|
241
|
+
_parent_span_context = get_current()
|
|
242
|
+
if _parent_span_context is not None and _parent_span_context.get(_SPAN_KEY, None):
|
|
243
|
+
parent_span = _parent_span_context.get(_SPAN_KEY, None)
|
|
244
|
+
return parent_span
|
|
245
|
+
|
|
243
246
|
def extract_http_headers(headers) -> object:
|
|
244
247
|
global http_scopes
|
|
245
248
|
trace_context:Context = extract(headers, context=get_current())
|
|
@@ -275,49 +278,44 @@ async def http_async_route_handler(func, *args, **kwargs):
|
|
|
275
278
|
headers = kwargs['req'].headers
|
|
276
279
|
else:
|
|
277
280
|
headers = None
|
|
278
|
-
return async_wrapper(func, None, None, headers, *args, **kwargs)
|
|
279
|
-
|
|
280
|
-
def run_async_with_scope(method, current_context, exceptions, *args, **kwargs):
|
|
281
|
-
token = None
|
|
282
281
|
try:
|
|
283
|
-
if
|
|
284
|
-
token =
|
|
285
|
-
return
|
|
286
|
-
except Exception as e:
|
|
287
|
-
exceptions['exception'] = e
|
|
288
|
-
raise e
|
|
282
|
+
if headers is not None:
|
|
283
|
+
token = extract_http_headers(headers)
|
|
284
|
+
return await func(*args, **kwargs)
|
|
289
285
|
finally:
|
|
290
|
-
if token:
|
|
291
|
-
|
|
286
|
+
if token is not None:
|
|
287
|
+
clear_http_scopes(token)
|
|
292
288
|
|
|
293
|
-
def
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
289
|
+
# def run_async_with_scope(method, current_context, exceptions, *args, **kwargs):
|
|
290
|
+
# token = None
|
|
291
|
+
# try:
|
|
292
|
+
# if current_context:
|
|
293
|
+
# token = attach(current_context)
|
|
294
|
+
# return asyncio.run(method(*args, **kwargs))
|
|
295
|
+
# except Exception as e:
|
|
296
|
+
# exceptions['exception'] = e
|
|
297
|
+
# raise e
|
|
298
|
+
# finally:
|
|
299
|
+
# if token:
|
|
300
|
+
# detach(token)
|
|
301
|
+
|
|
302
|
+
# async def async_wrapper(method, headers=None, *args, **kwargs):
|
|
303
|
+
# current_context = get_current()
|
|
304
|
+
# try:
|
|
305
|
+
# if run_loop and run_loop.is_running():
|
|
306
|
+
# results = []
|
|
307
|
+
# thread = threading.Thread(target=lambda: results.append(run_async_with_scope(method, current_context, exceptions, *args, **kwargs)))
|
|
308
|
+
# thread.start()
|
|
309
|
+
# thread.join()
|
|
310
|
+
# if 'exception' in exceptions:
|
|
311
|
+
# raise exceptions['exception']
|
|
312
|
+
# return_value = results[0] if len(results) > 0 else None
|
|
313
|
+
# return return_value
|
|
314
|
+
# else:
|
|
315
|
+
# return run_async_with_scope(method, None, exceptions, *args, **kwargs)
|
|
316
|
+
# finally:
|
|
317
|
+
# if token:
|
|
318
|
+
# remove_scope(token)
|
|
321
319
|
|
|
322
320
|
def get_monocle_version() -> str:
|
|
323
321
|
global monocle_sdk_version
|
|
@@ -365,7 +363,45 @@ def try_option(func: Callable[..., T], *args, **kwargs) -> Option[T]:
|
|
|
365
363
|
def get_llm_type(instance):
|
|
366
364
|
try:
|
|
367
365
|
t_name = type(instance).__name__.lower()
|
|
368
|
-
|
|
366
|
+
t_name = t_name.replace("async", "") if "async" in t_name else t_name
|
|
367
|
+
llm_type = llm_type_map.get(t_name)
|
|
369
368
|
return llm_type
|
|
370
369
|
except:
|
|
371
370
|
pass
|
|
371
|
+
|
|
372
|
+
def get_status(arguments):
|
|
373
|
+
if arguments['exception'] is not None:
|
|
374
|
+
return 'error'
|
|
375
|
+
else:
|
|
376
|
+
return 'success'
|
|
377
|
+
|
|
378
|
+
def get_exception_status_code(arguments):
|
|
379
|
+
if arguments['exception'] is not None and hasattr(arguments['exception'], 'code'):
|
|
380
|
+
return arguments['exception'].code
|
|
381
|
+
else:
|
|
382
|
+
return 'error'
|
|
383
|
+
|
|
384
|
+
def get_exception_message(arguments):
|
|
385
|
+
if arguments['exception'] is not None:
|
|
386
|
+
if hasattr(arguments['exception'], 'message'):
|
|
387
|
+
return arguments['exception'].message
|
|
388
|
+
else:
|
|
389
|
+
return arguments['exception'].__str__()
|
|
390
|
+
else:
|
|
391
|
+
return ''
|
|
392
|
+
|
|
393
|
+
def patch_instance_method(obj, method_name, func):
|
|
394
|
+
"""
|
|
395
|
+
Patch a special method (like __iter__) for a single instance.
|
|
396
|
+
|
|
397
|
+
Args:
|
|
398
|
+
obj: the instance to patch
|
|
399
|
+
method_name: the name of the method (e.g., '__iter__')
|
|
400
|
+
func: the new function, expecting (self, ...)
|
|
401
|
+
"""
|
|
402
|
+
cls = obj.__class__
|
|
403
|
+
# Dynamically create a new class that inherits from obj's class
|
|
404
|
+
new_cls = type(f"Patched{cls.__name__}", (cls,), {
|
|
405
|
+
method_name: func
|
|
406
|
+
})
|
|
407
|
+
obj.__class__ = new_cls
|
|
@@ -6,78 +6,185 @@ from opentelemetry.context import set_value, attach, detach, get_value
|
|
|
6
6
|
from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
|
|
7
7
|
from monocle_apptrace.instrumentation.common.utils import (
|
|
8
8
|
get_fully_qualified_class_name,
|
|
9
|
+
set_scopes,
|
|
9
10
|
with_tracer_wrapper,
|
|
10
11
|
set_scope,
|
|
11
12
|
remove_scope,
|
|
12
|
-
|
|
13
|
+
get_parent_span
|
|
13
14
|
)
|
|
14
15
|
from monocle_apptrace.instrumentation.common.constants import WORKFLOW_TYPE_KEY, ADD_NEW_WORKFLOW
|
|
15
16
|
logger = logging.getLogger(__name__)
|
|
16
17
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
def get_auto_close_span(to_wrap, kwargs):
|
|
19
|
+
try:
|
|
20
|
+
if to_wrap.get("output_processor") and to_wrap.get("output_processor").get("is_auto_close"):
|
|
21
|
+
return to_wrap.get("output_processor").get("is_auto_close")(kwargs)
|
|
22
|
+
return True
|
|
23
|
+
except Exception as e:
|
|
24
|
+
logger.warning("Warning: Error occurred in get_auto_close_span: %s", str(e))
|
|
25
|
+
return True
|
|
26
|
+
|
|
27
|
+
def pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path):
|
|
28
|
+
SpanHandler.set_default_monocle_attributes(span, source_path)
|
|
29
|
+
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
30
|
+
# This is a direct API call of a non-framework type
|
|
31
|
+
SpanHandler.set_workflow_properties(span, to_wrap)
|
|
32
|
+
else:
|
|
33
|
+
SpanHandler.set_non_workflow_properties(span)
|
|
34
|
+
try:
|
|
35
|
+
handler.pre_task_processing(to_wrap, wrapped, instance, args, kwargs, span)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.info(f"Warning: Error occurred in pre_task_processing: {e}")
|
|
21
38
|
|
|
39
|
+
def post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, return_value, span, parent_span=None, ex = None):
|
|
40
|
+
if not (SpanHandler.is_root_span(span) or get_value(ADD_NEW_WORKFLOW) == True):
|
|
41
|
+
try:
|
|
42
|
+
handler.hydrate_span(to_wrap, wrapped, instance, args, kwargs, return_value, span, parent_span, ex)
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logger.info(f"Warning: Error occurred in hydrate_span: {e}")
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
handler.post_task_processing(to_wrap, wrapped, instance, args, kwargs, return_value, span)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
logger.info(f"Warning: Error occurred in post_task_processing: {e}")
|
|
50
|
+
|
|
51
|
+
def get_span_name(to_wrap, instance):
|
|
22
52
|
if to_wrap.get("span_name"):
|
|
23
53
|
name = to_wrap.get("span_name")
|
|
24
54
|
else:
|
|
25
55
|
name = get_fully_qualified_class_name(instance)
|
|
56
|
+
return name
|
|
57
|
+
|
|
58
|
+
def monocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
|
|
59
|
+
# Main span processing logic
|
|
60
|
+
name = get_span_name(to_wrap, instance)
|
|
61
|
+
return_value = None
|
|
62
|
+
span_status = None
|
|
63
|
+
auto_close_span = get_auto_close_span(to_wrap, kwargs)
|
|
64
|
+
parent_span = get_parent_span()
|
|
65
|
+
with tracer.start_as_current_span(name, end_on_exit=auto_close_span) as span:
|
|
66
|
+
pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path)
|
|
67
|
+
|
|
68
|
+
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
69
|
+
# Recursive call for the actual span
|
|
70
|
+
return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
|
|
71
|
+
span.set_status(span_status)
|
|
72
|
+
if not auto_close_span:
|
|
73
|
+
span.end()
|
|
74
|
+
else:
|
|
75
|
+
ex:Exception = None
|
|
76
|
+
try:
|
|
77
|
+
with SpanHandler.workflow_type(to_wrap, span):
|
|
78
|
+
return_value = wrapped(*args, **kwargs)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
ex = e
|
|
81
|
+
raise
|
|
82
|
+
finally:
|
|
83
|
+
def post_process_span_internal(ret_val):
|
|
84
|
+
post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span ,ex)
|
|
85
|
+
if not auto_close_span:
|
|
86
|
+
span.end()
|
|
87
|
+
if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
|
|
88
|
+
to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
|
|
89
|
+
else:
|
|
90
|
+
post_process_span_internal(return_value)
|
|
91
|
+
span_status = span.status
|
|
92
|
+
return return_value, span_status
|
|
26
93
|
|
|
94
|
+
def monocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
27
95
|
return_value = None
|
|
28
96
|
token = None
|
|
29
97
|
try:
|
|
30
|
-
|
|
98
|
+
try:
|
|
99
|
+
handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
logger.info(f"Warning: Error occurred in pre_tracing: {e}")
|
|
31
102
|
if to_wrap.get('skip_span', False) or handler.skip_span(to_wrap, wrapped, instance, args, kwargs):
|
|
32
|
-
|
|
33
|
-
return_value = async_wrapper(wrapped, None, None, None, *args, **kwargs)
|
|
34
|
-
else:
|
|
35
|
-
return_value = wrapped(*args, **kwargs)
|
|
103
|
+
return_value = wrapped(*args, **kwargs)
|
|
36
104
|
else:
|
|
37
105
|
add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
|
|
38
106
|
token = attach(set_value(ADD_NEW_WORKFLOW, False))
|
|
39
107
|
try:
|
|
40
|
-
return_value =
|
|
41
|
-
to_wrap, wrapped, instance, args, kwargs)
|
|
108
|
+
return_value, span_status = monocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs)
|
|
42
109
|
finally:
|
|
43
110
|
detach(token)
|
|
44
111
|
return return_value
|
|
45
112
|
finally:
|
|
46
|
-
|
|
113
|
+
try:
|
|
114
|
+
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.info(f"Warning: Error occurred in post_tracing: {e}")
|
|
47
117
|
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
|
|
118
|
+
async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
|
|
119
|
+
# Main span processing logic
|
|
120
|
+
name = get_span_name(to_wrap, instance)
|
|
51
121
|
return_value = None
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
122
|
+
span_status = None
|
|
123
|
+
auto_close_span = get_auto_close_span(to_wrap, kwargs)
|
|
124
|
+
parent_span = get_parent_span()
|
|
125
|
+
with tracer.start_as_current_span(name, end_on_exit=auto_close_span) as span:
|
|
126
|
+
pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path)
|
|
127
|
+
|
|
55
128
|
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
56
|
-
#
|
|
57
|
-
|
|
58
|
-
|
|
129
|
+
# Recursive call for the actual span
|
|
130
|
+
return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs)
|
|
131
|
+
span.set_status(span_status)
|
|
132
|
+
if not auto_close_span:
|
|
133
|
+
span.end()
|
|
59
134
|
else:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
135
|
+
ex:Exception = None
|
|
136
|
+
try:
|
|
137
|
+
with SpanHandler.workflow_type(to_wrap, span):
|
|
138
|
+
return_value = await wrapped(*args, **kwargs)
|
|
139
|
+
except Exception as e:
|
|
140
|
+
ex = e
|
|
141
|
+
raise
|
|
142
|
+
finally:
|
|
143
|
+
def post_process_span_internal(ret_val):
|
|
144
|
+
post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span,ex)
|
|
145
|
+
if not auto_close_span:
|
|
146
|
+
span.end()
|
|
147
|
+
if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
|
|
148
|
+
to_wrap.get("output_processor").get("response_processor")(to_wrap, return_value, post_process_span_internal)
|
|
149
|
+
else:
|
|
150
|
+
post_process_span_internal(return_value)
|
|
151
|
+
span_status = span.status
|
|
152
|
+
return return_value, span.status
|
|
153
|
+
|
|
154
|
+
async def amonocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
155
|
+
return_value = None
|
|
156
|
+
token = None
|
|
157
|
+
try:
|
|
158
|
+
try:
|
|
159
|
+
handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
160
|
+
except Exception as e:
|
|
161
|
+
logger.info(f"Warning: Error occurred in pre_tracing: {e}")
|
|
162
|
+
if to_wrap.get('skip_span', False) or handler.skip_span(to_wrap, wrapped, instance, args, kwargs):
|
|
163
|
+
return_value = await wrapped(*args, **kwargs)
|
|
164
|
+
else:
|
|
165
|
+
add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
|
|
166
|
+
token = attach(set_value(ADD_NEW_WORKFLOW, False))
|
|
167
|
+
try:
|
|
168
|
+
return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs)
|
|
169
|
+
finally:
|
|
170
|
+
detach(token)
|
|
171
|
+
return return_value
|
|
172
|
+
finally:
|
|
173
|
+
try:
|
|
174
|
+
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
175
|
+
except Exception as e:
|
|
176
|
+
logger.info(f"Warning: Error occurred in post_tracing: {e}")
|
|
70
177
|
|
|
71
178
|
@with_tracer_wrapper
|
|
72
|
-
def task_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, args, kwargs):
|
|
73
|
-
return
|
|
179
|
+
def task_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
180
|
+
return monocle_wrapper(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs)
|
|
74
181
|
|
|
75
182
|
@with_tracer_wrapper
|
|
76
|
-
async def atask_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, args, kwargs):
|
|
77
|
-
return
|
|
183
|
+
async def atask_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
184
|
+
return await amonocle_wrapper(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs)
|
|
78
185
|
|
|
79
186
|
@with_tracer_wrapper
|
|
80
|
-
def scope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, args, kwargs):
|
|
187
|
+
def scope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
81
188
|
scope_name = to_wrap.get('scope_name', None)
|
|
82
189
|
if scope_name:
|
|
83
190
|
token = set_scope(scope_name)
|
|
@@ -87,8 +194,54 @@ def scope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instan
|
|
|
87
194
|
return return_value
|
|
88
195
|
|
|
89
196
|
@with_tracer_wrapper
|
|
90
|
-
async def ascope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, args, kwargs):
|
|
197
|
+
async def ascope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
91
198
|
scope_name = to_wrap.get('scope_name', None)
|
|
92
199
|
scope_value = to_wrap.get('scope_value', None)
|
|
93
|
-
|
|
94
|
-
|
|
200
|
+
token = None
|
|
201
|
+
try:
|
|
202
|
+
if scope_name:
|
|
203
|
+
token = set_scope(scope_name, scope_value)
|
|
204
|
+
return_value = await wrapped(*args, **kwargs)
|
|
205
|
+
return return_value
|
|
206
|
+
finally:
|
|
207
|
+
if token:
|
|
208
|
+
remove_scope(token)
|
|
209
|
+
|
|
210
|
+
@with_tracer_wrapper
|
|
211
|
+
def scopes_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
212
|
+
scope_values = to_wrap.get('scope_values', None)
|
|
213
|
+
scope_values = evaluate_scope_values(args, kwargs, to_wrap, scope_values)
|
|
214
|
+
token = None
|
|
215
|
+
try:
|
|
216
|
+
if scope_values:
|
|
217
|
+
token = set_scopes(scope_values)
|
|
218
|
+
return_value = wrapped(*args, **kwargs)
|
|
219
|
+
return return_value
|
|
220
|
+
finally:
|
|
221
|
+
if token:
|
|
222
|
+
remove_scope(token)
|
|
223
|
+
|
|
224
|
+
@with_tracer_wrapper
|
|
225
|
+
async def ascopes_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
226
|
+
scope_values = to_wrap.get('scope_values', None)
|
|
227
|
+
scope_values = evaluate_scope_values(args, kwargs, to_wrap, scope_values)
|
|
228
|
+
token = None
|
|
229
|
+
try:
|
|
230
|
+
if scope_values:
|
|
231
|
+
token = set_scopes(scope_values)
|
|
232
|
+
return_value = await wrapped(*args, **kwargs)
|
|
233
|
+
return return_value
|
|
234
|
+
finally:
|
|
235
|
+
if token:
|
|
236
|
+
remove_scope(token)
|
|
237
|
+
|
|
238
|
+
def evaluate_scope_values(args, kwargs, to_wrap, scope_values):
|
|
239
|
+
if callable(scope_values):
|
|
240
|
+
try:
|
|
241
|
+
scope_values = scope_values(args, kwargs)
|
|
242
|
+
except Exception as e:
|
|
243
|
+
logger.warning("Warning: Error occurred in evaluate_scope_values: %s", str(e))
|
|
244
|
+
scope_values = None
|
|
245
|
+
if isinstance(scope_values, dict):
|
|
246
|
+
return scope_values
|
|
247
|
+
return None
|
|
@@ -10,6 +10,7 @@ from monocle_apptrace.instrumentation.metamodel.langchain.methods import (
|
|
|
10
10
|
from monocle_apptrace.instrumentation.metamodel.llamaindex.methods import (LLAMAINDEX_METHODS, )
|
|
11
11
|
from monocle_apptrace.instrumentation.metamodel.haystack.methods import (HAYSTACK_METHODS, )
|
|
12
12
|
from monocle_apptrace.instrumentation.metamodel.openai.methods import (OPENAI_METHODS,)
|
|
13
|
+
from monocle_apptrace.instrumentation.metamodel.openai._helper import OpenAISpanHandler
|
|
13
14
|
from monocle_apptrace.instrumentation.metamodel.langgraph.methods import LANGGRAPH_METHODS
|
|
14
15
|
from monocle_apptrace.instrumentation.metamodel.flask.methods import (FLASK_METHODS, )
|
|
15
16
|
from monocle_apptrace.instrumentation.metamodel.flask._helper import FlaskSpanHandler, FlaskResponseSpanHandler
|
|
@@ -17,7 +18,8 @@ from monocle_apptrace.instrumentation.metamodel.requests.methods import (REQUEST
|
|
|
17
18
|
from monocle_apptrace.instrumentation.metamodel.requests._helper import RequestSpanHandler
|
|
18
19
|
from monocle_apptrace.instrumentation.metamodel.teamsai.methods import (TEAMAI_METHODS, )
|
|
19
20
|
from monocle_apptrace.instrumentation.metamodel.anthropic.methods import (ANTHROPIC_METHODS, )
|
|
20
|
-
|
|
21
|
+
from monocle_apptrace.instrumentation.metamodel.aiohttp.methods import (AIOHTTP_METHODS, )
|
|
22
|
+
from monocle_apptrace.instrumentation.metamodel.aiohttp._helper import aiohttpSpanHandler
|
|
21
23
|
class WrapperMethod:
|
|
22
24
|
def __init__(
|
|
23
25
|
self,
|
|
@@ -29,7 +31,8 @@ class WrapperMethod:
|
|
|
29
31
|
wrapper_method = task_wrapper,
|
|
30
32
|
span_handler = 'default',
|
|
31
33
|
scope_name: str = None,
|
|
32
|
-
span_type: str = None
|
|
34
|
+
span_type: str = None,
|
|
35
|
+
scope_values = None,
|
|
33
36
|
):
|
|
34
37
|
self.package = package
|
|
35
38
|
self.object = object_name
|
|
@@ -37,10 +40,11 @@ class WrapperMethod:
|
|
|
37
40
|
self.span_name = span_name
|
|
38
41
|
self.output_processor=output_processor
|
|
39
42
|
self.span_type = span_type
|
|
43
|
+
self.scope_values = scope_values
|
|
40
44
|
|
|
41
45
|
self.span_handler:SpanHandler.__class__ = span_handler
|
|
42
46
|
self.scope_name = scope_name
|
|
43
|
-
if scope_name:
|
|
47
|
+
if scope_name and not scope_values:
|
|
44
48
|
self.wrapper_method = scope_wrapper
|
|
45
49
|
else:
|
|
46
50
|
self.wrapper_method = wrapper_method
|
|
@@ -56,20 +60,23 @@ class WrapperMethod:
|
|
|
56
60
|
'wrapper_method': self.wrapper_method,
|
|
57
61
|
'span_handler': self.span_handler,
|
|
58
62
|
'scope_name': self.scope_name,
|
|
59
|
-
'span_type': self.span_type
|
|
63
|
+
'span_type': self.span_type,
|
|
64
|
+
'scope_values': self.scope_values,
|
|
60
65
|
}
|
|
61
66
|
return instance_dict
|
|
62
67
|
|
|
63
68
|
def get_span_handler(self) -> SpanHandler:
|
|
64
69
|
return self.span_handler()
|
|
65
70
|
|
|
66
|
-
DEFAULT_METHODS_LIST = LANGCHAIN_METHODS + LLAMAINDEX_METHODS + HAYSTACK_METHODS + BOTOCORE_METHODS + FLASK_METHODS + REQUESTS_METHODS + LANGGRAPH_METHODS + OPENAI_METHODS + TEAMAI_METHODS + ANTHROPIC_METHODS
|
|
71
|
+
DEFAULT_METHODS_LIST = LANGCHAIN_METHODS + LLAMAINDEX_METHODS + HAYSTACK_METHODS + BOTOCORE_METHODS + FLASK_METHODS + REQUESTS_METHODS + LANGGRAPH_METHODS + OPENAI_METHODS + TEAMAI_METHODS + ANTHROPIC_METHODS + AIOHTTP_METHODS
|
|
67
72
|
|
|
68
73
|
MONOCLE_SPAN_HANDLERS: Dict[str, SpanHandler] = {
|
|
69
74
|
"default": SpanHandler(),
|
|
75
|
+
"aiohttp_handler": aiohttpSpanHandler(),
|
|
70
76
|
"botocore_handler": BotoCoreSpanHandler(),
|
|
71
77
|
"flask_handler": FlaskSpanHandler(),
|
|
72
78
|
"flask_response_handler": FlaskResponseSpanHandler(),
|
|
73
79
|
"request_handler": RequestSpanHandler(),
|
|
74
|
-
"non_framework_handler": NonFrameworkSpanHandler()
|
|
80
|
+
"non_framework_handler": NonFrameworkSpanHandler(),
|
|
81
|
+
"openai_handler": OpenAISpanHandler(),
|
|
75
82
|
}
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from threading import local
|
|
3
|
+
from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, try_option, Option, MonocleSpanException
|
|
4
|
+
from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
|
|
5
|
+
from monocle_apptrace.instrumentation.common.constants import HTTP_SUCCESS_CODES
|
|
6
|
+
from urllib.parse import unquote
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
MAX_DATA_LENGTH = 1000
|
|
10
|
+
token_data = local()
|
|
11
|
+
token_data.current_token = None
|
|
12
|
+
|
|
13
|
+
def get_route(args) -> str:
|
|
14
|
+
route_path: Option[str] = try_option(getattr, args[0], 'path')
|
|
15
|
+
return route_path.unwrap_or("")
|
|
16
|
+
|
|
17
|
+
def get_method(args) -> str:
|
|
18
|
+
# return args[0]['method'] if 'method' in args[0] else ""
|
|
19
|
+
http_method: Option[str] = try_option(getattr, args[0], 'method')
|
|
20
|
+
return http_method.unwrap_or("")
|
|
21
|
+
|
|
22
|
+
def get_params(args) -> dict:
|
|
23
|
+
params: Option[str] = try_option(getattr, args[0], 'query_string')
|
|
24
|
+
return unquote(params.unwrap_or(""))
|
|
25
|
+
|
|
26
|
+
def get_body(args) -> dict:
|
|
27
|
+
return ""
|
|
28
|
+
|
|
29
|
+
def extract_response(result) -> str:
|
|
30
|
+
if hasattr(result, 'text'):
|
|
31
|
+
response = result.text[0:max(result.text.__len__(), MAX_DATA_LENGTH)]
|
|
32
|
+
else:
|
|
33
|
+
response = ""
|
|
34
|
+
return response
|
|
35
|
+
|
|
36
|
+
def extract_status(result) -> str:
|
|
37
|
+
status = f"{result.status}" if hasattr(result, 'status') else ""
|
|
38
|
+
if status not in HTTP_SUCCESS_CODES:
|
|
39
|
+
error_message = extract_response(result)
|
|
40
|
+
raise MonocleSpanException(f"error: {status} - {error_message}")
|
|
41
|
+
return status
|
|
42
|
+
|
|
43
|
+
def aiohttp_pre_tracing(args):
|
|
44
|
+
token_data.current_token = extract_http_headers(args[0].headers)
|
|
45
|
+
|
|
46
|
+
def aiohttp_post_tracing():
|
|
47
|
+
clear_http_scopes(token_data.current_token)
|
|
48
|
+
token_data.current_token = None
|
|
49
|
+
|
|
50
|
+
def aiohttp_skip_span(args) -> bool:
|
|
51
|
+
if get_method(args) == "HEAD":
|
|
52
|
+
return True
|
|
53
|
+
return False
|
|
54
|
+
|
|
55
|
+
class aiohttpSpanHandler(SpanHandler):
|
|
56
|
+
|
|
57
|
+
def pre_tracing(self, to_wrap, wrapped, instance, args, kwargs):
|
|
58
|
+
aiohttp_pre_tracing(args)
|
|
59
|
+
return super().pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
60
|
+
|
|
61
|
+
def post_tracing(self, to_wrap, wrapped, instance, args, kwargs, return_value):
|
|
62
|
+
aiohttp_post_tracing()
|
|
63
|
+
return super().post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
64
|
+
|
|
65
|
+
def skip_span(self, to_wrap, wrapped, instance, args, kwargs) -> bool:
|
|
66
|
+
return aiohttp_skip_span(args)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.metamodel.aiohttp import _helper
|
|
2
|
+
AIO_HTTP_PROCESSOR = {
|
|
3
|
+
"type": "http.process",
|
|
4
|
+
"attributes": [
|
|
5
|
+
[
|
|
6
|
+
{
|
|
7
|
+
"_comment": "request method, request URI",
|
|
8
|
+
"attribute": "method",
|
|
9
|
+
"accessor": lambda arguments: _helper.get_method(arguments['args'])
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"_comment": "request method, request URI",
|
|
13
|
+
"attribute": "route",
|
|
14
|
+
"accessor": lambda arguments: _helper.get_route(arguments['args'])
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"_comment": "request method, request URI",
|
|
18
|
+
"attribute": "body",
|
|
19
|
+
"accessor": lambda arguments: _helper.get_body(arguments['args'])
|
|
20
|
+
},
|
|
21
|
+
]
|
|
22
|
+
],
|
|
23
|
+
"events": [
|
|
24
|
+
{
|
|
25
|
+
"name": "data.input",
|
|
26
|
+
"attributes": [
|
|
27
|
+
{
|
|
28
|
+
"_comment": "route params",
|
|
29
|
+
"attribute": "params",
|
|
30
|
+
"accessor": lambda arguments: _helper.get_params(arguments['args'])
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "data.output",
|
|
36
|
+
"attributes": [
|
|
37
|
+
{
|
|
38
|
+
"_comment": "status from HTTP response",
|
|
39
|
+
"attribute": "status",
|
|
40
|
+
"accessor": lambda arguments: _helper.extract_status(arguments['result'])
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"_comment": "this is result from LLM",
|
|
44
|
+
"attribute": "response",
|
|
45
|
+
"accessor": lambda arguments: _helper.extract_response(arguments['result'])
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
]
|
|
51
|
+
}
|