monocle-apptrace 0.4.1__py3-none-any.whl → 0.5.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/__main__.py +1 -1
- monocle_apptrace/exporters/file_exporter.py +125 -37
- monocle_apptrace/instrumentation/common/__init__.py +16 -1
- monocle_apptrace/instrumentation/common/constants.py +14 -1
- monocle_apptrace/instrumentation/common/instrumentor.py +19 -152
- monocle_apptrace/instrumentation/common/method_wrappers.py +376 -0
- monocle_apptrace/instrumentation/common/span_handler.py +58 -32
- monocle_apptrace/instrumentation/common/utils.py +52 -15
- monocle_apptrace/instrumentation/common/wrapper.py +124 -18
- monocle_apptrace/instrumentation/common/wrapper_method.py +48 -1
- monocle_apptrace/instrumentation/metamodel/a2a/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/a2a/_helper.py +37 -0
- monocle_apptrace/instrumentation/metamodel/a2a/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +112 -0
- monocle_apptrace/instrumentation/metamodel/a2a/methods.py +22 -0
- monocle_apptrace/instrumentation/metamodel/adk/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/adk/_helper.py +182 -0
- monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +50 -0
- monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +57 -0
- monocle_apptrace/instrumentation/metamodel/adk/methods.py +24 -0
- monocle_apptrace/instrumentation/metamodel/agents/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/agents/_helper.py +220 -0
- monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +152 -0
- monocle_apptrace/instrumentation/metamodel/agents/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +191 -0
- monocle_apptrace/instrumentation/metamodel/agents/methods.py +56 -0
- monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +6 -11
- monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +112 -18
- monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +18 -10
- monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +13 -11
- monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +5 -0
- monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +88 -8
- monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +22 -8
- monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +92 -16
- monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +13 -8
- monocle_apptrace/instrumentation/metamodel/botocore/handlers/botocore_span_handler.py +1 -1
- monocle_apptrace/instrumentation/metamodel/fastapi/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +82 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +44 -0
- monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +23 -0
- monocle_apptrace/instrumentation/metamodel/finish_types.py +463 -0
- monocle_apptrace/instrumentation/metamodel/flask/_helper.py +6 -11
- monocle_apptrace/instrumentation/metamodel/gemini/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/gemini/_helper.py +120 -0
- monocle_apptrace/instrumentation/metamodel/gemini/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +86 -0
- monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +43 -0
- monocle_apptrace/instrumentation/metamodel/gemini/methods.py +31 -0
- monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +79 -8
- monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +15 -10
- monocle_apptrace/instrumentation/metamodel/haystack/methods.py +7 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +78 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +51 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/methods.py +23 -0
- monocle_apptrace/instrumentation/metamodel/lambdafunc/wrapper.py +23 -0
- monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +145 -19
- monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +19 -10
- monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +67 -10
- monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +127 -20
- monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +46 -0
- monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +35 -9
- monocle_apptrace/instrumentation/metamodel/litellm/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/litellm/_helper.py +89 -0
- monocle_apptrace/instrumentation/metamodel/litellm/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +108 -0
- monocle_apptrace/instrumentation/metamodel/litellm/methods.py +19 -0
- monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +227 -16
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +127 -10
- monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +13 -8
- monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +62 -0
- monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +68 -1
- monocle_apptrace/instrumentation/metamodel/mcp/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +118 -0
- monocle_apptrace/instrumentation/metamodel/mcp/entities/__init__.py +0 -0
- monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +48 -0
- monocle_apptrace/instrumentation/metamodel/mcp/mcp_processor.py +8 -0
- monocle_apptrace/instrumentation/metamodel/mcp/methods.py +21 -0
- monocle_apptrace/instrumentation/metamodel/openai/_helper.py +188 -16
- monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +148 -92
- monocle_apptrace/instrumentation/metamodel/openai/entities/retrieval.py +1 -1
- monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +53 -23
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +1 -1
- monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +15 -9
- monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +0 -4
- {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/METADATA +27 -11
- monocle_apptrace-0.5.0.dist-info/RECORD +142 -0
- monocle_apptrace-0.4.1.dist-info/RECORD +0 -96
- {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/WHEEL +0 -0
- {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/LICENSE +0 -0
- {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -11,6 +11,8 @@ 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
|
|
14
|
+
from opentelemetry.trace.span import INVALID_SPAN
|
|
15
|
+
_MONOCLE_SPAN_KEY = "monocle" + _SPAN_KEY
|
|
14
16
|
|
|
15
17
|
T = TypeVar('T')
|
|
16
18
|
U = TypeVar('U')
|
|
@@ -70,7 +72,7 @@ def with_tracer_wrapper(func):
|
|
|
70
72
|
"""Helper for providing tracer for wrapper functions."""
|
|
71
73
|
|
|
72
74
|
def _with_tracer(tracer, handler, to_wrap):
|
|
73
|
-
def wrapper(wrapped, instance, args, kwargs):
|
|
75
|
+
def wrapper(wrapped, instance, args, kwargs, source_path=None):
|
|
74
76
|
try:
|
|
75
77
|
# get and log the parent span context if injected by the application
|
|
76
78
|
# This is useful for debugging and tracing of Azure functions
|
|
@@ -83,12 +85,12 @@ def with_tracer_wrapper(func):
|
|
|
83
85
|
f"Parent span is found with trace id {hex(parent_span.get_span_context().trace_id)}")
|
|
84
86
|
except Exception as e:
|
|
85
87
|
logger.error("Exception in attaching parent context: %s", e)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
88
|
+
if not source_path:
|
|
89
|
+
if traceback.extract_stack().__len__() > 2:
|
|
90
|
+
filename, line_number, _, _ = traceback.extract_stack()[-2]
|
|
91
|
+
source_path = f"{filename}:{line_number}"
|
|
92
|
+
else:
|
|
93
|
+
source_path = ""
|
|
92
94
|
val = func(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs)
|
|
93
95
|
return val
|
|
94
96
|
|
|
@@ -152,13 +154,6 @@ def flatten_dict(d, parent_key='', sep='_'):
|
|
|
152
154
|
items.append((new_key, v))
|
|
153
155
|
return dict(items)
|
|
154
156
|
|
|
155
|
-
def get_fully_qualified_class_name(instance):
|
|
156
|
-
if instance is None:
|
|
157
|
-
return None
|
|
158
|
-
module_name = instance.__class__.__module__
|
|
159
|
-
qualname = instance.__class__.__qualname__
|
|
160
|
-
return f"{module_name}.{qualname}"
|
|
161
|
-
|
|
162
157
|
# returns json path like key probe in a dictionary
|
|
163
158
|
def get_nested_value(data, keys):
|
|
164
159
|
for key in keys:
|
|
@@ -330,6 +325,12 @@ def add_monocle_trace_state(headers:dict[str:str]) -> None:
|
|
|
330
325
|
else:
|
|
331
326
|
headers['tracestate'] = monocle_trace_state
|
|
332
327
|
|
|
328
|
+
def get_json_dumps(obj) -> str:
|
|
329
|
+
try:
|
|
330
|
+
return json.dumps(obj)
|
|
331
|
+
except TypeError as e:
|
|
332
|
+
return str(obj)
|
|
333
|
+
|
|
333
334
|
class Option(Generic[T]):
|
|
334
335
|
def __init__(self, value: Optional[T]):
|
|
335
336
|
self.value = value
|
|
@@ -392,6 +393,13 @@ def get_exception_message(arguments):
|
|
|
392
393
|
else:
|
|
393
394
|
return ''
|
|
394
395
|
|
|
396
|
+
def get_error_message(arguments):
|
|
397
|
+
status_code = get_status_code(arguments)
|
|
398
|
+
if status_code == 'success':
|
|
399
|
+
return ''
|
|
400
|
+
else:
|
|
401
|
+
return status_code
|
|
402
|
+
|
|
395
403
|
def get_status_code(arguments):
|
|
396
404
|
if arguments["exception"] is not None:
|
|
397
405
|
return get_exception_status_code(arguments)
|
|
@@ -422,4 +430,33 @@ def patch_instance_method(obj, method_name, func):
|
|
|
422
430
|
new_cls = type(f"Patched{cls.__name__}", (cls,), {
|
|
423
431
|
method_name: func
|
|
424
432
|
})
|
|
425
|
-
obj.__class__ = new_cls
|
|
433
|
+
obj.__class__ = new_cls
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def set_monocle_span_in_context(
|
|
437
|
+
span: Span, context: Optional[Context] = None
|
|
438
|
+
) -> Context:
|
|
439
|
+
"""Set the span in the given context.
|
|
440
|
+
|
|
441
|
+
Args:
|
|
442
|
+
span: The Span to set.
|
|
443
|
+
context: a Context object. if one is not passed, the
|
|
444
|
+
default current context is used instead.
|
|
445
|
+
"""
|
|
446
|
+
ctx = set_value(_MONOCLE_SPAN_KEY, span, context=context)
|
|
447
|
+
return ctx
|
|
448
|
+
|
|
449
|
+
def get_current_monocle_span(context: Optional[Context] = None) -> Span:
|
|
450
|
+
"""Retrieve the current span.
|
|
451
|
+
|
|
452
|
+
Args:
|
|
453
|
+
context: A Context object. If one is not passed, the
|
|
454
|
+
default current context is used instead.
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
The Span set in the context if it exists. INVALID_SPAN otherwise.
|
|
458
|
+
"""
|
|
459
|
+
span = get_value(_MONOCLE_SPAN_KEY, context=context)
|
|
460
|
+
if span is None or not isinstance(span, Span):
|
|
461
|
+
return INVALID_SPAN
|
|
462
|
+
return span
|
|
@@ -1,19 +1,28 @@
|
|
|
1
1
|
# pylint: disable=protected-access
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
import os
|
|
4
|
+
from typing import AsyncGenerator, Iterator, Optional
|
|
2
5
|
import logging
|
|
3
6
|
from opentelemetry.trace import Tracer
|
|
7
|
+
from opentelemetry.trace.propagation import _SPAN_KEY, set_span_in_context, get_current_span
|
|
8
|
+
from opentelemetry.trace import propagation
|
|
4
9
|
from opentelemetry.context import set_value, attach, detach, get_value
|
|
10
|
+
from opentelemetry.context import create_key, get_value, set_value
|
|
11
|
+
from opentelemetry.context.context import Context
|
|
12
|
+
from opentelemetry.trace.span import INVALID_SPAN, Span
|
|
5
13
|
|
|
6
14
|
from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
|
|
7
15
|
from monocle_apptrace.instrumentation.common.utils import (
|
|
8
|
-
get_fully_qualified_class_name,
|
|
9
16
|
set_scopes,
|
|
10
17
|
with_tracer_wrapper,
|
|
11
18
|
set_scope,
|
|
12
19
|
remove_scope,
|
|
13
|
-
|
|
20
|
+
get_current_monocle_span,
|
|
21
|
+
set_monocle_span_in_context
|
|
14
22
|
)
|
|
15
23
|
from monocle_apptrace.instrumentation.common.constants import WORKFLOW_TYPE_KEY, ADD_NEW_WORKFLOW
|
|
16
24
|
logger = logging.getLogger(__name__)
|
|
25
|
+
ISOLATE_MONOCLE_SPANS = os.getenv("MONOCLE_ISOLATE_SPANS", "true").lower() == "true"
|
|
17
26
|
|
|
18
27
|
def get_auto_close_span(to_wrap, kwargs):
|
|
19
28
|
try:
|
|
@@ -36,15 +45,17 @@ def pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped,
|
|
|
36
45
|
except Exception as e:
|
|
37
46
|
logger.info(f"Warning: Error occurred in pre_task_processing: {e}")
|
|
38
47
|
|
|
39
|
-
def post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, return_value, span, parent_span
|
|
48
|
+
def post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, return_value, span, parent_span, ex):
|
|
40
49
|
if not (SpanHandler.is_root_span(span) or get_value(ADD_NEW_WORKFLOW) == True):
|
|
41
50
|
try:
|
|
51
|
+
if parent_span == INVALID_SPAN:
|
|
52
|
+
parent_span = None
|
|
42
53
|
handler.hydrate_span(to_wrap, wrapped, instance, args, kwargs, return_value, span, parent_span, ex)
|
|
43
54
|
except Exception as e:
|
|
44
55
|
logger.info(f"Warning: Error occurred in hydrate_span: {e}")
|
|
45
56
|
|
|
46
57
|
try:
|
|
47
|
-
handler.post_task_processing(to_wrap, wrapped, instance, args, kwargs, return_value, span)
|
|
58
|
+
handler.post_task_processing(to_wrap, wrapped, instance, args, kwargs, return_value, ex, span, parent_span)
|
|
48
59
|
except Exception as e:
|
|
49
60
|
logger.info(f"Warning: Error occurred in post_task_processing: {e}")
|
|
50
61
|
|
|
@@ -52,7 +63,7 @@ def get_span_name(to_wrap, instance):
|
|
|
52
63
|
if to_wrap.get("span_name"):
|
|
53
64
|
name = to_wrap.get("span_name")
|
|
54
65
|
else:
|
|
55
|
-
name =
|
|
66
|
+
name = to_wrap.get("package", "") + "." + to_wrap.get("object", "") + "." + to_wrap.get("method", "")
|
|
56
67
|
return name
|
|
57
68
|
|
|
58
69
|
def monocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
|
|
@@ -61,8 +72,8 @@ def monocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap
|
|
|
61
72
|
return_value = None
|
|
62
73
|
span_status = None
|
|
63
74
|
auto_close_span = get_auto_close_span(to_wrap, kwargs)
|
|
64
|
-
parent_span =
|
|
65
|
-
with tracer
|
|
75
|
+
parent_span = get_current_monocle_span()
|
|
76
|
+
with start_as_monocle_span(tracer, name, auto_close_span) as span:
|
|
66
77
|
pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path)
|
|
67
78
|
|
|
68
79
|
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
@@ -93,10 +104,11 @@ def monocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap
|
|
|
93
104
|
|
|
94
105
|
def monocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
95
106
|
return_value = None
|
|
107
|
+
pre_trace_token = None
|
|
96
108
|
token = None
|
|
97
109
|
try:
|
|
98
110
|
try:
|
|
99
|
-
handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
111
|
+
pre_trace_token = handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
100
112
|
except Exception as e:
|
|
101
113
|
logger.info(f"Warning: Error occurred in pre_tracing: {e}")
|
|
102
114
|
if to_wrap.get('skip_span', False) or handler.skip_span(to_wrap, wrapped, instance, args, kwargs):
|
|
@@ -111,18 +123,19 @@ def monocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, inst
|
|
|
111
123
|
return return_value
|
|
112
124
|
finally:
|
|
113
125
|
try:
|
|
114
|
-
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
126
|
+
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value, token=pre_trace_token)
|
|
115
127
|
except Exception as e:
|
|
116
128
|
logger.info(f"Warning: Error occurred in post_tracing: {e}")
|
|
117
129
|
|
|
118
|
-
async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span,
|
|
130
|
+
async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span,
|
|
131
|
+
args, kwargs):
|
|
119
132
|
# Main span processing logic
|
|
120
133
|
name = get_span_name(to_wrap, instance)
|
|
121
134
|
return_value = None
|
|
122
135
|
span_status = None
|
|
123
136
|
auto_close_span = get_auto_close_span(to_wrap, kwargs)
|
|
124
|
-
parent_span =
|
|
125
|
-
with tracer
|
|
137
|
+
parent_span = get_current_monocle_span()
|
|
138
|
+
with start_as_monocle_span(tracer, name, auto_close_span) as span:
|
|
126
139
|
pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path)
|
|
127
140
|
|
|
128
141
|
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
@@ -141,7 +154,7 @@ async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler,
|
|
|
141
154
|
raise
|
|
142
155
|
finally:
|
|
143
156
|
def post_process_span_internal(ret_val):
|
|
144
|
-
post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span,ex)
|
|
157
|
+
post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
|
|
145
158
|
if not auto_close_span:
|
|
146
159
|
span.end()
|
|
147
160
|
if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
|
|
@@ -149,14 +162,54 @@ async def amonocle_wrapper_span_processor(tracer: Tracer, handler: SpanHandler,
|
|
|
149
162
|
else:
|
|
150
163
|
post_process_span_internal(return_value)
|
|
151
164
|
span_status = span.status
|
|
152
|
-
return return_value,
|
|
165
|
+
return return_value, span_status
|
|
166
|
+
|
|
167
|
+
async def amonocle_iter_wrapper_span_processor(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, add_workflow_span,
|
|
168
|
+
args, kwargs) -> AsyncGenerator[any, None]:
|
|
169
|
+
# Main span processing logic
|
|
170
|
+
name = get_span_name(to_wrap, instance)
|
|
171
|
+
auto_close_span = get_auto_close_span(to_wrap, kwargs)
|
|
172
|
+
parent_span = get_current_monocle_span()
|
|
173
|
+
last_item = None
|
|
174
|
+
|
|
175
|
+
with start_as_monocle_span(tracer, name, auto_close_span) as span:
|
|
176
|
+
pre_process_span(name, tracer, handler, add_workflow_span, to_wrap, wrapped, instance, args, kwargs, span, source_path)
|
|
177
|
+
|
|
178
|
+
if SpanHandler.is_root_span(span) or add_workflow_span:
|
|
179
|
+
# Recursive call for the actual span
|
|
180
|
+
async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, False, args, kwargs):
|
|
181
|
+
yield item
|
|
182
|
+
|
|
183
|
+
if not auto_close_span:
|
|
184
|
+
span.end()
|
|
185
|
+
else:
|
|
186
|
+
ex:Exception = None
|
|
187
|
+
try:
|
|
188
|
+
with SpanHandler.workflow_type(to_wrap, span):
|
|
189
|
+
async for item in wrapped(*args, **kwargs):
|
|
190
|
+
last_item = item
|
|
191
|
+
yield item
|
|
192
|
+
except Exception as e:
|
|
193
|
+
ex = e
|
|
194
|
+
raise
|
|
195
|
+
finally:
|
|
196
|
+
def post_process_span_internal(ret_val):
|
|
197
|
+
post_process_span(handler, to_wrap, wrapped, instance, args, kwargs, ret_val, span, parent_span, ex)
|
|
198
|
+
if not auto_close_span:
|
|
199
|
+
span.end()
|
|
200
|
+
if ex is None and not auto_close_span and to_wrap.get("output_processor") and to_wrap.get("output_processor").get("response_processor"):
|
|
201
|
+
to_wrap.get("output_processor").get("response_processor")(to_wrap, None, post_process_span_internal)
|
|
202
|
+
else:
|
|
203
|
+
post_process_span_internal(last_item)
|
|
204
|
+
return
|
|
153
205
|
|
|
154
206
|
async def amonocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
155
207
|
return_value = None
|
|
156
208
|
token = None
|
|
209
|
+
pre_trace_token = None
|
|
157
210
|
try:
|
|
158
211
|
try:
|
|
159
|
-
handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
212
|
+
pre_trace_token = handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
160
213
|
except Exception as e:
|
|
161
214
|
logger.info(f"Warning: Error occurred in pre_tracing: {e}")
|
|
162
215
|
if to_wrap.get('skip_span', False) or handler.skip_span(to_wrap, wrapped, instance, args, kwargs):
|
|
@@ -165,13 +218,40 @@ async def amonocle_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrappe
|
|
|
165
218
|
add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
|
|
166
219
|
token = attach(set_value(ADD_NEW_WORKFLOW, False))
|
|
167
220
|
try:
|
|
168
|
-
return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path,
|
|
221
|
+
return_value, span_status = await amonocle_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path,
|
|
222
|
+
add_workflow_span, args, kwargs)
|
|
169
223
|
finally:
|
|
170
224
|
detach(token)
|
|
171
225
|
return return_value
|
|
172
226
|
finally:
|
|
173
227
|
try:
|
|
174
|
-
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value)
|
|
228
|
+
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, return_value, pre_trace_token)
|
|
229
|
+
except Exception as e:
|
|
230
|
+
logger.info(f"Warning: Error occurred in post_tracing: {e}")
|
|
231
|
+
|
|
232
|
+
async def amonocle_iter_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs) -> AsyncGenerator[any, None]:
|
|
233
|
+
token = None
|
|
234
|
+
pre_trace_token = None
|
|
235
|
+
try:
|
|
236
|
+
try:
|
|
237
|
+
pre_trace_token = handler.pre_tracing(to_wrap, wrapped, instance, args, kwargs)
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.info(f"Warning: Error occurred in pre_tracing: {e}")
|
|
240
|
+
if to_wrap.get('skip_span', False) or handler.skip_span(to_wrap, wrapped, instance, args, kwargs):
|
|
241
|
+
async for item in wrapped(*args, **kwargs):
|
|
242
|
+
yield item
|
|
243
|
+
else:
|
|
244
|
+
add_workflow_span = get_value(ADD_NEW_WORKFLOW) == True
|
|
245
|
+
token = attach(set_value(ADD_NEW_WORKFLOW, False))
|
|
246
|
+
try:
|
|
247
|
+
async for item in amonocle_iter_wrapper_span_processor(tracer, handler, to_wrap, wrapped, instance, source_path, add_workflow_span, args, kwargs):
|
|
248
|
+
yield item
|
|
249
|
+
finally:
|
|
250
|
+
detach(token)
|
|
251
|
+
return
|
|
252
|
+
finally:
|
|
253
|
+
try:
|
|
254
|
+
handler.post_tracing(to_wrap, wrapped, instance, args, kwargs, None, pre_trace_token)
|
|
175
255
|
except Exception as e:
|
|
176
256
|
logger.info(f"Warning: Error occurred in post_tracing: {e}")
|
|
177
257
|
|
|
@@ -183,6 +263,12 @@ def task_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instanc
|
|
|
183
263
|
async def atask_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
184
264
|
return await amonocle_wrapper(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs)
|
|
185
265
|
|
|
266
|
+
@with_tracer_wrapper
|
|
267
|
+
async def atask_iter_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs) -> AsyncGenerator[any, None]:
|
|
268
|
+
async for item in amonocle_iter_wrapper(tracer, handler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
269
|
+
yield item
|
|
270
|
+
return
|
|
271
|
+
|
|
186
272
|
@with_tracer_wrapper
|
|
187
273
|
def scope_wrapper(tracer: Tracer, handler: SpanHandler, to_wrap, wrapped, instance, source_path, args, kwargs):
|
|
188
274
|
scope_name = to_wrap.get('scope_name', None)
|
|
@@ -244,4 +330,24 @@ def evaluate_scope_values(args, kwargs, to_wrap, scope_values):
|
|
|
244
330
|
scope_values = None
|
|
245
331
|
if isinstance(scope_values, dict):
|
|
246
332
|
return scope_values
|
|
247
|
-
return None
|
|
333
|
+
return None
|
|
334
|
+
|
|
335
|
+
@contextmanager
|
|
336
|
+
def start_as_monocle_span(tracer: Tracer, name: str, auto_close_span: bool) -> Iterator["Span"]:
|
|
337
|
+
""" Wrapper to OTEL start_as_current_span to isolate monocle and non monocle spans.
|
|
338
|
+
This essentiall links monocle and non-monocle spans separately which is default behavior.
|
|
339
|
+
It can be optionally overridden by setting the environment variable MONOCLE_ISOLATE_SPANS to false.
|
|
340
|
+
"""
|
|
341
|
+
if not ISOLATE_MONOCLE_SPANS:
|
|
342
|
+
# If not isolating, use the default start_as_current_span
|
|
343
|
+
yield tracer.start_as_current_span(name, end_on_exit=auto_close_span)
|
|
344
|
+
return
|
|
345
|
+
original_span = get_current_span()
|
|
346
|
+
monocle_span_token = attach(set_span_in_context(get_current_monocle_span()))
|
|
347
|
+
with tracer.start_as_current_span(name, end_on_exit=auto_close_span) as span:
|
|
348
|
+
new_monocle_token = attach(set_monocle_span_in_context(span))
|
|
349
|
+
original_span_token = attach(set_span_in_context(original_span))
|
|
350
|
+
yield span
|
|
351
|
+
detach(original_span_token)
|
|
352
|
+
detach(new_monocle_token)
|
|
353
|
+
detach(monocle_span_token)
|
|
@@ -9,10 +9,14 @@ from monocle_apptrace.instrumentation.metamodel.langchain.methods import (
|
|
|
9
9
|
LANGCHAIN_METHODS,
|
|
10
10
|
)
|
|
11
11
|
from monocle_apptrace.instrumentation.metamodel.llamaindex.methods import (LLAMAINDEX_METHODS, )
|
|
12
|
+
from monocle_apptrace.instrumentation.metamodel.llamaindex.llamaindex_processor import LlamaIndexToolHandler, LlamaIndexAgentHandler, LlamaIndexSingleAgenttToolHandlerWrapper
|
|
12
13
|
from monocle_apptrace.instrumentation.metamodel.haystack.methods import (HAYSTACK_METHODS, )
|
|
13
14
|
from monocle_apptrace.instrumentation.metamodel.openai.methods import (OPENAI_METHODS,)
|
|
14
15
|
from monocle_apptrace.instrumentation.metamodel.openai._helper import OpenAISpanHandler
|
|
15
16
|
from monocle_apptrace.instrumentation.metamodel.langgraph.methods import LANGGRAPH_METHODS
|
|
17
|
+
from monocle_apptrace.instrumentation.metamodel.langgraph.langgraph_processor import LanggraphAgentHandler, LanggraphToolHandler
|
|
18
|
+
from monocle_apptrace.instrumentation.metamodel.agents.methods import AGENTS_METHODS
|
|
19
|
+
from monocle_apptrace.instrumentation.metamodel.agents.agents_processor import AgentsSpanHandler
|
|
16
20
|
from monocle_apptrace.instrumentation.metamodel.flask.methods import (FLASK_METHODS, )
|
|
17
21
|
from monocle_apptrace.instrumentation.metamodel.flask._helper import FlaskSpanHandler, FlaskResponseSpanHandler
|
|
18
22
|
from monocle_apptrace.instrumentation.metamodel.requests.methods import (REQUESTS_METHODS, )
|
|
@@ -23,6 +27,17 @@ from monocle_apptrace.instrumentation.metamodel.aiohttp.methods import (AIOHTTP_
|
|
|
23
27
|
from monocle_apptrace.instrumentation.metamodel.aiohttp._helper import aiohttpSpanHandler
|
|
24
28
|
from monocle_apptrace.instrumentation.metamodel.azfunc._helper import (azureSpanHandler)
|
|
25
29
|
from monocle_apptrace.instrumentation.metamodel.azfunc.methods import AZFUNC_HTTP_METHODS
|
|
30
|
+
from monocle_apptrace.instrumentation.metamodel.gemini.methods import GEMINI_METHODS
|
|
31
|
+
from monocle_apptrace.instrumentation.metamodel.fastapi.methods import FASTAPI_METHODS
|
|
32
|
+
from monocle_apptrace.instrumentation.metamodel.fastapi._helper import FastAPISpanHandler, FastAPIResponseSpanHandler
|
|
33
|
+
from monocle_apptrace.instrumentation.metamodel.lambdafunc._helper import lambdaSpanHandler
|
|
34
|
+
from monocle_apptrace.instrumentation.metamodel.lambdafunc.methods import LAMBDA_HTTP_METHODS
|
|
35
|
+
from monocle_apptrace.instrumentation.metamodel.mcp.methods import MCP_METHODS
|
|
36
|
+
from monocle_apptrace.instrumentation.metamodel.mcp.mcp_processor import MCPAgentHandler
|
|
37
|
+
from monocle_apptrace.instrumentation.metamodel.a2a.methods import A2A_CLIENT_METHODS
|
|
38
|
+
from monocle_apptrace.instrumentation.metamodel.litellm.methods import LITELLM_METHODS
|
|
39
|
+
from monocle_apptrace.instrumentation.metamodel.adk.methods import ADK_METHODS
|
|
40
|
+
|
|
26
41
|
class WrapperMethod:
|
|
27
42
|
def __init__(
|
|
28
43
|
self,
|
|
@@ -71,7 +86,29 @@ class WrapperMethod:
|
|
|
71
86
|
def get_span_handler(self) -> SpanHandler:
|
|
72
87
|
return self.span_handler()
|
|
73
88
|
|
|
74
|
-
DEFAULT_METHODS_LIST =
|
|
89
|
+
DEFAULT_METHODS_LIST = (
|
|
90
|
+
LANGCHAIN_METHODS +
|
|
91
|
+
LLAMAINDEX_METHODS +
|
|
92
|
+
HAYSTACK_METHODS +
|
|
93
|
+
BOTOCORE_METHODS +
|
|
94
|
+
FLASK_METHODS +
|
|
95
|
+
REQUESTS_METHODS +
|
|
96
|
+
LANGGRAPH_METHODS +
|
|
97
|
+
AGENTS_METHODS +
|
|
98
|
+
OPENAI_METHODS +
|
|
99
|
+
TEAMAI_METHODS +
|
|
100
|
+
ANTHROPIC_METHODS +
|
|
101
|
+
AIOHTTP_METHODS +
|
|
102
|
+
AZURE_AI_INFERENCE_METHODS +
|
|
103
|
+
AZFUNC_HTTP_METHODS +
|
|
104
|
+
GEMINI_METHODS +
|
|
105
|
+
FASTAPI_METHODS +
|
|
106
|
+
LAMBDA_HTTP_METHODS +
|
|
107
|
+
MCP_METHODS +
|
|
108
|
+
A2A_CLIENT_METHODS +
|
|
109
|
+
LITELLM_METHODS +
|
|
110
|
+
ADK_METHODS
|
|
111
|
+
)
|
|
75
112
|
|
|
76
113
|
MONOCLE_SPAN_HANDLERS: Dict[str, SpanHandler] = {
|
|
77
114
|
"default": SpanHandler(),
|
|
@@ -83,4 +120,14 @@ MONOCLE_SPAN_HANDLERS: Dict[str, SpanHandler] = {
|
|
|
83
120
|
"non_framework_handler": NonFrameworkSpanHandler(),
|
|
84
121
|
"openai_handler": OpenAISpanHandler(),
|
|
85
122
|
"azure_func_handler": azureSpanHandler(),
|
|
123
|
+
"mcp_agent_handler": MCPAgentHandler(),
|
|
124
|
+
"fastapi_handler": FastAPISpanHandler(),
|
|
125
|
+
"fastapi_response_handler": FastAPIResponseSpanHandler(),
|
|
126
|
+
"langgraph_agent_handler": LanggraphAgentHandler(),
|
|
127
|
+
"langgraph_tool_handler": LanggraphToolHandler(),
|
|
128
|
+
"agents_agent_handler": AgentsSpanHandler(),
|
|
129
|
+
"llamaindex_tool_handler": LlamaIndexToolHandler(),
|
|
130
|
+
"llamaindex_agent_handler": LlamaIndexAgentHandler(),
|
|
131
|
+
"llamaindex_single_agent_tool_handler": LlamaIndexSingleAgenttToolHandlerWrapper(),
|
|
132
|
+
"lambda_func_handler": lambdaSpanHandler(),
|
|
86
133
|
}
|
|
File without changes
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from opentelemetry.context import get_value
|
|
2
|
+
from monocle_apptrace.instrumentation.common.utils import resolve_from_alias
|
|
3
|
+
import logging
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
logger = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
def get_url(arguments):
|
|
9
|
+
"""Get the URL of the tool from the instance."""
|
|
10
|
+
return arguments["instance"].url
|
|
11
|
+
|
|
12
|
+
def get_method(arguments):
|
|
13
|
+
"""Get the method of the tool from the instance."""
|
|
14
|
+
return arguments["args"][0].method
|
|
15
|
+
|
|
16
|
+
def get_params_arguments(arguments):
|
|
17
|
+
"""Get the params of the tool from the instance."""
|
|
18
|
+
return arguments["args"][0].params.message.parts[0].root.text
|
|
19
|
+
|
|
20
|
+
def get_role(arguments):
|
|
21
|
+
"""Get the role of the tool from the instance."""
|
|
22
|
+
return arguments["args"][0].params.message.role.value
|
|
23
|
+
|
|
24
|
+
def get_status(arguments):
|
|
25
|
+
"""Get the status of the tool from the result."""
|
|
26
|
+
return arguments["result"].root.result.status.state.value
|
|
27
|
+
|
|
28
|
+
def get_response(arguments):
|
|
29
|
+
"""Get the response of the tool from the result."""
|
|
30
|
+
ret_val = []
|
|
31
|
+
for artifact in arguments["result"].root.result.artifacts:
|
|
32
|
+
if artifact.parts:
|
|
33
|
+
for part in artifact.parts:
|
|
34
|
+
if part.root.text:
|
|
35
|
+
ret_val.append(part.root.text)
|
|
36
|
+
return ret_val
|
|
37
|
+
# return arguments["result"].root.result.artifacts[0].parts[0].root.text
|
|
File without changes
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.metamodel.a2a import _helper
|
|
2
|
+
|
|
3
|
+
A2A_CLIENT = {
|
|
4
|
+
"type": "agentic.invocation",
|
|
5
|
+
"attributes": [
|
|
6
|
+
[
|
|
7
|
+
{
|
|
8
|
+
"attribute": "type",
|
|
9
|
+
"accessor": lambda arguments: "agent2agent.server"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"attribute": "url",
|
|
13
|
+
"accessor": lambda arguments: _helper.get_url(arguments)
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"attribute": "method",
|
|
17
|
+
"accessor": lambda arguments: _helper.get_method(arguments)
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
],
|
|
21
|
+
"events": [
|
|
22
|
+
{
|
|
23
|
+
"name": "data.input",
|
|
24
|
+
"attributes": [
|
|
25
|
+
{
|
|
26
|
+
"_comment": "this is a2a input",
|
|
27
|
+
"attribute": "input",
|
|
28
|
+
"accessor": lambda arguments: _helper.get_params_arguments(arguments)
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"_comment": "this is a2a input",
|
|
32
|
+
"attribute": "role",
|
|
33
|
+
"accessor": lambda arguments: _helper.get_role(arguments)
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "data.output",
|
|
39
|
+
"attributes": [
|
|
40
|
+
{
|
|
41
|
+
"_comment": "this is a2a output",
|
|
42
|
+
"attribute": "status",
|
|
43
|
+
"accessor": lambda arguments: _helper.get_status(arguments, "status")
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"_comment": "this is a2a output",
|
|
47
|
+
"attribute": "response",
|
|
48
|
+
"accessor": lambda arguments: _helper.get_response(arguments)
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# A2A_RESOLVE = {
|
|
56
|
+
# "type": "a2a.resolve",
|
|
57
|
+
# "attributes": [
|
|
58
|
+
# [
|
|
59
|
+
# # {
|
|
60
|
+
# # "_comment": "tool type",
|
|
61
|
+
# # "attribute": "type",
|
|
62
|
+
# # "accessor": lambda arguments:'tool.mcp'
|
|
63
|
+
# # },
|
|
64
|
+
# {
|
|
65
|
+
# "_comment": "name of the tool",
|
|
66
|
+
# "attribute": "name",
|
|
67
|
+
# "accessor": lambda arguments: _helper.log(arguments),
|
|
68
|
+
# },
|
|
69
|
+
# {
|
|
70
|
+
# "_comment": "tool description",
|
|
71
|
+
# "attribute": "agent_description",
|
|
72
|
+
# "accessor": lambda arguments: arguments["result"].description
|
|
73
|
+
# },
|
|
74
|
+
# {
|
|
75
|
+
# "_comment": "tool name",
|
|
76
|
+
# "attribute": "agent_name",
|
|
77
|
+
# "accessor": lambda arguments: arguments["result"].name
|
|
78
|
+
# }
|
|
79
|
+
# # {
|
|
80
|
+
# # "_comment": "tool type",
|
|
81
|
+
# # "attribute": "type",
|
|
82
|
+
# # "accessor": lambda arguments: _helper.get_type(arguments),
|
|
83
|
+
# # },
|
|
84
|
+
# ]
|
|
85
|
+
# ],
|
|
86
|
+
# "events": [
|
|
87
|
+
# # {
|
|
88
|
+
# # "name": "data.input",
|
|
89
|
+
# # "attributes": [
|
|
90
|
+
# # {
|
|
91
|
+
# # "_comment": "this is Tool input",
|
|
92
|
+
# # "attribute": "input",
|
|
93
|
+
# # "accessor": lambda arguments: _helper.get_params_arguments(
|
|
94
|
+
# # arguments
|
|
95
|
+
# # ),
|
|
96
|
+
# # },
|
|
97
|
+
# # ],
|
|
98
|
+
# # },
|
|
99
|
+
# # {
|
|
100
|
+
# # "name": "data.output",
|
|
101
|
+
# # "attributes": [
|
|
102
|
+
# # {
|
|
103
|
+
# # "_comment": "this is Tool output",
|
|
104
|
+
# # "attribute": "output",
|
|
105
|
+
# # "accessor": lambda arguments: _helper.get_output_text(arguments)
|
|
106
|
+
# # },
|
|
107
|
+
# # ],
|
|
108
|
+
# # },
|
|
109
|
+
# ],
|
|
110
|
+
# }
|
|
111
|
+
|
|
112
|
+
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from monocle_apptrace.instrumentation.common.wrapper import task_wrapper, atask_wrapper
|
|
2
|
+
from monocle_apptrace.instrumentation.metamodel.a2a.entities.inference import A2A_CLIENT
|
|
3
|
+
|
|
4
|
+
A2A_CLIENT_METHODS = [
|
|
5
|
+
# {
|
|
6
|
+
# "package": "a2a.client.client",
|
|
7
|
+
# "object": "A2ACardResolver",
|
|
8
|
+
# "method": "get_agent_card",
|
|
9
|
+
# "wrapper_method": atask_wrapper,
|
|
10
|
+
# # "span_handler": "mcp_agent_handler",
|
|
11
|
+
# "output_processor": A2A_RESOLVE,
|
|
12
|
+
# },
|
|
13
|
+
{
|
|
14
|
+
"package": "a2a.client.client",
|
|
15
|
+
"object": "A2AClient",
|
|
16
|
+
"method": "send_message",
|
|
17
|
+
"wrapper_method": atask_wrapper,
|
|
18
|
+
"output_processor": A2A_CLIENT,
|
|
19
|
+
},
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
|
|
File without changes
|