From 56fce221af3637981c6bf98e1fe97e56bc159035 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 25 Mar 2026 21:30:19 +0000 Subject: [PATCH] Add debug logging to episode, audit, observability, glob, and MCP renderer files Adds logger declarations and meaningful log calls to 5 files that previously had no debug logging, aiding troubleshooting of episode classification, agentic analysis, observability insight generation, glob pattern validation, and MCP config rendering. Co-Authored-By: Claude Sonnet 4.6 --- pkg/cli/audit_agentic_analysis.go | 6 ++++++ pkg/cli/logs_episode.go | 6 ++++++ pkg/cli/observability_insights.go | 6 ++++++ pkg/workflow/glob_validation.go | 12 +++++++++++- pkg/workflow/mcp_renderer_helpers.go | 9 ++++++++- 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/cli/audit_agentic_analysis.go b/pkg/cli/audit_agentic_analysis.go index 9674a2120f0..41e342cecfa 100644 --- a/pkg/cli/audit_agentic_analysis.go +++ b/pkg/cli/audit_agentic_analysis.go @@ -7,10 +7,13 @@ import ( "strings" "time" + "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/timeutil" "github.com/github/gh-aw/pkg/workflow" ) +var auditAgenticLog = logger.New("cli:audit_agentic_analysis") + // TaskDomainInfo describes the dominant task type inferred for a workflow run. type TaskDomainInfo struct { Name string `json:"name"` @@ -86,6 +89,7 @@ func buildToolUsageInfo(metrics LogMetrics) []ToolUsageInfo { } func deriveRunAgenticAnalysis(processedRun ProcessedRun, metrics LogMetrics) (*AwContext, []ToolUsageInfo, []CreatedItemReport, *TaskDomainInfo, *BehaviorFingerprint, []AgenticAssessment) { + auditAgenticLog.Printf("Deriving agentic analysis for run: id=%d workflow=%s", processedRun.Run.DatabaseID, processedRun.Run.WorkflowName) var awContext *AwContext if processedRun.AwContext != nil { awContext = processedRun.AwContext @@ -110,10 +114,12 @@ func deriveRunAgenticAnalysis(processedRun ProcessedRun, metrics LogMetrics) (*A behaviorFingerprint := buildBehaviorFingerprint(processedRun, metricsData, toolUsage, createdItems, awContext) agenticAssessments := buildAgenticAssessments(processedRun, metricsData, toolUsage, createdItems, taskDomain, behaviorFingerprint, awContext) + auditAgenticLog.Printf("Agentic analysis complete: tool_types=%d created_items=%d assessments=%d", len(toolUsage), len(createdItems), len(agenticAssessments)) return awContext, toolUsage, createdItems, taskDomain, behaviorFingerprint, agenticAssessments } func detectTaskDomain(processedRun ProcessedRun, createdItems []CreatedItemReport, toolUsage []ToolUsageInfo, awContext *AwContext) *TaskDomainInfo { + auditAgenticLog.Printf("Detecting task domain for run: workflow=%s event=%s", processedRun.Run.WorkflowName, processedRun.Run.Event) combined := strings.ToLower(strings.Join([]string{ processedRun.Run.WorkflowName, processedRun.Run.WorkflowPath, diff --git a/pkg/cli/logs_episode.go b/pkg/cli/logs_episode.go index 159d82e5d5e..353d286df1d 100644 --- a/pkg/cli/logs_episode.go +++ b/pkg/cli/logs_episode.go @@ -8,9 +8,12 @@ import ( "strings" "time" + "github.com/github/gh-aw/pkg/logger" "github.com/github/gh-aw/pkg/timeutil" ) +var logsEpisodeLog = logger.New("cli:logs_episode") + // EpisodeEdge represents a deterministic lineage edge between two workflow runs. type EpisodeEdge struct { SourceRunID int64 `json:"source_run_id"` @@ -71,6 +74,7 @@ type episodeSeed struct { } func buildEpisodeData(runs []RunData, processedRuns []ProcessedRun) ([]EpisodeData, []EpisodeEdge) { + logsEpisodeLog.Printf("Building episode data: runs=%d processed_runs=%d", len(runs), len(processedRuns)) runsByID := make(map[int64]RunData, len(runs)) processedByID := make(map[int64]ProcessedRun, len(processedRuns)) seedsByRunID := make(map[int64]episodeSeed, len(runs)) @@ -230,6 +234,7 @@ func buildEpisodeData(runs []RunData, processedRuns []ProcessedRun) ([]EpisodeDa return cmp.Compare(a.TargetRunID, b.TargetRunID) }) + logsEpisodeLog.Printf("Built %d episodes and %d edges from %d runs", len(episodes), len(edges), len(runs)) return episodes, edges } @@ -287,6 +292,7 @@ func seedConfidenceRank(confidence string) int { } func classifyEpisode(run RunData) (string, string, string, []string) { + logsEpisodeLog.Printf("Classifying episode for run: id=%d event=%s", run.DatabaseID, run.Event) if run.AwContext != nil { if run.AwContext.WorkflowCallID != "" { return "dispatch:" + run.AwContext.WorkflowCallID, "dispatch_workflow", "high", []string{"context.workflow_call_id"} diff --git a/pkg/cli/observability_insights.go b/pkg/cli/observability_insights.go index b2cb45cee2b..a12d6709041 100644 --- a/pkg/cli/observability_insights.go +++ b/pkg/cli/observability_insights.go @@ -4,8 +4,12 @@ import ( "fmt" "os" "strings" + + "github.com/github/gh-aw/pkg/logger" ) +var observabilityInsightsLog = logger.New("cli:observability_insights") + type ObservabilityInsight struct { Category string `json:"category"` Severity string `json:"severity"` @@ -31,6 +35,7 @@ type workflowObservabilityStats struct { } func buildAuditObservabilityInsights(processedRun ProcessedRun, metrics MetricsData, toolUsage []ToolUsageInfo, createdItems []CreatedItemReport) []ObservabilityInsight { + observabilityInsightsLog.Printf("Building audit observability insights: run_id=%d turns=%d tool_types=%d", processedRun.Run.DatabaseID, metrics.Turns, len(toolUsage)) insights := make([]ObservabilityInsight, 0, 5) toolTypes := len(toolUsage) @@ -135,6 +140,7 @@ func buildLogsObservabilityInsights(processedRuns []ProcessedRun, toolUsage []To return nil } + observabilityInsightsLog.Printf("Building logs observability insights: processed_runs=%d tool_usage_entries=%d", len(processedRuns), len(toolUsage)) insights := make([]ObservabilityInsight, 0, 6) workflowStats := make(map[string]*workflowObservabilityStats) writeRuns := 0 diff --git a/pkg/workflow/glob_validation.go b/pkg/workflow/glob_validation.go index 06d14c5a8c3..53647e188a3 100644 --- a/pkg/workflow/glob_validation.go +++ b/pkg/workflow/glob_validation.go @@ -21,8 +21,12 @@ import ( "strings" "text/scanner" "unicode" + + "github.com/github/gh-aw/pkg/logger" ) +var globValidationLog = logger.New("workflow:glob_validation") + // invalidGlobPattern describes a single validation error within a glob pattern. type invalidGlobPattern struct { // Message is a human-readable description of the problem. @@ -217,13 +221,19 @@ func runGlobValidation(pat string, isRef bool) []invalidGlobPattern { // validateRefGlob validates a GitHub Actions ref filter glob (branch or tag pattern). // It returns a non-empty slice of invalidGlobPattern when the pattern is invalid. func validateRefGlob(pat string) []invalidGlobPattern { - return runGlobValidation(pat, true) + globValidationLog.Printf("Validating ref glob pattern: %s", pat) + errs := runGlobValidation(pat, true) + if len(errs) > 0 { + globValidationLog.Printf("Ref glob pattern invalid: %d error(s) found", len(errs)) + } + return errs } // validatePathGlob validates a GitHub Actions path filter glob. // It returns a non-empty slice of invalidGlobPattern when the pattern is invalid. // Path patterns starting with "./" or "../" are explicitly rejected. func validatePathGlob(pat string) []invalidGlobPattern { + globValidationLog.Printf("Validating path glob pattern: %s", pat) p := strings.TrimSpace(pat) var errs []invalidGlobPattern diff --git a/pkg/workflow/mcp_renderer_helpers.go b/pkg/workflow/mcp_renderer_helpers.go index f7c313d8a47..37c63e1f3a8 100644 --- a/pkg/workflow/mcp_renderer_helpers.go +++ b/pkg/workflow/mcp_renderer_helpers.go @@ -1,6 +1,12 @@ package workflow -import "strings" +import ( + "strings" + + "github.com/github/gh-aw/pkg/logger" +) + +var mcpRendererHelpersLog = logger.New("workflow:mcp_renderer_helpers") // renderStandardJSONMCPConfig is a shared helper for JSON MCP config rendering used by // Claude, Gemini, Copilot, and Codex engines. It consolidates the repeated sequence of: @@ -29,6 +35,7 @@ func renderStandardJSONMCPConfig( renderCustom RenderCustomMCPToolConfigHandler, filterTool func(string) bool, ) error { + mcpRendererHelpersLog.Printf("Rendering standard JSON MCP config: config_path=%s tools=%d mcp_tools=%d", configPath, len(tools), len(mcpTools)) createRenderer := buildMCPRendererFactory(workflowData, "json", includeCopilotFields, inlineArgs) return RenderJSONMCPConfig(yaml, tools, mcpTools, workflowData, JSONMCPConfigOptions{ ConfigPath: configPath,