monocle-apptrace 0.5.2__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of monocle-apptrace might be problematic. Click here for more details.

Files changed (47) hide show
  1. monocle_apptrace/exporters/file_exporter.py +15 -2
  2. monocle_apptrace/instrumentation/common/instrumentor.py +1 -1
  3. monocle_apptrace/instrumentation/common/span_handler.py +8 -4
  4. monocle_apptrace/instrumentation/common/utils.py +10 -2
  5. monocle_apptrace/instrumentation/common/wrapper_method.py +5 -1
  6. monocle_apptrace/instrumentation/metamodel/adk/_helper.py +6 -4
  7. monocle_apptrace/instrumentation/metamodel/adk/entities/agent.py +12 -2
  8. monocle_apptrace/instrumentation/metamodel/adk/entities/tool.py +8 -3
  9. monocle_apptrace/instrumentation/metamodel/agents/_helper.py +5 -5
  10. monocle_apptrace/instrumentation/metamodel/agents/entities/inference.py +22 -5
  11. monocle_apptrace/instrumentation/metamodel/aiohttp/_helper.py +22 -7
  12. monocle_apptrace/instrumentation/metamodel/aiohttp/entities/http.py +14 -3
  13. monocle_apptrace/instrumentation/metamodel/azfunc/_helper.py +21 -11
  14. monocle_apptrace/instrumentation/metamodel/azfunc/entities/http.py +7 -2
  15. monocle_apptrace/instrumentation/metamodel/fastapi/_helper.py +19 -6
  16. monocle_apptrace/instrumentation/metamodel/fastapi/entities/http.py +6 -2
  17. monocle_apptrace/instrumentation/metamodel/fastapi/methods.py +19 -19
  18. monocle_apptrace/instrumentation/metamodel/finish_types.py +32 -1
  19. monocle_apptrace/instrumentation/metamodel/flask/_helper.py +20 -6
  20. monocle_apptrace/instrumentation/metamodel/flask/entities/http.py +7 -2
  21. monocle_apptrace/instrumentation/metamodel/hugging_face/__init__.py +0 -0
  22. monocle_apptrace/instrumentation/metamodel/hugging_face/_helper.py +138 -0
  23. monocle_apptrace/instrumentation/metamodel/hugging_face/entities/__init__.py +0 -0
  24. monocle_apptrace/instrumentation/metamodel/hugging_face/entities/inference.py +97 -0
  25. monocle_apptrace/instrumentation/metamodel/hugging_face/methods.py +23 -0
  26. monocle_apptrace/instrumentation/metamodel/lambdafunc/_helper.py +25 -14
  27. monocle_apptrace/instrumentation/metamodel/lambdafunc/entities/http.py +7 -2
  28. monocle_apptrace/instrumentation/metamodel/langgraph/_helper.py +4 -2
  29. monocle_apptrace/instrumentation/metamodel/langgraph/entities/inference.py +8 -3
  30. monocle_apptrace/instrumentation/metamodel/llamaindex/entities/agent.py +1 -1
  31. monocle_apptrace/instrumentation/metamodel/mcp/_helper.py +6 -5
  32. monocle_apptrace/instrumentation/metamodel/mcp/entities/inference.py +5 -0
  33. monocle_apptrace/instrumentation/metamodel/mistral/__init__.py +0 -0
  34. monocle_apptrace/instrumentation/metamodel/mistral/_helper.py +223 -0
  35. monocle_apptrace/instrumentation/metamodel/mistral/entities/__init__.py +0 -0
  36. monocle_apptrace/instrumentation/metamodel/mistral/entities/inference.py +94 -0
  37. monocle_apptrace/instrumentation/metamodel/mistral/entities/retrieval.py +41 -0
  38. monocle_apptrace/instrumentation/metamodel/mistral/methods.py +58 -0
  39. monocle_apptrace/instrumentation/metamodel/teamsai/_helper.py +2 -2
  40. {monocle_apptrace-0.5.2.dist-info → monocle_apptrace-0.6.0.dist-info}/METADATA +9 -76
  41. {monocle_apptrace-0.5.2.dist-info → monocle_apptrace-0.6.0.dist-info}/RECORD +44 -36
  42. monocle_apptrace/README.md +0 -101
  43. monocle_apptrace/mcp_server.py +0 -94
  44. monocle_apptrace-0.5.2.dist-info/licenses/NOTICE +0 -4
  45. {monocle_apptrace-0.5.2.dist-info → monocle_apptrace-0.6.0.dist-info}/WHEEL +0 -0
  46. {monocle_apptrace-0.5.2.dist-info → monocle_apptrace-0.6.0.dist-info}/entry_points.txt +0 -0
  47. {monocle_apptrace-0.5.2.dist-info → monocle_apptrace-0.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -14,12 +14,13 @@ from monocle_apptrace.exporters.exporter_processor import ExportTaskProcessor
14
14
  DEFAULT_FILE_PREFIX:str = "monocle_trace_"
15
15
  DEFAULT_TIME_FORMAT:str = "%Y-%m-%d_%H.%M.%S"
16
16
  HANDLE_TIMEOUT_SECONDS: int = 60 # 1 minute timeout
17
+ DEFAULT_TRACE_FOLDER = ".monocle"
17
18
 
18
19
  class FileSpanExporter(SpanExporterBase):
19
20
  def __init__(
20
21
  self,
21
22
  service_name: Optional[str] = None,
22
- out_path:str = ".",
23
+ out_path:str = path.join(".", DEFAULT_TRACE_FOLDER),
23
24
  file_prefix = DEFAULT_FILE_PREFIX,
24
25
  time_format = DEFAULT_TIME_FORMAT,
25
26
  formatter: Callable[
@@ -34,12 +35,16 @@ class FileSpanExporter(SpanExporterBase):
34
35
  self.formatter = formatter
35
36
  self.service_name = service_name
36
37
  self.output_path = os.getenv("MONOCLE_TRACE_OUTPUT_PATH", out_path)
38
+ if not os.path.exists(self.output_path):
39
+ os.makedirs(self.output_path)
37
40
  self.file_prefix = file_prefix
38
41
  self.time_format = time_format
39
42
  self.task_processor = task_processor
40
43
  self.is_first_span_in_file = True # Track if this is the first span in the current file
41
44
  if self.task_processor is not None:
42
45
  self.task_processor.start()
46
+ self.last_file_processed:str = None
47
+ self.last_trace_id = None
43
48
 
44
49
  def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
45
50
  is_root_span = any(not span.parent for span in spans)
@@ -50,6 +55,9 @@ class FileSpanExporter(SpanExporterBase):
50
55
  else:
51
56
  return self._process_spans(spans, is_root_span=is_root_span)
52
57
 
58
+ def set_service_name(self, service_name: str) -> None:
59
+ self.service_name = service_name
60
+
53
61
  def _cleanup_expired_handles(self) -> None:
54
62
  """Close and remove file handles that have exceeded the timeout."""
55
63
  current_time = datetime.now()
@@ -96,6 +104,8 @@ class FileSpanExporter(SpanExporterBase):
96
104
  print(f"Error closing file {file_path}: {e}")
97
105
  finally:
98
106
  del self.file_handles[trace_id]
107
+ self.last_file_processed = file_path
108
+ self.last_trace_id = trace_id
99
109
 
100
110
  def _mark_span_written(self, trace_id: int) -> None:
101
111
  """Mark that a span has been written for this trace (no longer first span)."""
@@ -123,7 +133,10 @@ class FileSpanExporter(SpanExporterBase):
123
133
 
124
134
  # Process spans for each trace
125
135
  for trace_id, trace_spans in spans_by_trace.items():
126
- service_name = trace_spans[0].resource.attributes.get(SERVICE_NAME, "unknown")
136
+ if self.service_name is not None:
137
+ service_name = self.service_name
138
+ else:
139
+ service_name = trace_spans[0].resource.attributes.get(SERVICE_NAME, "unknown")
127
140
  handle, file_path, is_first_span = self._get_or_create_handle(trace_id, service_name)
128
141
 
129
142
  if handle is None:
@@ -165,7 +165,7 @@ def setup_monocle_telemetry(
165
165
  span_handlers: Dict[str,SpanHandler] = None,
166
166
  wrapper_methods: List[Union[dict,WrapperMethod]] = None,
167
167
  union_with_default_methods: bool = True,
168
- monocle_exporters_list:str = None) -> None:
168
+ monocle_exporters_list:str = None) -> MonocleInstrumentor:
169
169
  """
170
170
  Set up Monocle telemetry for the application.
171
171
 
@@ -26,6 +26,8 @@ WORKFLOW_TYPE_MAP = {
26
26
  "anthropic": "workflow.anthropic",
27
27
  "gemini": "workflow.gemini",
28
28
  "litellm": "workflow.litellm",
29
+ "mistralai": "workflow.mistral",
30
+ "huggingface_hub": "workflow.huggingface"
29
31
  }
30
32
 
31
33
  FRAMEWORK_WORKFLOW_LIST = [
@@ -185,7 +187,12 @@ class SpanHandler:
185
187
  accessor = attribute.get("accessor")
186
188
  if accessor:
187
189
  try:
188
- result = accessor(arguments)
190
+ try:
191
+ result = accessor(arguments)
192
+ except MonocleSpanException as e:
193
+ span.set_status(StatusCode.ERROR, e.message)
194
+ detected_error = True
195
+ result = e.get_err_code()
189
196
  if result and isinstance(result, dict):
190
197
  result = dict((key, value) for key, value in result.items() if value is not None)
191
198
  if result and isinstance(result, (int, str, list, dict)):
@@ -193,9 +200,6 @@ class SpanHandler:
193
200
  event_attributes[attribute_key] = result
194
201
  else:
195
202
  event_attributes.update(result)
196
- except MonocleSpanException as e:
197
- span.set_status(StatusCode.ERROR, e.message)
198
- detected_error = True
199
203
  except Exception as e:
200
204
  logger.debug(f"Error evaluating accessor for attribute '{attribute_key}': {e}")
201
205
  matching_timestamp = getattr(ret_result, "timestamps", {}).get(event_name, None)
@@ -30,7 +30,7 @@ except Exception as e:
30
30
  logger.warning("Exception finding monocle-apptrace version.")
31
31
 
32
32
  class MonocleSpanException(Exception):
33
- def __init__(self, err_message:str):
33
+ def __init__(self, err_message:str, err_code:str = None):
34
34
  """
35
35
  Monocle exeption to indicate error in span processing.
36
36
  Parameters:
@@ -39,10 +39,15 @@ class MonocleSpanException(Exception):
39
39
  """
40
40
  super().__init__(err_message)
41
41
  self.message = err_message
42
+ self.err_code = err_code
42
43
 
43
44
  def __str__(self):
44
45
  """String representation of the exception."""
45
- return f"[Monocle Span Error: {self.message} {self.status}"
46
+ return f"[Monocle Span Error: {self.message}"
47
+
48
+ def get_err_code(self):
49
+ """Retrieve the error code."""
50
+ return self.err_code
46
51
 
47
52
  def set_span_attribute(span, name, value):
48
53
  if value is not None:
@@ -98,6 +103,7 @@ def with_tracer_wrapper(func):
98
103
 
99
104
  return _with_tracer
100
105
 
106
+
101
107
  def resolve_from_alias(my_map, alias):
102
108
  """Find a alias that is not none from list of aliases"""
103
109
 
@@ -393,6 +399,7 @@ def get_exception_message(arguments):
393
399
  else:
394
400
  return ''
395
401
 
402
+
396
403
  def get_error_message(arguments):
397
404
  status_code = get_status_code(arguments)
398
405
  if status_code == 'success':
@@ -400,6 +407,7 @@ def get_error_message(arguments):
400
407
  else:
401
408
  return status_code
402
409
 
410
+
403
411
  def get_status_code(arguments):
404
412
  if arguments["exception"] is not None:
405
413
  return get_exception_status_code(arguments)
@@ -5,6 +5,7 @@ from monocle_apptrace.instrumentation.common.span_handler import SpanHandler, No
5
5
  from monocle_apptrace.instrumentation.metamodel.azureaiinference.methods import AZURE_AI_INFERENCE_METHODS
6
6
  from monocle_apptrace.instrumentation.metamodel.botocore.methods import BOTOCORE_METHODS
7
7
  from monocle_apptrace.instrumentation.metamodel.botocore.handlers.botocore_span_handler import BotoCoreSpanHandler
8
+ from monocle_apptrace.instrumentation.metamodel.hugging_face.methods import HUGGING_FACE_METHODS
8
9
  from monocle_apptrace.instrumentation.metamodel.langchain.methods import (
9
10
  LANGCHAIN_METHODS,
10
11
  )
@@ -37,6 +38,7 @@ from monocle_apptrace.instrumentation.metamodel.mcp.mcp_processor import MCPAgen
37
38
  from monocle_apptrace.instrumentation.metamodel.a2a.methods import A2A_CLIENT_METHODS
38
39
  from monocle_apptrace.instrumentation.metamodel.litellm.methods import LITELLM_METHODS
39
40
  from monocle_apptrace.instrumentation.metamodel.adk.methods import ADK_METHODS
41
+ from monocle_apptrace.instrumentation.metamodel.mistral.methods import MISTRAL_METHODS
40
42
 
41
43
  class WrapperMethod:
42
44
  def __init__(
@@ -107,7 +109,9 @@ DEFAULT_METHODS_LIST = (
107
109
  MCP_METHODS +
108
110
  A2A_CLIENT_METHODS +
109
111
  LITELLM_METHODS +
110
- ADK_METHODS
112
+ ADK_METHODS +
113
+ MISTRAL_METHODS +
114
+ HUGGING_FACE_METHODS
111
115
  )
112
116
 
113
117
  MONOCLE_SPAN_HANDLERS: Dict[str, SpanHandler] = {
@@ -82,7 +82,7 @@ def extract_agent_input(arguments: Dict[str, Any]) -> Any:
82
82
  Returns:
83
83
  Any: The extracted input data
84
84
  """
85
- return arguments['args'][0].user_content.parts[0].text
85
+ return [arguments['args'][0].user_content.parts[0].text]
86
86
 
87
87
  def extract_agent_request_input(arguments: Dict[str, Any]) -> Any:
88
88
  """
@@ -94,7 +94,7 @@ def extract_agent_request_input(arguments: Dict[str, Any]) -> Any:
94
94
  Returns:
95
95
  Any: The extracted input data
96
96
  """
97
- return arguments['kwargs']['new_message'].parts[0].text if 'new_message' in arguments['kwargs'] else None
97
+ return [arguments['kwargs']['new_message'].parts[0].text] if 'new_message' in arguments['kwargs'] else []
98
98
 
99
99
  def extract_agent_response(result: Any) -> Any:
100
100
  """
@@ -107,7 +107,9 @@ def extract_agent_response(result: Any) -> Any:
107
107
  Any: The extracted response data
108
108
  """
109
109
  if result:
110
- return result.content.parts[0].text
110
+ return str(result.content.parts[0].text)
111
+ else:
112
+ return ""
111
113
 
112
114
  def get_tool_name(instance: Any) -> str:
113
115
  """
@@ -179,7 +181,7 @@ def extract_tool_input(arguments: Dict[str, Any]) -> Any:
179
181
  Returns:
180
182
  Any: The extracted input data
181
183
  """
182
- return str(arguments['kwargs'].get('args'))
184
+ return [str(arguments['kwargs'].get('args'))]
183
185
 
184
186
  def extract_tool_response(result: Any) -> Any:
185
187
  """
@@ -1,5 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.common.constants import SPAN_SUBTYPES, SPAN_TYPES
2
+ from monocle_apptrace.instrumentation.common.utils import get_error_message
2
3
  from monocle_apptrace.instrumentation.metamodel.adk import _helper
4
+ from monocle_apptrace.instrumentation.common.utils import get_error_message
3
5
  AGENT = {
4
6
  "type": SPAN_TYPES.AGENTIC_INVOCATION,
5
7
  "subtype": SPAN_SUBTYPES.ROUTING,
@@ -33,7 +35,7 @@ AGENT = {
33
35
  "attributes": [
34
36
  {
35
37
  "_comment": "this is Agent input",
36
- "attribute": "query",
38
+ "attribute": "input",
37
39
  "accessor": lambda arguments: _helper.extract_agent_input(arguments)
38
40
  }
39
41
  ]
@@ -41,10 +43,18 @@ AGENT = {
41
43
  {
42
44
  "name":"data.output",
43
45
  "attributes": [
46
+ {
47
+ "attribute": "error_code",
48
+ "accessor": lambda arguments: get_error_message(arguments)
49
+ },
44
50
  {
45
51
  "_comment": "this is response from LLM",
46
52
  "attribute": "response",
47
53
  "accessor": lambda arguments: _helper.extract_agent_response(arguments['result'])
54
+ },
55
+ {
56
+ "attribute": "error_code",
57
+ "accessor": lambda arguments: get_error_message(arguments)
48
58
  }
49
59
  ]
50
60
  }
@@ -108,4 +118,4 @@ DELEGATION = {
108
118
  }
109
119
  ]
110
120
  ]
111
- }
121
+ }
@@ -1,4 +1,5 @@
1
1
  from monocle_apptrace.instrumentation.common.constants import SPAN_SUBTYPES, SPAN_TYPES
2
+ from monocle_apptrace.instrumentation.common.utils import get_error_message
2
3
  from monocle_apptrace.instrumentation.metamodel.adk import _helper
3
4
  TOOL = {
4
5
  "type": SPAN_TYPES.AGENTIC_TOOL_INVOCATION,
@@ -40,7 +41,7 @@ TOOL = {
40
41
  "attributes": [
41
42
  {
42
43
  "_comment": "this is Tool input",
43
- "attribute": "Inputs",
44
+ "attribute": "input",
44
45
  "accessor": lambda arguments: _helper.extract_tool_input(arguments)
45
46
  },
46
47
  ]
@@ -52,8 +53,12 @@ TOOL = {
52
53
  "_comment": "this is response from Tool",
53
54
  "attribute": "response",
54
55
  "accessor": lambda arguments: _helper.extract_tool_response(arguments['result'])
55
- }
56
+ },
57
+ {
58
+ "attribute": "error_code",
59
+ "accessor": lambda arguments: get_error_message(arguments)
60
+ },
56
61
  ]
57
62
  }
58
63
  ]
59
- }
64
+ }
@@ -50,21 +50,21 @@ def extract_agent_input(arguments):
50
50
  if len(arguments["args"]) > 1:
51
51
  input_data = arguments["args"][1]
52
52
  if isinstance(input_data, str):
53
- return input_data
53
+ return [input_data]
54
54
  elif isinstance(input_data, list):
55
55
  # Handle list of input items
56
- return get_json_dumps(input_data)
56
+ return input_data
57
57
 
58
58
  # Fallback to kwargs
59
59
  if "original_input" in arguments["kwargs"]:
60
60
  input_data = arguments["kwargs"]["original_input"]
61
61
  if isinstance(input_data, str):
62
- return input_data
62
+ return [input_data]
63
63
  elif isinstance(input_data, list):
64
- return get_json_dumps(input_data)
64
+ return input_data
65
65
  except Exception as e:
66
66
  logger.warning("Warning: Error occurred in extract_agent_input: %s", str(e))
67
- return None
67
+ return []
68
68
 
69
69
 
70
70
  def get_agent_name(arguments) -> str:
@@ -1,5 +1,7 @@
1
1
  from monocle_apptrace.instrumentation.common.constants import AGENT_REQUEST_SPAN_NAME, SPAN_SUBTYPES, SPAN_TYPES
2
+ from monocle_apptrace.instrumentation.common.utils import get_error_message
2
3
  from monocle_apptrace.instrumentation.metamodel.agents import _helper
4
+ from monocle_apptrace.instrumentation.common.utils import get_error_message
3
5
 
4
6
  AGENT = {
5
7
  "type": SPAN_TYPES.AGENTIC_INVOCATION,
@@ -34,7 +36,7 @@ AGENT = {
34
36
  "attributes": [
35
37
  {
36
38
  "_comment": "this is Agent input",
37
- "attribute": "query",
39
+ "attribute": "input",
38
40
  "accessor": lambda arguments: _helper.extract_agent_input(
39
41
  arguments
40
42
  ),
@@ -44,12 +46,20 @@ AGENT = {
44
46
  {
45
47
  "name": "data.output",
46
48
  "attributes": [
49
+ {
50
+ "attribute": "error_code",
51
+ "accessor": lambda arguments: get_error_message(arguments)
52
+ },
47
53
  {
48
54
  "_comment": "this is response from Agent",
49
55
  "attribute": "response",
50
56
  "accessor": lambda arguments: _helper.extract_agent_response(
51
57
  arguments["result"]
52
58
  ),
59
+ },
60
+ {
61
+ "attribute": "error_code",
62
+ "accessor": lambda arguments: get_error_message(arguments)
53
63
  }
54
64
  ],
55
65
  },
@@ -68,7 +78,7 @@ AGENT = {
68
78
  }
69
79
 
70
80
  AGENT_REQUEST = {
71
- "type": AGENT_REQUEST_SPAN_NAME,
81
+ "type": SPAN_TYPES.AGENTIC_REQUEST,
72
82
  "subtype": SPAN_SUBTYPES.PLANNING,
73
83
  "attributes": [
74
84
  [
@@ -101,8 +111,11 @@ AGENT_REQUEST = {
101
111
  "accessor": lambda arguments: _helper.extract_agent_response(
102
112
  arguments["result"]
103
113
  ),
104
- }
105
- ],
114
+ },
115
+ {
116
+ "attribute": "error_code",
117
+ "accessor": lambda arguments: get_error_message(arguments)
118
+ }],
106
119
  },
107
120
  ],
108
121
  }
@@ -151,7 +164,7 @@ TOOLS = {
151
164
  "attributes": [
152
165
  {
153
166
  "_comment": "this is Tool input",
154
- "attribute": "Inputs",
167
+ "attribute": "input",
155
168
  "accessor": lambda arguments: _helper.extract_tool_input(arguments),
156
169
  },
157
170
  ],
@@ -165,6 +178,10 @@ TOOLS = {
165
178
  "accessor": lambda arguments: _helper.extract_tool_response(
166
179
  arguments["result"]
167
180
  ),
181
+ },
182
+ {
183
+ "attribute": "error_code",
184
+ "accessor": lambda arguments: get_error_message(arguments)
168
185
  }
169
186
  ],
170
187
  },
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from threading import local
3
- from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, try_option, Option, MonocleSpanException
3
+ from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, get_exception_status_code, try_option, Option, MonocleSpanException
4
4
  from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
5
5
  from monocle_apptrace.instrumentation.common.constants import HTTP_SUCCESS_CODES
6
6
  from urllib.parse import unquote
@@ -8,7 +8,7 @@ from urllib.parse import unquote
8
8
  logger = logging.getLogger(__name__)
9
9
  MAX_DATA_LENGTH = 1000
10
10
 
11
- def get_route(args) -> str:
11
+ def get_url(args) -> str:
12
12
  route_path: Option[str] = try_option(getattr, args[0], 'path')
13
13
  return route_path.unwrap_or("")
14
14
 
@@ -31,11 +31,17 @@ def extract_response(result) -> str:
31
31
  response = ""
32
32
  return response
33
33
 
34
- def extract_status(result) -> str:
35
- status = f"{result.status}" if hasattr(result, 'status') else ""
36
- if status not in HTTP_SUCCESS_CODES:
37
- error_message = extract_response(result)
38
- raise MonocleSpanException(f"error: {status} - {error_message}")
34
+ def extract_status(arguments) -> str:
35
+ if arguments["exception"] is not None:
36
+ return get_exception_status_code(arguments)
37
+ result = arguments['result']
38
+ if hasattr(result, 'status'):
39
+ status = f"{result.status}"
40
+ if status not in HTTP_SUCCESS_CODES:
41
+ error_message = extract_response(result)
42
+ raise MonocleSpanException(f"error: {status} - {error_message}", status)
43
+ else:
44
+ status = "success"
39
45
  return status
40
46
 
41
47
  def aiohttp_pre_tracing(args):
@@ -49,6 +55,15 @@ def aiohttp_skip_span(args) -> bool:
49
55
  return True
50
56
  return False
51
57
 
58
+ def get_route(args) -> str:
59
+ try:
60
+ return args[0].match_info.route.resource.canonical
61
+ except Exception as e:
62
+ return get_url(args)
63
+
64
+ def get_function_name(args) -> str:
65
+ return args[0].match_info.handler.__name__
66
+
52
67
  class aiohttpSpanHandler(SpanHandler):
53
68
 
54
69
  def pre_tracing(self, to_wrap, wrapped, instance, args, kwargs):
@@ -1,5 +1,6 @@
1
1
  from monocle_apptrace.instrumentation.common.constants import SPAN_TYPES
2
2
  from monocle_apptrace.instrumentation.metamodel.aiohttp import _helper
3
+
3
4
  AIO_HTTP_PROCESSOR = {
4
5
  "type": SPAN_TYPES.HTTP_PROCESS,
5
6
  "attributes": [
@@ -14,11 +15,21 @@ AIO_HTTP_PROCESSOR = {
14
15
  "attribute": "route",
15
16
  "accessor": lambda arguments: _helper.get_route(arguments['args'])
16
17
  },
18
+ {
19
+ "_comment": "request method, request URI",
20
+ "attribute": "url",
21
+ "accessor": lambda arguments: _helper.get_url(arguments['args'])
22
+ },
23
+ {
24
+ "_comment": "request function name",
25
+ "attribute": "function_name",
26
+ "accessor": lambda arguments: _helper.get_function_name(arguments['args'])
27
+ },
17
28
  {
18
29
  "_comment": "request method, request URI",
19
30
  "attribute": "body",
20
31
  "accessor": lambda arguments: _helper.get_body(arguments['args'])
21
- },
32
+ }
22
33
  ]
23
34
  ],
24
35
  "events": [
@@ -37,8 +48,8 @@ AIO_HTTP_PROCESSOR = {
37
48
  "attributes": [
38
49
  {
39
50
  "_comment": "status from HTTP response",
40
- "attribute": "status",
41
- "accessor": lambda arguments: _helper.extract_status(arguments['result'])
51
+ "attribute": "error_code",
52
+ "accessor": lambda arguments: _helper.extract_status(arguments)
42
53
  },
43
54
  {
44
55
  "_comment": "this is result from LLM",
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from threading import local
3
- from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, try_option, Option, MonocleSpanException
3
+ from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, get_exception_status_code, try_option, Option, MonocleSpanException
4
4
  from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
5
5
  from monocle_apptrace.instrumentation.common.constants import HTTP_SUCCESS_CODES
6
6
  from urllib.parse import unquote, urlparse, ParseResult
@@ -13,7 +13,7 @@ def get_url(kwargs) -> ParseResult:
13
13
  url_str = try_option(getattr, kwargs['req'], 'url')
14
14
  url = url_str.unwrap_or(None)
15
15
  if url is not None:
16
- return urlparse(url)
16
+ return url
17
17
  else:
18
18
  return None
19
19
 
@@ -25,9 +25,11 @@ def get_function_name(kwargs) -> str:
25
25
 
26
26
 
27
27
  def get_route(kwargs) -> str:
28
- url:ParseResult = get_url(kwargs)
29
- if url is not None:
28
+ url_str = get_url(kwargs)
29
+ if url_str is not None:
30
+ url: ParseResult = urlparse(url_str)
30
31
  return url.path
32
+ return ""
31
33
 
32
34
  def get_method(kwargs) -> str:
33
35
  # return args[0]['method'] if 'method' in args[0] else ""
@@ -35,9 +37,11 @@ def get_method(kwargs) -> str:
35
37
  return http_method.unwrap_or("")
36
38
 
37
39
  def get_params(kwargs) -> dict:
38
- url:ParseResult = get_url(kwargs)
39
- if url is not None:
40
+ url_str = get_url(kwargs)
41
+ if url_str is not None:
42
+ url: ParseResult = urlparse(url_str)
40
43
  return unquote(url.query)
44
+ return {}
41
45
 
42
46
  def get_body(kwargs) -> dict:
43
47
  if hasattr(kwargs['req'], 'get_body'):
@@ -57,11 +61,17 @@ def extract_response(result) -> str:
57
61
  response = ""
58
62
  return response
59
63
 
60
- def extract_status(result) -> str:
61
- status = f"{result.status_code}" if hasattr(result, 'status_code') else ""
62
- if status not in HTTP_SUCCESS_CODES:
63
- error_message = extract_response(result)
64
- raise MonocleSpanException(f"error: {status} - {error_message}")
64
+ def extract_status(arguments) -> str:
65
+ if arguments["exception"] is not None:
66
+ return get_exception_status_code(arguments)
67
+ result = arguments['result']
68
+ if hasattr(result, 'status_code'):
69
+ status = f"{result.status_code}"
70
+ if status not in HTTP_SUCCESS_CODES:
71
+ error_message = extract_response(result)
72
+ raise MonocleSpanException(f"error: {status} - {error_message}", status)
73
+ else:
74
+ status = "success"
65
75
  return status
66
76
 
67
77
  def azure_func_pre_tracing(kwargs):
@@ -23,6 +23,11 @@ AZFUNC_HTTP_PROCESSOR = {
23
23
  "_comment": "request function name",
24
24
  "attribute": "function_name",
25
25
  "accessor": lambda arguments: _helper.get_function_name(arguments['kwargs'])
26
+ },
27
+ {
28
+ "_comment": "request function name",
29
+ "attribute": "url",
30
+ "accessor": lambda arguments: _helper.get_url(arguments['kwargs'])
26
31
  }
27
32
  ]
28
33
  ],
@@ -42,8 +47,8 @@ AZFUNC_HTTP_PROCESSOR = {
42
47
  "attributes": [
43
48
  {
44
49
  "_comment": "status from HTTP response",
45
- "attribute": "status",
46
- "accessor": lambda arguments: _helper.extract_status(arguments['result'])
50
+ "attribute": "error_code",
51
+ "accessor": lambda arguments: _helper.extract_status(arguments)
47
52
  },
48
53
  {
49
54
  "_comment": "this is result from LLM",
@@ -1,6 +1,6 @@
1
1
  import logging
2
2
  from threading import local
3
- from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes
3
+ from monocle_apptrace.instrumentation.common.utils import extract_http_headers, clear_http_scopes, get_exception_status_code
4
4
  from monocle_apptrace.instrumentation.common.span_handler import SpanHandler
5
5
  from monocle_apptrace.instrumentation.common.constants import HTTP_SUCCESS_CODES
6
6
  from monocle_apptrace.instrumentation.common.utils import MonocleSpanException
@@ -15,6 +15,13 @@ MAX_DATA_LENGTH = 1000
15
15
  token_data = local()
16
16
  token_data.current_token = None
17
17
 
18
+ def get_url(args) -> str:
19
+ server = args.get('server', ('127.0.0.1', 80))
20
+ host, port = server
21
+ path = args.get('path', '/')
22
+ scheme = args.get('scheme', 'http')
23
+ return f"{scheme}://{host}:{port}{path}"
24
+
18
25
  def get_route(scope) -> str:
19
26
  return scope.get('path', '')
20
27
 
@@ -42,11 +49,17 @@ def extract_response(response) -> str:
42
49
  logger.warning(f"Error extracting response: {e}")
43
50
  return ""
44
51
 
45
- def extract_status(instance) -> str:
46
- status = f"{instance.status_code}" if hasattr(instance, 'status_code') else ""
47
- if status not in HTTP_SUCCESS_CODES:
48
- error_message = extract_response(instance)
49
- raise MonocleSpanException(f"error: {status} - {error_message}")
52
+ def extract_status(arguments) -> str:
53
+ if arguments["exception"] is not None:
54
+ return get_exception_status_code(arguments)
55
+ instance = arguments['instance']
56
+ if hasattr(instance, 'status_code'):
57
+ status = f"{instance.status_code}"
58
+ if status not in HTTP_SUCCESS_CODES:
59
+ error_message = extract_response(instance)
60
+ raise MonocleSpanException(f"error: {status} - {error_message}", status)
61
+ else:
62
+ status = "success"
50
63
  return status
51
64
 
52
65
  def fastapi_pre_tracing(scope):
@@ -13,6 +13,10 @@ FASTAPI_HTTP_PROCESSOR = {
13
13
  "attribute": "route",
14
14
  "accessor": lambda arguments: _helper.get_route(arguments['args'][0])
15
15
  },
16
+ {
17
+ "attribute": "url",
18
+ "accessor": lambda arguments: _helper.get_url(arguments['args'][0])
19
+ },
16
20
  ]
17
21
  ]
18
22
  }
@@ -32,8 +36,8 @@ FASTAPI_RESPONSE_PROCESSOR = {
32
36
  "name": "data.output",
33
37
  "attributes": [
34
38
  {
35
- "attribute": "status",
36
- "accessor": lambda arguments: _helper.extract_status(arguments['instance'])
39
+ "attribute": "error_code",
40
+ "accessor": lambda arguments: _helper.extract_status(arguments)
37
41
  },
38
42
  {
39
43
  "attribute": "response",