diff --git a/scripts/metricsdocgen/scanner/scanner.go b/scripts/metricsdocgen/scanner/scanner.go index e38da99876..eee4166e49 100644 --- a/scripts/metricsdocgen/scanner/scanner.go +++ b/scripts/metricsdocgen/scanner/scanner.go @@ -20,6 +20,7 @@ import ( "sort" "strings" + "golang.org/x/term" "golang.org/x/xerrors" ) @@ -80,6 +81,26 @@ type declarations struct { // constants from later directories won't be available when scanning earlier ones. var packageDeclarations = make(map[string]map[string]string) +// verbose controls whether informational messages are printed to +// stderr. It is true when stdout is a terminal (interactive use) +// and false when stdout is piped (e.g. via atomic_write in make). +var verbose = term.IsTerminal(int(os.Stdout.Fd())) + +// logf prints an informational message to stderr only when running +// interactively. Use this for progress and debug output that is +// not actionable. +func logf(format string, args ...any) { + if verbose { + log.Printf(format, args...) + } +} + +// warnf prints a warning to stderr unconditionally. Use this for +// messages about real problems that a developer should investigate. +func warnf(format string, args ...any) { + log.Printf("WARNING: "+format, args...) +} + func main() { metrics, err := scanAllDirs() if err != nil { @@ -103,7 +124,7 @@ func main() { writeMetrics(metrics, os.Stdout) - log.Printf("Successfully parsed %d metrics", len(metrics)) + logf("Successfully parsed %d metrics", len(metrics)) } // scanAllDirs scans all configured directories for metric definitions. @@ -116,7 +137,7 @@ func scanAllDirs() ([]Metric, error) { return nil, xerrors.Errorf("scanning %s: %w", dir, err) } - log.Printf("scanning %s: found %d metrics", dir, len(metrics)) + logf("scanning %s: found %d metrics", dir, len(metrics)) allMetrics = append(allMetrics, metrics...) } @@ -155,7 +176,7 @@ func scanDirectory(root string) ([]Metric, error) { } if len(fileMetrics) > 0 { - log.Printf("scanning %s: found %d metrics", path, len(fileMetrics)) + logf("scanning %s: found %d metrics", path, len(fileMetrics)) } metrics = append(metrics, fileMetrics...) @@ -191,7 +212,7 @@ func scanFile(path string) ([]Metric, error) { metric, ok := extractMetricFromCall(call, decls) if ok { if metric.Help == "" { - log.Printf("WARNING: metric %q has no HELP description, skipping", metric.Name) + warnf("metric %q has no HELP description, skipping", metric.Name) // Skip metrics without descriptions, they should be fixed in the source code // or added to the static metrics file with a manual description. return true @@ -392,7 +413,7 @@ func extractNewDescMetric(call *ast.CallExpr, decls declarations) (Metric, bool) // Extract name (first argument). name := resolveStringExpr(call.Args[0], decls) if name == "" { - log.Printf("extractNewDescMetric: skipping prometheus.NewDesc() call: could not resolve metric name") + warnf("extractNewDescMetric: skipping prometheus.NewDesc() call: could not resolve metric name") return Metric{}, false } @@ -542,7 +563,7 @@ func extractOptsMetric(call *ast.CallExpr, decls declarations) (Metric, bool) { // Extract metric info from the Opts struct. opts, ok := extractOpts(call.Args[0], decls) if !ok { - log.Printf("extractOptsMetric: skipping prometheus.%s() call: could not extract opts", funcName) + warnf("extractOptsMetric: skipping prometheus.%s() call: could not extract opts", funcName) return Metric{}, false } @@ -555,7 +576,7 @@ func extractOptsMetric(call *ast.CallExpr, decls declarations) (Metric, bool) { // Build the full metric name. name := buildMetricName(opts.Namespace, opts.Subsystem, opts.Name) if name == "" { - log.Printf("extractOptsMetric: skipping prometheus.%s() call: could not build metric name", funcName) + warnf("extractOptsMetric: skipping prometheus.%s() call: could not build metric name", funcName) return Metric{}, false } @@ -627,7 +648,7 @@ func extractPromautoMetric(call *ast.CallExpr, decls declarations) (Metric, bool // Extract metric info from the Opts struct. opts, ok := extractOpts(call.Args[0], decls) if !ok { - log.Printf("extractPromautoMetric: skipping promauto.%s() call: could not extract opts", funcName) + warnf("extractPromautoMetric: skipping promauto.%s() call: could not extract opts", funcName) return Metric{}, false } @@ -640,7 +661,7 @@ func extractPromautoMetric(call *ast.CallExpr, decls declarations) (Metric, bool // Build the full metric name. name := buildMetricName(opts.Namespace, opts.Subsystem, opts.Name) if name == "" { - log.Printf("extractPromautoMetric: skipping promauto.%s() call: could not build metric name", funcName) + warnf("extractPromautoMetric: skipping promauto.%s() call: could not build metric name", funcName) return Metric{}, false }