diff --git a/holmes/plugins/toolsets/datadog/datadog_traces_formatter.py b/holmes/plugins/toolsets/datadog/datadog_traces_formatter.py index 43fcf0817..769265784 100644 --- a/holmes/plugins/toolsets/datadog/datadog_traces_formatter.py +++ b/holmes/plugins/toolsets/datadog/datadog_traces_formatter.py @@ -282,6 +282,42 @@ def format_spans_search( if status and status != "ok": output_lines.append(f" │ status: {status}") + # Check for custom error information + custom = attrs.get("custom") or {} + if not isinstance(custom, dict): + custom = {} + error_info = custom.get("error") + if isinstance(error_info, dict) and error_info: + output_lines.append(" │ error:") + + # Extract error fields + error_id = error_info.get("id") + error_file = error_info.get("file") + error_stack = error_info.get("stack") + error_message = error_info.get("message") + error_type = error_info.get("type") + + if error_id: + output_lines.append(f" │ id: {error_id}") + if error_file: + output_lines.append(f" │ file: {error_file}") + if error_message: + output_lines.append(f" │ message: {error_message}") + if error_type: + output_lines.append(f" │ type: {error_type}") + if error_stack: + # Truncate stack trace for readability and support list inputs + if isinstance(error_stack, list): + lines = [str(x) for x in error_stack] + else: + lines = str(error_stack).splitlines() + stack_lines = lines[:5] + output_lines.append(f" │ stack: {stack_lines[0]}") + for stack_line in stack_lines[1:]: + output_lines.append(f" │ {stack_line}") + if len(lines) > 5: + output_lines.append(" │ ... (truncated)") + # Show important tags tags = attrs.get("tags", []) important_tags = {} diff --git a/holmes/plugins/toolsets/datadog/toolset_datadog_traces.py b/holmes/plugins/toolsets/datadog/toolset_datadog_traces.py index 73220ba4a..3c7ca1595 100644 --- a/holmes/plugins/toolsets/datadog/toolset_datadog_traces.py +++ b/holmes/plugins/toolsets/datadog/toolset_datadog_traces.py @@ -159,6 +159,11 @@ def __init__(self, toolset: "DatadogTracesToolset"): name="fetch_datadog_traces", description="[datadog/traces toolset] Fetch a list of traces from Datadog with optional filters", parameters={ + "query": ToolParameter( + description="Datadog search query (e.g., 'service:web-app @http.status_code:500')", + type="string", + required=False, + ), "service": ToolParameter( description="Filter by service name", type="string", @@ -200,6 +205,9 @@ def __init__(self, toolset: "DatadogTracesToolset"): def get_parameterized_one_liner(self, params: dict) -> str: """Get a one-liner description of the tool invocation.""" + if "query" in params: + return f"{toolset_name_for_one_liner(self.toolset.name)}: Fetch Traces ({params['query']})" + filters = [] if "service" in params: filters.append(f"service={params['service']}") @@ -238,6 +246,11 @@ def _invoke(self, params: dict, context: ToolInvokeContext) -> StructuredToolRes # Build search query query_parts = [] + # If a custom query is provided, use it as the base + if params.get("query"): + query_parts.append(params["query"]) + + # Add additional filters if params.get("service"): query_parts.append(f"service:{params['service']}")