From 4e6cbf864c4c60634347f4277dda099fb83522aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sun, 11 Oct 2026 04:53:43 +0200 Subject: [PATCH] mixin: explain "not in Go" goroutines, allow a compact dashboard (#2671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 (1M context) Signed-off-by: Jan-Otto Kröpke --- contrib/mixin/README.md | 15 ++++++++++++++- contrib/mixin/config.libsonnet | 5 +++++ contrib/mixin/dashboards/exporter.libsonnet | 2 +- .../mixin/dashboards/windows-exporter.libsonnet | 10 ++++++---- contrib/mixin/tests/dashboard.test.jsonnet | 10 ++++++++-- dashboard/windows-exporter-dashboard.json | 2 +- 6 files changed, 35 insertions(+), 9 deletions(-) diff --git a/contrib/mixin/README.md b/contrib/mixin/README.md index c6634214..46c6b299 100644 --- a/contrib/mixin/README.md +++ b/contrib/mixin/README.md @@ -257,7 +257,8 @@ The checked-in JSON remains the reference for the rendered dashboard, including queries, IDs, variables, annotations, transformations, and tab/row layout. `mise run check-dashboards` regenerates it and runs `git diff --exit-code`, displaying any drift. CI runs that check before the mixin tests. The dashboard uses its own -variables for selectors; from `_config` it reads only `collectors`. +variables for selectors; from `_config` it reads only `collectors`, +`enableFleetTab` and `enableOverviewTab`. ### Collectors @@ -279,6 +280,18 @@ object with `collectors:` enables only the listed collectors: }.grafanaDashboards['windows-exporter.json'] ``` +The Fleet and Overview tabs combine several collectors. For a compact +dashboard with only the collector tabs and the Exporter tab, turn them off: + +```jsonnet +(import 'mixin.libsonnet') { + _config+:: { + enableFleetTab: false, + enableOverviewTab: false, + }, +}.grafanaDashboards['windows-exporter.json'] +``` + The committed sample dashboard enables every collector. The Fleet hosts table always queries the default collectors; its columns stay empty for collectors that are turned off. Tab sources are diff --git a/contrib/mixin/config.libsonnet b/contrib/mixin/config.libsonnet index ee21678f..e8ac85e3 100644 --- a/contrib/mixin/config.libsonnet +++ b/contrib/mixin/config.libsonnet @@ -11,6 +11,11 @@ // Requires the time collector with its ntp subcollector enabled. enableTime: false, + // Dashboard tabs that don't belong to a single collector. Turn them off + // for a compact dashboard with only the collector tabs. + enableFleetTab: true, + enableOverviewTab: true, + // Collectors enabled on the windows_exporter targets, by collector name. // The dashboard only renders the tabs, rows and panels of enabled // collectors. The defaults match the exporter's default collectors. diff --git a/contrib/mixin/dashboards/exporter.libsonnet b/contrib/mixin/dashboards/exporter.libsonnet index 3b4169c7..7098318f 100644 --- a/contrib/mixin/dashboards/exporter.libsonnet +++ b/contrib/mixin/dashboards/exporter.libsonnet @@ -495,7 +495,7 @@ function(on) }), b.panel.new(107, 'Goroutines by state', 'timeseries') - + b.panel.withDescription('Steady growth of goroutines points to a goroutine leak. Goroutines that stay "not in Go" sit in a system call, for example a collector waiting on WMI or PDH. The states need an exporter build with the Go scheduler metrics; the total line works with every build.') + + b.panel.withDescription('Steady growth of goroutines points to a goroutine leak. Goroutines that stay "not in Go" sit in a system call, for example a collector waiting on WMI or PDH. The states need an exporter build with the Go scheduler metrics; the total line works with every build. Since 0.32, "not in Go" keeps growing even without a leak: a Go runtime bug (golang/go#82136) counts each WMI callback from a Windows thread once and never subtracts it. Use the total line to spot a leak instead.') + b.panel.withQueries([ b.query.new('go_sched_goroutines_running_goroutines{job=~"$job", instance="$instance"}', 'A') + b.query.withLegendFormat('running'), diff --git a/contrib/mixin/dashboards/windows-exporter.libsonnet b/contrib/mixin/dashboards/windows-exporter.libsonnet index 1d3e6ecf..746176ae 100644 --- a/contrib/mixin/dashboards/windows-exporter.libsonnet +++ b/contrib/mixin/dashboards/windows-exporter.libsonnet @@ -1,7 +1,9 @@ local b = import 'builders.libsonnet'; local dashboard = b.dashboard; -// config.collectors selects the collectors the dashboard renders, see config.libsonnet. +// config.collectors selects the collectors the dashboard renders, and +// config.enableFleetTab and config.enableOverviewTab the tabs across +// collectors, see config.libsonnet. function(config) local known = std.objectFields((import '../config.libsonnet')._config.collectors); local unknown = std.setDiff(std.objectFields(config.collectors), known); @@ -15,8 +17,8 @@ function(config) local tabs = [ tab for tab in [ - (import 'fleet.libsonnet')(on, config), - (import 'overview.libsonnet')(on), + if config.enableFleetTab then (import 'fleet.libsonnet')(on, config), + if config.enableOverviewTab then (import 'overview.libsonnet')(on), (import 'cpu.libsonnet')(on), (import 'memory.libsonnet')(on), (import 'disk.libsonnet')(on), @@ -31,7 +33,7 @@ function(config) (import 'time.libsonnet')(on), (import 'exporter.libsonnet')(on), ] - if !tab.empty + if tab != null && !tab.empty ]; local panelNames = std.flattenArrays([std.objectFields(tab.elements) for tab in tabs]); diff --git a/contrib/mixin/tests/dashboard.test.jsonnet b/contrib/mixin/tests/dashboard.test.jsonnet index 41d0cca9..7aa33bbd 100644 --- a/contrib/mixin/tests/dashboard.test.jsonnet +++ b/contrib/mixin/tests/dashboard.test.jsonnet @@ -3,8 +3,8 @@ // empty. Run with jsonnet -J vendor tests/dashboard.test.jsonnet. local mixin = import '../mixin.libsonnet'; -local render(collectors) = - (mixin { _config+:: { collectors: collectors(super.collectors) } }).grafanaDashboards['windows-exporter.json']; +local render(collectors, config={}) = + (mixin { _config+:: { collectors: collectors(super.collectors) } + config }).grafanaDashboards['windows-exporter.json']; local all(value) = function(collectors) { [name]: value for name in std.objectFields(collectors) }; local placed(layout) = @@ -36,6 +36,8 @@ local results = { storageSpacesOnly: summary(render(only({ storage_spaces: true }))).Disk, // A collectors object given without +: enables only the listed collectors. replaced: summary(render(function(_) { os: true, cpu: true })), + // Only collector tabs, for a compact dashboard. + collectorTabsOnly: summary(render(function(_) { os: true, cpu: true }, { enableFleetTab: false, enableOverviewTab: false })), }; local expect(name, want) = @@ -64,5 +66,9 @@ assert expect('replaced', { Fleet: ['Summary', 'Hosts', 'Utilization'], Overview: ['Summary', 'CPU and memory'], }); +assert expect('collectorTabsOnly', { + CPU: ['Summary', 'Utilization', 'System calls and frequency'], + Exporter: exporter, +}); results diff --git a/dashboard/windows-exporter-dashboard.json b/dashboard/windows-exporter-dashboard.json index e0371bf6..f15c5e5d 100644 --- a/dashboard/windows-exporter-dashboard.json +++ b/dashboard/windows-exporter-dashboard.json @@ -1031,7 +1031,7 @@ "transformations": [] } }, - "description": "Steady growth of goroutines points to a goroutine leak. Goroutines that stay \"not in Go\" sit in a system call, for example a collector waiting on WMI or PDH. The states need an exporter build with the Go scheduler metrics; the total line works with every build.", + "description": "Steady growth of goroutines points to a goroutine leak. Goroutines that stay \"not in Go\" sit in a system call, for example a collector waiting on WMI or PDH. The states need an exporter build with the Go scheduler metrics; the total line works with every build. Since 0.32, \"not in Go\" keeps growing even without a leak: a Go runtime bug (golang/go#82136) counts each WMI callback from a Windows thread once and never subtracts it. Use the total line to spot a leak instead.", "id": 107, "links": [], "title": "Goroutines by state",