From c50c4a27a6518a39d291ee4d0c6733a88cd26359 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 11 Jul 2026 04:31:45 +0000 Subject: [PATCH] Add debug logging to custom linter analyzers Instrument five previously-uninstrumented custom Go analysis linters in pkg/linters/ with the project's namespace-based logger (pkg/logger): - httprespbodyclose - largefunc - deferinloop - excessivefuncparams - httpstatuscode Each linter gains a package-level `log = logger.New("linters:")`, an entry log in run() (package path plus threshold where relevant), and a report-site log at each diagnostic chokepoint. Logger arguments are side-effect-free (already-computed locals and the pass.Pkg.Path() getter), and calls are zero-overhead when DEBUG is unset. These analyzers contain real AST control-flow logic but had no logging, unlike pkg/workflow, pkg/parser and pkg/cli which are already fully instrumented. Co-Authored-By: Claude Opus 4.8 (1M context) --- pkg/linters/deferinloop/deferinloop.go | 6 ++++++ pkg/linters/excessivefuncparams/excessivefuncparams.go | 6 ++++++ pkg/linters/httprespbodyclose/httprespbodyclose.go | 7 +++++++ pkg/linters/httpstatuscode/httpstatuscode.go | 7 +++++++ pkg/linters/largefunc/largefunc.go | 6 ++++++ 5 files changed, 32 insertions(+) diff --git a/pkg/linters/deferinloop/deferinloop.go b/pkg/linters/deferinloop/deferinloop.go index d88a71c0490..6709a8c8292 100644 --- a/pkg/linters/deferinloop/deferinloop.go +++ b/pkg/linters/deferinloop/deferinloop.go @@ -15,8 +15,11 @@ import ( "github.com/github/gh-aw/pkg/linters/internal/astutil" "github.com/github/gh-aw/pkg/linters/internal/filecheck" "github.com/github/gh-aw/pkg/linters/internal/nolint" + "github.com/github/gh-aw/pkg/logger" ) +var log = logger.New("linters:deferinloop") + // Analyzer is the defer-in-loop analysis pass. var Analyzer = &analysis.Analyzer{ Name: "deferinloop", @@ -27,6 +30,8 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (any, error) { + log.Printf("analyzing package %s", pass.Pkg.Path()) + insp, err := astutil.Inspector(pass) if err != nil { return nil, err @@ -51,6 +56,7 @@ func run(pass *analysis.Pass) (any, error) { continue } + log.Printf("flagging defer inside loop at %s", pos) pass.ReportRangef(deferStmt, "defer inside a loop does not execute at the end of each iteration; it runs when the enclosing function returns, which can cause resource leaks") } diff --git a/pkg/linters/excessivefuncparams/excessivefuncparams.go b/pkg/linters/excessivefuncparams/excessivefuncparams.go index a058fd98f7a..48d2e089967 100644 --- a/pkg/linters/excessivefuncparams/excessivefuncparams.go +++ b/pkg/linters/excessivefuncparams/excessivefuncparams.go @@ -11,8 +11,11 @@ import ( "github.com/github/gh-aw/pkg/linters/internal/astutil" "github.com/github/gh-aw/pkg/linters/internal/filecheck" "github.com/github/gh-aw/pkg/linters/internal/nolint" + "github.com/github/gh-aw/pkg/logger" ) +var log = logger.New("linters:excessivefuncparams") + // DefaultMaxParams is the default maximum number of parameters allowed in a function declaration. const DefaultMaxParams = 8 @@ -34,6 +37,8 @@ func init() { } func run(pass *analysis.Pass) (any, error) { + log.Printf("analyzing package %s (max-params=%d)", pass.Pkg.Path(), maxParams) + insp, err := astutil.Inspector(pass) if err != nil { return nil, err @@ -70,6 +75,7 @@ func run(pass *analysis.Pass) (any, error) { if nolint.HasDirective(position, noLintLinesByFile) { return } + log.Printf("flagging %s: %d parameters exceeds limit %d", fn.Name.Name, params, maxParams) pass.ReportRangef( fn.Name, "%s has %d parameters (limit: %d); consider using an options struct", diff --git a/pkg/linters/httprespbodyclose/httprespbodyclose.go b/pkg/linters/httprespbodyclose/httprespbodyclose.go index e1348f1d5aa..08b4e04a058 100644 --- a/pkg/linters/httprespbodyclose/httprespbodyclose.go +++ b/pkg/linters/httprespbodyclose/httprespbodyclose.go @@ -13,8 +13,11 @@ import ( "github.com/github/gh-aw/pkg/linters/internal/astutil" "github.com/github/gh-aw/pkg/linters/internal/filecheck" "github.com/github/gh-aw/pkg/linters/internal/nolint" + "github.com/github/gh-aw/pkg/logger" ) +var log = logger.New("linters:httprespbodyclose") + // Analyzer is the http-resp-body-close analysis pass. var Analyzer = &analysis.Analyzer{ Name: "httprespbodyclose", @@ -25,6 +28,8 @@ var Analyzer = &analysis.Analyzer{ } func run(pass *analysis.Pass) (any, error) { + log.Printf("analyzing package %s", pass.Pkg.Path()) + insp, err := astutil.Inspector(pass) if err != nil { return nil, err @@ -172,6 +177,8 @@ type respVarState struct { } func reportMissingDefer(pass *analysis.Pass, state *respVarState) { + log.Printf("flagging non-deferred Body.Close() at %s", pass.Fset.PositionFor(state.assignPos, false)) + diag := analysis.Diagnostic{ Pos: state.assignPos, Message: "HTTP response Body.Close() should be deferred immediately after receiving the response to prevent resource leaks", diff --git a/pkg/linters/httpstatuscode/httpstatuscode.go b/pkg/linters/httpstatuscode/httpstatuscode.go index dbca642295a..42783eec6d5 100644 --- a/pkg/linters/httpstatuscode/httpstatuscode.go +++ b/pkg/linters/httpstatuscode/httpstatuscode.go @@ -16,8 +16,11 @@ import ( "github.com/github/gh-aw/pkg/linters/internal/astutil" "github.com/github/gh-aw/pkg/linters/internal/filecheck" "github.com/github/gh-aw/pkg/linters/internal/nolint" + "github.com/github/gh-aw/pkg/logger" ) +var log = logger.New("linters:httpstatuscode") + var Analyzer = &analysis.Analyzer{ Name: "httpstatuscode", Doc: "reports integer HTTP status code literals used in comparisons that should use http.Status* named constants", @@ -91,6 +94,8 @@ var httpStatusNames = map[int]string{ } func run(pass *analysis.Pass) (any, error) { + log.Printf("analyzing package %s", pass.Pkg.Path()) + root, err := astutil.Root(pass) if err != nil { return nil, err @@ -149,6 +154,8 @@ func checkAndReport(pass *analysis.Pass, lit *ast.BasicLit, noLintLinesByFile ma return } + log.Printf("flagging magic HTTP status code %d at %s", code, pos) + if name, ok := httpStatusNames[code]; ok { pass.Reportf(lit.Pos(), "use %s instead of magic HTTP status code %d", name, code) return diff --git a/pkg/linters/largefunc/largefunc.go b/pkg/linters/largefunc/largefunc.go index 59bd184d551..e63b2a2029c 100644 --- a/pkg/linters/largefunc/largefunc.go +++ b/pkg/linters/largefunc/largefunc.go @@ -11,8 +11,11 @@ import ( "github.com/github/gh-aw/pkg/linters/internal/astutil" "github.com/github/gh-aw/pkg/linters/internal/filecheck" "github.com/github/gh-aw/pkg/linters/internal/nolint" + "github.com/github/gh-aw/pkg/logger" ) +var log = logger.New("linters:largefunc") + // DefaultMaxLines is the default maximum number of lines allowed in a function body. const DefaultMaxLines = 60 @@ -34,6 +37,8 @@ func init() { } func run(pass *analysis.Pass) (any, error) { + log.Printf("analyzing package %s (max-lines=%d)", pass.Pkg.Path(), maxLines) + insp, err := astutil.Inspector(pass) if err != nil { return nil, err @@ -79,6 +84,7 @@ func run(pass *analysis.Pass) (any, error) { if nolint.HasDirective(position, noLintLinesByFile) { return } + log.Printf("flagging %s: %d lines exceeds limit %d", name, lines, maxLines) pass.ReportRangef( reportNode, "%s is %d lines long (limit: %d); consider breaking it up",