From f77d82d8667dc48a455ddef7046d087a10e8e52f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 16 Apr 2026 21:37:00 +0000 Subject: [PATCH] Add debug logging to 5 Go files for improved troubleshooting - pkg/workflow/mcp_cli_mount.go: Add mcpCLIMountLog to trace MCP server selection decisions (feature flag checks, server list, mount step generation) - pkg/workflow/mcp_property_validation.go: Add mcpPropertyValidationLog to trace MCP type validation (explicit vs inferred type, per-tool validation entry) - pkg/workflow/build_input_schema.go: Add buildInputSchemaLog to trace input schema generation (per-input type/required, final property counts) - pkg/cli/gateway_logs_mcp.go: Reuse existing gatewayLogsLog to trace MCP tool usage extraction (log source selection, tool call counts, summary stats) - pkg/cli/logs_report_firewall.go: Add firewallReportLog to trace domain aggregation across runs (run count, final allowed/blocked domain counts) Co-Authored-By: Claude Sonnet 4.6 --- pkg/cli/gateway_logs_mcp.go | 10 ++++++++++ pkg/cli/logs_report_firewall.go | 7 +++++++ pkg/workflow/build_input_schema.go | 8 ++++++++ pkg/workflow/mcp_cli_mount.go | 8 ++++++++ pkg/workflow/mcp_property_validation.go | 7 +++++++ 5 files changed, 40 insertions(+) diff --git a/pkg/cli/gateway_logs_mcp.go b/pkg/cli/gateway_logs_mcp.go index a51dccdf019..6625a011b32 100644 --- a/pkg/cli/gateway_logs_mcp.go +++ b/pkg/cli/gateway_logs_mcp.go @@ -19,19 +19,24 @@ import ( // extractMCPToolUsageData creates detailed MCP tool usage data from gateway metrics func extractMCPToolUsageData(logDir string, verbose bool) (*MCPToolUsageData, error) { + gatewayLogsLog.Printf("Extracting MCP tool usage data from: %s", logDir) + // Parse gateway logs (falls back to rpc-messages.jsonl automatically) gatewayMetrics, err := parseGatewayLogs(logDir, verbose) if err != nil { // Return nil if no log file exists (not an error for workflows without MCP) if strings.Contains(err.Error(), "not found") { + gatewayLogsLog.Print("No gateway log file found, skipping MCP tool usage extraction") return nil, nil } return nil, fmt.Errorf("failed to parse gateway logs: %w", err) } if gatewayMetrics == nil || len(gatewayMetrics.Servers) == 0 { + gatewayLogsLog.Print("No gateway metrics or servers found") return nil, nil } + gatewayLogsLog.Printf("Found gateway metrics: %d servers", len(gatewayMetrics.Servers)) mcpData := &MCPToolUsageData{ Summary: []MCPToolSummary{}, @@ -66,20 +71,25 @@ func extractMCPToolUsageData(logDir string, verbose bool) (*MCPToolUsageData, er } if usingRPCMessages { + gatewayLogsLog.Printf("Reading tool calls from rpc-messages.jsonl: %s", gatewayLogPath) // Build tool call records from rpc-messages.jsonl toolCalls, err := buildToolCallsFromRPCMessages(gatewayLogPath) if err != nil { return nil, fmt.Errorf("failed to read rpc-messages.jsonl: %w", err) } mcpData.ToolCalls = toolCalls + gatewayLogsLog.Printf("Loaded %d tool calls from rpc-messages.jsonl", len(toolCalls)) } else { + gatewayLogsLog.Printf("Reading tool calls from gateway.jsonl: %s", gatewayLogPath) if err := extractToolCallsFromGatewayLog(gatewayLogPath, mcpData); err != nil { return nil, err } + gatewayLogsLog.Printf("Loaded %d tool calls from gateway.jsonl", len(mcpData.ToolCalls)) } // Build summary statistics from aggregated metrics buildMCPSummaryStats(gatewayMetrics, mcpData) + gatewayLogsLog.Printf("Built MCP summary: %d tool summaries, %d server stats", len(mcpData.Summary), len(mcpData.Servers)) return mcpData, nil } diff --git a/pkg/cli/logs_report_firewall.go b/pkg/cli/logs_report_firewall.go index 75e9b58732e..7706c39d98b 100644 --- a/pkg/cli/logs_report_firewall.go +++ b/pkg/cli/logs_report_firewall.go @@ -2,8 +2,12 @@ package cli import ( "slices" + + "github.com/github/gh-aw/pkg/logger" ) +var firewallReportLog = logger.New("cli:logs_report_firewall") + // AccessLogSummary contains aggregated access log analysis type AccessLogSummary struct { TotalRequests int `json:"total_requests" console:"header:Total Requests"` @@ -37,6 +41,7 @@ type domainAggregation struct { // aggregateDomainStats aggregates domain statistics across runs // This is a shared helper for both access log and firewall log summaries func aggregateDomainStats(processedRuns []ProcessedRun, getAnalysis func(*ProcessedRun) (allowedDomains, blockedDomains []string, totalRequests, allowedCount, blockedCount int, exists bool)) *domainAggregation { + firewallReportLog.Printf("Aggregating domain stats across %d runs", len(processedRuns)) agg := &domainAggregation{ allAllowedDomains: make(map[string]bool), allBlockedDomains: make(map[string]bool), @@ -60,6 +65,8 @@ func aggregateDomainStats(processedRuns []ProcessedRun, getAnalysis func(*Proces } } + firewallReportLog.Printf("Domain aggregation complete: %d allowed, %d blocked, %d total requests", + len(agg.allAllowedDomains), len(agg.allBlockedDomains), agg.totalRequests) return agg } diff --git a/pkg/workflow/build_input_schema.go b/pkg/workflow/build_input_schema.go index 5b816dff463..be8185725f7 100644 --- a/pkg/workflow/build_input_schema.go +++ b/pkg/workflow/build_input_schema.go @@ -1,5 +1,9 @@ package workflow +import "github.com/github/gh-aw/pkg/logger" + +var buildInputSchemaLog = logger.New("workflow:build_input_schema") + // buildInputSchema converts GitHub Actions input definitions (workflow_dispatch, // workflow_call, or dispatch_repository inputs) into JSON Schema properties and // a required field list suitable for MCP tool inputSchema. @@ -11,12 +15,14 @@ package workflow // Choice inputs with options are mapped to a string enum. Unknown types default // to string. func buildInputSchema(inputs map[string]any, descriptionFn func(inputName string) string) (properties map[string]any, required []string) { + buildInputSchemaLog.Printf("Building input schema for %d inputs", len(inputs)) properties = make(map[string]any) required = []string{} for inputName, inputDef := range inputs { inputDefMap, ok := inputDef.(map[string]any) if !ok { + buildInputSchemaLog.Printf("Skipping input %q: expected map, got %T", inputName, inputDef) continue } @@ -68,6 +74,7 @@ func buildInputSchema(inputs map[string]any, descriptionFn func(inputName string if defaultVal, ok := inputDefMap["default"]; ok { prop["default"] = defaultVal } + buildInputSchemaLog.Printf("Input %q: type=%s, required=%v", inputName, inputType, inputRequired) properties[inputName] = prop if inputRequired { @@ -75,5 +82,6 @@ func buildInputSchema(inputs map[string]any, descriptionFn func(inputName string } } + buildInputSchemaLog.Printf("Built input schema: %d properties, %d required", len(properties), len(required)) return properties, required } diff --git a/pkg/workflow/mcp_cli_mount.go b/pkg/workflow/mcp_cli_mount.go index 5e04a339f10..d26eaffdb68 100644 --- a/pkg/workflow/mcp_cli_mount.go +++ b/pkg/workflow/mcp_cli_mount.go @@ -7,8 +7,11 @@ import ( "strings" "github.com/github/gh-aw/pkg/constants" + "github.com/github/gh-aw/pkg/logger" ) +var mcpCLIMountLog = logger.New("workflow:mcp_cli_mount") + // mcp_cli_mount.go generates a workflow step that mounts MCP servers as local CLI tools // and produces the prompt section that informs the agent about these tools. // @@ -54,8 +57,10 @@ func getMCPCLIServerNames(data *WorkflowData) []string { // Without the feature flag, code generation remains unchanged regardless of // the mount-as-clis setting. if !isFeatureEnabled(constants.MCPCLIFeatureFlag, data) { + mcpCLIMountLog.Print("mcp-cli feature flag not enabled, skipping CLI mount generation") return nil } + mcpCLIMountLog.Print("mcp-cli feature flag enabled, collecting CLI server names") var servers []string @@ -109,10 +114,12 @@ func getMCPCLIServerNames(data *WorkflowData) []string { } if len(servers) == 0 { + mcpCLIMountLog.Print("No MCP CLI servers configured") return nil } sort.Strings(servers) + mcpCLIMountLog.Printf("MCP CLI servers selected: %v", servers) return servers } @@ -150,6 +157,7 @@ func (c *Compiler) generateMCPCLIMountStep(yaml *strings.Builder, data *Workflow if len(servers) == 0 { return } + mcpCLIMountLog.Printf("Generating MCP CLI mount step for %d servers: %v", len(servers), servers) yaml.WriteString(" - name: Mount MCP servers as CLIs\n") yaml.WriteString(" id: mount-mcp-clis\n") diff --git a/pkg/workflow/mcp_property_validation.go b/pkg/workflow/mcp_property_validation.go index fe93da1df3e..6dcc047f662 100644 --- a/pkg/workflow/mcp_property_validation.go +++ b/pkg/workflow/mcp_property_validation.go @@ -15,9 +15,12 @@ import ( "fmt" "github.com/github/gh-aw/pkg/constants" + "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/parser" ) +var mcpPropertyValidationLog = logger.New("workflow:mcp_property_validation") + // validateStringProperty validates that a property is a string and returns appropriate error message func validateStringProperty(toolName, propertyName string, value any, exists bool) error { if !exists { @@ -31,6 +34,8 @@ func validateStringProperty(toolName, propertyName string, value any, exists boo // validateMCPRequirements validates the specific requirements for MCP configuration func validateMCPRequirements(toolName string, mcpConfig map[string]any, toolConfig map[string]any) error { + mcpPropertyValidationLog.Printf("Validating MCP requirements for tool: %s", toolName) + // Validate 'type' property - allow inference from other fields mcpType, hasType := mcpConfig["type"] var typeStr string @@ -41,12 +46,14 @@ func validateMCPRequirements(toolName string, mcpConfig map[string]any, toolConf return fmt.Errorf("tool '%s' mcp configuration 'type' must be a string, got %T. Valid types per MCP Gateway Specification: stdio, http. Note: 'local' is accepted for backward compatibility and treated as 'stdio'.\n\nExample:\ntools:\n %s:\n type: \"stdio\"\n command: \"node server.js\"\n\nSee: %s", toolName, mcpType, toolName, constants.DocsToolsURL) } typeStr = mcpType.(string) + mcpPropertyValidationLog.Printf("Tool %s: explicit MCP type=%s", toolName, typeStr) } else { // Infer type from presence of fields typeStr = inferMCPType(mcpConfig) if typeStr == "" { return fmt.Errorf("tool '%s' unable to determine MCP type: missing type, url, command, or container.\n\nExample:\ntools:\n %s:\n command: \"node server.js\"\n args: [\"--port\", \"3000\"]\n\nSee: %s", toolName, toolName, constants.DocsToolsURL) } + mcpPropertyValidationLog.Printf("Tool %s: inferred MCP type=%s", toolName, typeStr) } // Normalize "local" to "stdio" for validation