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.

Files changed (91) hide show
  1. monocle_apptrace/__main__.py +1 -1
  2. monocle_apptrace/exporters/file_exporter.py +125 -37
  3. monocle_apptrace/instrumentation/common/__init__.py +16 -1
  4. monocle_apptrace/instrumentation/common/constants.py +14 -1
  5. monocle_apptrace/instrumentation/common/instrumentor.py +19 -152
  6. monocle_apptrace/instrumentation/common/method_wrappers.py +376 -0
  7. monocle_apptrace/instrumentation/common/span_handler.py +58 -32
  8. monocle_apptrace/instrumentation/common/utils.py +52 -15
  9. monocle_apptrace/instrumentation/common/wrapper.py +124 -18
  10. monocle_apptrace/instrumentation/common/wrapper_method.py +48 -1
  11. monocle_apptrace/instrumentation/metamodel/a2a/__init__.py +0 -0
  12. monocle_apptrace/instrumentation/metamodel/a2a/_helper.py +37 -0
  13. monocle_apptrace/instrumentation/metamodel/a2a/entities/__init__.py +0 -0
  14. monocle_apptrace/instrumentation/metamodel/a2a/entities/inference.py +112 -0
  15. monocle_apptrace/instrumentation/metamodel/a2a/methods.py +22 -0
  16. monocle_apptrace/instrumentation/metamodel/adk/__init__.py +0 -0
  17. monocle_apptrace/instrumentation/metamodel/adk/_helper.py +182 -0
  18. monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +50 -0
  19. monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +57 -0
  20. monocle_apptrace/instrumentation/metamodel/adk/methods.py +24 -0
  21. monocle_apptrace/instrumentation/metamodel/agents/__init__.py +0 -0
  22. monocle_apptrace/instrumentation/metamodel/agents/_helper.py +220 -0
  23. monocle_apptrace/instrumentation/metamodel/agents/agents_processor.py +152 -0
  24. monocle_apptrace/instrumentation/metamodel/agents/entities/__init__.py +0 -0
  25. monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +191 -0
  26. monocle_apptrace/instrumentation/metamodel/agents/methods.py +56 -0
  27. monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +6 -11
  28. monocle_apptrace/instrumentation/metamodel/anthropic/_helper.py +112 -18
  29. monocle_apptrace/instrumentation/metamodel/anthropic/entities/inference.py +18 -10
  30. monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +13 -11
  31. monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +5 -0
  32. monocle_apptrace/instrumentation/metamodel/azureaiinference/_helper.py +88 -8
  33. monocle_apptrace/instrumentation/metamodel/azureaiinference/entities/inference.py +22 -8
  34. monocle_apptrace/instrumentation/metamodel/botocore/_helper.py +92 -16
  35. monocle_apptrace/instrumentation/metamodel/botocore/entities/inference.py +13 -8
  36. monocle_apptrace/instrumentation/metamodel/botocore/handlers/botocore_span_handler.py +1 -1
  37. monocle_apptrace/instrumentation/metamodel/fastapi/__init__.py +0 -0
  38. monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +82 -0
  39. monocle_apptrace/instrumentation/metamodel/fastapi/entities/__init__.py +0 -0
  40. monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +44 -0
  41. monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +23 -0
  42. monocle_apptrace/instrumentation/metamodel/finish_types.py +463 -0
  43. monocle_apptrace/instrumentation/metamodel/flask/_helper.py +6 -11
  44. monocle_apptrace/instrumentation/metamodel/gemini/__init__.py +0 -0
  45. monocle_apptrace/instrumentation/metamodel/gemini/_helper.py +120 -0
  46. monocle_apptrace/instrumentation/metamodel/gemini/entities/__init__.py +0 -0
  47. monocle_apptrace/instrumentation/metamodel/gemini/entities/inference.py +86 -0
  48. monocle_apptrace/instrumentation/metamodel/gemini/entities/retrieval.py +43 -0
  49. monocle_apptrace/instrumentation/metamodel/gemini/methods.py +31 -0
  50. monocle_apptrace/instrumentation/metamodel/haystack/_helper.py +79 -8
  51. monocle_apptrace/instrumentation/metamodel/haystack/entities/inference.py +15 -10
  52. monocle_apptrace/instrumentation/metamodel/haystack/methods.py +7 -0
  53. monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +78 -0
  54. monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +51 -0
  55. monocle_apptrace/instrumentation/metamodel/lambdafunc/methods.py +23 -0
  56. monocle_apptrace/instrumentation/metamodel/lambdafunc/wrapper.py +23 -0
  57. monocle_apptrace/instrumentation/metamodel/langchain/_helper.py +145 -19
  58. monocle_apptrace/instrumentation/metamodel/langchain/entities/inference.py +19 -10
  59. monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +67 -10
  60. monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +127 -20
  61. monocle_apptrace/instrumentation/metamodel/langgraph/langgraph_processor.py +46 -0
  62. monocle_apptrace/instrumentation/metamodel/langgraph/methods.py +35 -9
  63. monocle_apptrace/instrumentation/metamodel/litellm/__init__.py +0 -0
  64. monocle_apptrace/instrumentation/metamodel/litellm/_helper.py +89 -0
  65. monocle_apptrace/instrumentation/metamodel/litellm/entities/__init__.py +0 -0
  66. monocle_apptrace/instrumentation/metamodel/litellm/entities/inference.py +108 -0
  67. monocle_apptrace/instrumentation/metamodel/litellm/methods.py +19 -0
  68. monocle_apptrace/instrumentation/metamodel/llamaindex/_helper.py +227 -16
  69. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +127 -10
  70. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/inference.py +13 -8
  71. monocle_apptrace/instrumentation/metamodel/llamaindex/llamaindex_processor.py +62 -0
  72. monocle_apptrace/instrumentation/metamodel/llamaindex/methods.py +68 -1
  73. monocle_apptrace/instrumentation/metamodel/mcp/__init__.py +0 -0
  74. monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +118 -0
  75. monocle_apptrace/instrumentation/metamodel/mcp/entities/__init__.py +0 -0
  76. monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +48 -0
  77. monocle_apptrace/instrumentation/metamodel/mcp/mcp_processor.py +8 -0
  78. monocle_apptrace/instrumentation/metamodel/mcp/methods.py +21 -0
  79. monocle_apptrace/instrumentation/metamodel/openai/_helper.py +188 -16
  80. monocle_apptrace/instrumentation/metamodel/openai/entities/inference.py +148 -92
  81. monocle_apptrace/instrumentation/metamodel/openai/entities/retrieval.py +1 -1
  82. monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +53 -23
  83. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/actionplanner_output_processor.py +1 -1
  84. monocle_apptrace/instrumentation/metamodel/teamsai/entities/inference/teamsai_output_processor.py +15 -9
  85. monocle_apptrace/instrumentation/metamodel/teamsai/sample.json +0 -4
  86. {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/METADATA +27 -11
  87. monocle_apptrace-0.5.0.dist-info/RECORD +142 -0
  88. monocle_apptrace-0.4.1.dist-info/RECORD +0 -96
  89. {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/WHEEL +0 -0
  90. {monocle_apptrace-0.4.1.dist-info → monocle_apptrace-0.5.0.dist-info}/licenses/LICENSE +0 -0
  91. {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
- 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 = ""
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
- get_parent_span
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=None, ex = None):
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 = get_fully_qualified_class_name(instance)
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 = get_parent_span()
65
- with tracer.start_as_current_span(name, end_on_exit=auto_close_span) as span:
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, args, kwargs):
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 = get_parent_span()
125
- with tracer.start_as_current_span(name, end_on_exit=auto_close_span) as span:
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, span.status
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, add_workflow_span, args, kwargs)
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 = LANGCHAIN_METHODS + LLAMAINDEX_METHODS + HAYSTACK_METHODS + BOTOCORE_METHODS + FLASK_METHODS + REQUESTS_METHODS + LANGGRAPH_METHODS + OPENAI_METHODS + TEAMAI_METHODS + ANTHROPIC_METHODS + AIOHTTP_METHODS + AZURE_AI_INFERENCE_METHODS + AZFUNC_HTTP_METHODS
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
  }
@@ -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
@@ -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
+