From 798570e9aabe603dc79cca81d95b08444f8c2af6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Sat, 10 Oct 2026 16:10:55 +0200 Subject: [PATCH] dashboard: add stat rows, sections, new tabs and collector selection (#2647) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Claude Opus 5.5 Signed-off-by: Jan-Otto Kröpke --- AGENTS.md | 4 + contrib/mixin/README.md | 36 +- contrib/mixin/config.libsonnet | 25 + contrib/mixin/dashboard.jsonnet | 8 +- .../mixin/dashboards/annotations.libsonnet | 35 +- contrib/mixin/dashboards/builders.libsonnet | 116 +- contrib/mixin/dashboards/cpu.libsonnet | 374 +- contrib/mixin/dashboards/dashboards.libsonnet | 2 +- contrib/mixin/dashboards/disk.libsonnet | 693 +- contrib/mixin/dashboards/exporter.libsonnet | 1247 +- contrib/mixin/dashboards/fleet.libsonnet | 1331 +- contrib/mixin/dashboards/gpu.libsonnet | 760 +- contrib/mixin/dashboards/hyper_v.libsonnet | 670 +- contrib/mixin/dashboards/memory.libsonnet | 261 +- contrib/mixin/dashboards/network.libsonnet | 431 +- contrib/mixin/dashboards/overview.libsonnet | 933 +- contrib/mixin/dashboards/processes.libsonnet | 69 +- .../dashboards/scheduled_tasks.libsonnet | 119 + contrib/mixin/dashboards/services.libsonnet | 197 +- contrib/mixin/dashboards/smb.libsonnet | 64 + contrib/mixin/dashboards/time.libsonnet | 187 +- contrib/mixin/dashboards/updates.libsonnet | 65 + contrib/mixin/dashboards/variables.libsonnet | 109 +- .../dashboards/windows-exporter.libsonnet | 147 +- contrib/mixin/mise.toml | 3 +- contrib/mixin/tests/dashboard.test.jsonnet | 66 + dashboard/README.md | 13 +- dashboard/windows-exporter-dashboard.json | 11311 ++++++++++++++-- 28 files changed, 14550 insertions(+), 4726 deletions(-) create mode 100644 contrib/mixin/dashboards/scheduled_tasks.libsonnet create mode 100644 contrib/mixin/dashboards/smb.libsonnet create mode 100644 contrib/mixin/dashboards/updates.libsonnet create mode 100644 contrib/mixin/tests/dashboard.test.jsonnet diff --git a/AGENTS.md b/AGENTS.md index e600dc2f..82c1e244 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -168,6 +168,10 @@ Read [`contrib/mixin/README.md`](contrib/mixin/README.md) and Edit the Jsonnet/Grafonnet source under `contrib/mixin/dashboards`, including its tab modules and shared builders, and regenerate `dashboard/windows-exporter-dashboard.json`. Do not hand-edit generated JSON. +Gate every tab, row, panel and variable on the collectors it queries with +`on('')` (names from `_config.collectors`), and run +`jsonnet -J vendor tests/dashboard.test.jsonnet` to check the layout for several +collector selections. From `contrib/mixin`, install the pinned tools with `make tools`, ensure they are on `PATH`, then run `make fmt`, `make generate`, `make check-dashboards` and diff --git a/contrib/mixin/README.md b/contrib/mixin/README.md index 27b29fe4..c6634214 100644 --- a/contrib/mixin/README.md +++ b/contrib/mixin/README.md @@ -215,6 +215,12 @@ pinned in `jsonnetfile.json`: - `dashboards/builders.libsonnet` uses Grafonnet's native `apps.dashboard.v2` builders for the dashboard and layout and wraps its Prometheus query builders into the v2 panel/query-group schema. +- Each tab is a list of rows. `b.flow` places `[id, width, height]` panels left + to right and wraps at 24 columns, so rows need no hand-written coordinates. +- `b.stat` builds the current values in the first row of each per-host tab + (`b.summary`), with a sparkline of the time range behind each value. Only + threshold steps (`b.levels(warn, crit)`) add color, so green, orange and red + always mean health; informational values keep the text color. - `dashboards/styles.libsonnet` shares the visualization defaults; individual panels add their differences using `withDefaults`, `withOptions`, and `withOverrides`. Explicit nulls are preserved and arrays are replaced whole. @@ -251,7 +257,35 @@ 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 and does not read `_config`. +variables for selectors; from `_config` it reads only `collectors`. + +### Collectors + +`_config.collectors` lists the windows_exporter collectors by their exporter +names, such as `cpu`, `physical_disk`, `diskdrive`, `smb` or `update`. The +dashboard renders only the tabs, rows, panels and variables of enabled +collectors, so a tab for a collector you do not run does not appear. The +defaults match the exporter's default collectors; `time` follows `enableTime`. +The `os` collector is required, because the variables select hosts through +`windows_os_hostname`. An unknown collector name fails the build. Enable +optional collectors on top of the defaults with `collectors+:`; replacing the +object with `collectors:` enables only the listed collectors: + +```jsonnet +(import 'mixin.libsonnet') { + _config+:: { + collectors+: { diskdrive: true, process: true, scheduled_task: true, update: true }, + }, +}.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 +functions of `on(collector)`; return `null` instead of a row, a `[id, width, +height]` panel or a stat ID to leave it out. Panels that no row places are not +rendered, and tabs without rows are dropped. `tests/dashboard.test.jsonnet` +renders several collector selections and checks the layout. ## Validate diff --git a/contrib/mixin/config.libsonnet b/contrib/mixin/config.libsonnet index ee45f633..5dcb4ecb 100644 --- a/contrib/mixin/config.libsonnet +++ b/contrib/mixin/config.libsonnet @@ -11,6 +11,31 @@ // Requires the time collector with its ntp subcollector enabled. enableTime: false, + // 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. + collectors: { + cpu: true, + diskdrive: false, + gpu: false, + hyperv: false, + logical_disk: true, + memory: true, + net: true, + os: true, + physical_disk: true, + process: false, + scheduled_task: false, + service: true, + smb: false, + smbclient: false, + system: true, + tcp: false, + time: $._config.enableTime, + udp: false, + update: false, + }, + runbookURLPattern: 'https://prometheus-community.github.io/windows_exporter/runbooks/%s/', cpuHighUsageThreshold: 90, diff --git a/contrib/mixin/dashboard.jsonnet b/contrib/mixin/dashboard.jsonnet index 54ec8129..3559f19e 100644 --- a/contrib/mixin/dashboard.jsonnet +++ b/contrib/mixin/dashboard.jsonnet @@ -1,2 +1,8 @@ // Renders dashboard/windows-exporter-dashboard.json. Run with jsonnet -J vendor -S. -(import 'lib/manifest.libsonnet')((import 'mixin.libsonnet').grafanaDashboards['windows-exporter.json']) +// The sample dashboard shows every collector; mixin users select theirs with +// _config.collectors. +local mixin = (import 'mixin.libsonnet') + { + _config+:: { collectors: { [collector]: true for collector in std.objectFields(super.collectors) } }, +}; + +(import 'lib/manifest.libsonnet')(mixin.grafanaDashboards['windows-exporter.json']) diff --git a/contrib/mixin/dashboards/annotations.libsonnet b/contrib/mixin/dashboards/annotations.libsonnet index a89bfe57..d707a980 100644 --- a/contrib/mixin/dashboards/annotations.libsonnet +++ b/contrib/mixin/dashboards/annotations.libsonnet @@ -1,7 +1,8 @@ local b = import 'builders.libsonnet'; local annotation = b.dashboard.spec.annotations; -[ +// The Reboots annotation needs the system collector. +function(on) [annotation for annotation in [ annotation.withKind() + annotation.spec.withBuiltIn(true) + annotation.spec.withEnable(true) @@ -13,18 +14,20 @@ local annotation = b.dashboard.spec.annotations; + annotation.spec.withName('Annotations & Alerts') + annotation.spec.withQuery(b.dataQuery({}, 'grafana', '-- Grafana --')) , - annotation.withKind() - + annotation.spec.withEnable(true) - + annotation.spec.withHide(false) - + annotation.spec.withIconColor('orange') - + annotation.spec.withLegacyOptions({ - expr: 'windows_system_boot_time_timestamp{job=~"$job", instance="$instance"} * 1000 > $__from < $__to', - step: '1m', - tagKeys: 'instance', - textFormat: '', - titleFormat: 'Reboot', - useValueForTime: 'on', - }) - + annotation.spec.withName('Reboots') - + annotation.spec.withQuery(b.dataQuery({}, 'prometheus', '${datasource}')), -] + if on('system') then ( + annotation.withKind() + + annotation.spec.withEnable(true) + + annotation.spec.withHide(false) + + annotation.spec.withIconColor('orange') + + annotation.spec.withLegacyOptions({ + expr: 'windows_system_boot_time_timestamp{job=~"$job", instance="$instance"} * 1000 > $__from < $__to', + step: '1m', + tagKeys: 'instance', + textFormat: '', + titleFormat: 'Reboot', + useValueForTime: 'on', + }) + + annotation.spec.withName('Reboots') + + annotation.spec.withQuery(b.dataQuery({}, 'prometheus', '${datasource}')) + ), +] if annotation != null] diff --git a/contrib/mixin/dashboards/builders.libsonnet b/contrib/mixin/dashboards/builders.libsonnet index 01b21a41..8d630150 100644 --- a/contrib/mixin/dashboards/builders.libsonnet +++ b/contrib/mixin/dashboards/builders.libsonnet @@ -56,6 +56,71 @@ local merge(base, patch) = base + { withOverrides(value): { spec+: { vizConfig+: { spec+: { fieldConfig+: { overrides: value } } } } }, }, + // Green below warn, orange from warn and red from crit. + levels(warn, crit): [ + { color: 'green', value: null }, + { color: 'orange', value: warn }, + { color: 'red', value: crit }, + ], + + // Current value with the time range drawn as a sparkline behind it. Only + // threshold steps add color, so green, orange and red always mean health; + // informational values stay in the text color. + stat(id, title, description, expr, unit='short', steps=null): + $.panel.new(id, title, 'stat') + + $.panel.withDescription(description) + + $.panel.withQueries([$.query.new(expr)]) + + $.panel.withQueryOptions({ maxDataPoints: 100 }) + + $.panel.withDefaults( + { unit: unit } + + if steps == null + then { color: { fixedColor: 'text', mode: 'fixed' } } + else { thresholds: { steps: steps } } + ) + + $.panel.withOptions({ graphMode: 'area' }), + + // Time series of [expr, legend] queries. Series whose name matches below are + // drawn below the axis, for example reads against writes. + graph(id, title, description, unit, queries, below=null): + $.panel.new(id, title, 'timeseries') + + $.panel.withDescription(description) + + $.panel.withQueries([ + $.query.new(queries[i][0], std.char(65 + i)) + $.query.withLegendFormat(queries[i][1]) + for i in std.range(0, std.length(queries) - 1) + ]) + + $.panel.withDefaults({ unit: unit } + if below == null then { min: 0 } else {}) + + $.panel.withOverrides(if below == null then [] else [{ + matcher: { id: 'byRegexp', options: below }, + properties: [{ id: 'custom.transform', value: 'negative-Y' }], + }]), + + // Table of instant queries joined by a label. columns lists [field, title] + // pairs in display order; the other fields are hidden. + joinedTable(id, title, description, byField, queries, columns, overrides=[]): + local refIds = [std.char(65 + i) for i in std.range(0, std.length(queries) - 1)]; + local shown = [column[0] for column in columns]; + $.panel.new(id, title, 'table') + + $.panel.withDescription(description) + + $.panel.withQueries([$.query.new(queries[i], refIds[i]) + $.query.withInstant() + $.query.withFormat('table') for i in std.range(0, std.length(queries) - 1)]) + + $.panel.withTransformations([ + { group: 'joinByField', kind: 'Transformation', spec: { options: { byField: byField, mode: 'outer' } } }, + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { [name]: true for name in ['Time'] + ['Time ' + i for i in std.range(1, std.length(queries))] + ['Value #' + refId for refId in refIds] if !std.member(shown, name) }, + includeByName: {}, + indexByName: { [columns[i][0]]: i for i in std.range(0, std.length(columns) - 1) }, + renameByName: { [column[0]]: column[1] for column in columns }, + }, + }, + }, + ]) + + $.panel.withDefaults({ unit: 'short' }) + + $.panel.withOptions({ sortBy: [{ desc: false, displayName: columns[0][1] }] }) + + $.panel.withOverrides(overrides), + dataQuery(spec, group='prometheus', datasource='${datasource}'): { kind: 'DataQuery', group: group, @@ -90,7 +155,12 @@ local merge(base, patch) = base + { }, grid(items): (grid.withKind() + grid.spec.withItems(items)).spec.layout, - rows(rows_): (rows.withKind() + rows.spec.withRows(rows_)).spec.layout, + // Rows of disabled collectors are null, and rows without panels are dropped. + rows(rows_): (rows.withKind() + rows.spec.withRows([ + row_ + for row_ in rows_ + if row_ != null && std.length(row_.spec.layout.spec.items) > 0 + ])).spec.layout, tabs(tabs_): (tabs.withKind() + tabs.spec.withTabs(tabs_)).spec.layout, place(id, x, y, width, height): item.withKind() @@ -99,9 +169,45 @@ local merge(base, patch) = base + { + item.spec.withY(y) + item.spec.withWidth(width) + item.spec.withHeight(height), + // Places stats side by side across the full row. When the stat count does not + // divide the 24 columns, the first stats are one column wider. + statRow(ids, y=0, height=4): + local present = [id for id in ids if id != null]; + local n = std.length(present); + local width(i) = std.floor(24 / n) + (if i < 24 % n then 1 else 0); + local x(i) = std.foldl(function(sum, j) sum + width(j), std.range(0, i - 1), 0); + [$.place(present[i], x(i), y, width(i), height) for i in std.range(0, n - 1)], + // Grid of [id, width, height] panels placed left to right, wrapping at 24 + // columns. Panels of disabled collectors are null and take no space. + flow(panels_): + local panels = [panel for panel in panels_ if panel != null]; + local step(acc, panel) = + local wrap = acc.x + panel[1] > 24; + local x = if wrap then 0 else acc.x; + local y = if wrap then acc.y + acc.height else acc.y; + { + x: x + panel[1], + y: y, + height: if wrap then panel[2] else std.max(acc.height, panel[2]), + items: acc.items + [$.place(panel[0], x, y, panel[1], panel[2])], + }; + $.grid(std.foldl(step, panels, { x: 0, y: 0, height: 0, items: [] }).items), + // First row of each tab: the stat row of current values. + summary(ids): $.row('Summary', $.grid($.statRow(ids))), row(title, layout): row.withKind() + row.withSpec({ title: title, collapse: false, layout: layout }), - tab(title, layout, panels): { - elements: { ['panel-' + panel.spec.id]: panel for panel in panels }, - layout: tab.withKind() + tab.withSpec({ title: title, layout: layout }), - }, + // Only panels placed in the layout become dashboard elements, so a layout + // without the rows of disabled collectors also drops their panels. + tab(title, layout, panels): + local placed(layout_) = + if layout_.kind == 'RowsLayout' + then std.flattenArrays([placed(row_.spec.layout) for row_ in layout_.spec.rows]) + else [item_.spec.element.name for item_ in layout_.spec.items]; + local names = std.set(placed(layout)); + local elements = { ['panel-' + panel.spec.id]: panel for panel in panels }; + assert std.length(std.setDiff(names, std.objectFields(elements))) == 0 : title + ' places undefined panels: ' + std.join(', ', std.setDiff(names, std.objectFields(elements))); + { + elements: { [name]: elements[name] for name in names }, + layout: tab.withKind() + tab.withSpec({ title: title, layout: layout }), + empty: std.length(names) == 0, + }, } diff --git a/contrib/mixin/dashboards/cpu.libsonnet b/contrib/mixin/dashboards/cpu.libsonnet index 5e801888..a4efb5d9 100644 --- a/contrib/mixin/dashboards/cpu.libsonnet +++ b/contrib/mixin/dashboards/cpu.libsonnet @@ -1,191 +1,203 @@ local b = import 'builders.libsonnet'; +local host = '{job=~"$job", instance="$instance"}'; +local cores = 'scalar(max(windows_cpu_logical_processor' + host + '))'; +local mode(m) = 'sum(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="' + m + '"}[$__rate_interval])) / ' + cores; -b.tab( - 'CPU', - b.grid([ - b.place(24, 0, 0, 12, 10), - b.place(25, 12, 0, 12, 10), - b.place(26, 0, 10, 8, 8), - b.place(27, 8, 10, 8, 8), - b.place(28, 16, 10, 8, 8), - b.place(29, 0, 18, 12, 8), - b.place(30, 12, 18, 12, 8), - ]), - [ - b.panel.new(24, 'CPU utilization by mode', 'timeseries') - + b.panel.withDescription('Share of total CPU time across all logical processors.') - + b.panel.withQueries([ - b.query.new('sum by (mode) (rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode!="idle"}[$__rate_interval])) / scalar(count(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}))', 'A') - + b.query.withLegendFormat('{{mode}}'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - max: 1, - min: 0, - }), - - b.panel.new(25, 'CPU utilization per core', 'state-timeline') - + b.panel.withDescription('Busy time of each logical processor, labelled processor group,core. Green is idle, red is fully busy.') - + b.panel.withQueries([ - b.query.new('label_replace(clamp(1 - rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 0, 1), "core", "$1,0$2", "core", "(\\\\d+),(\\\\d)")', 'A') - + b.query.withLegendFormat('{{core}}'), - ]) - + b.panel.withDefaults({ - color: { - mode: 'continuous-GrYlRd', - }, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - ], - }, - unit: 'percentunit', - }), - - b.panel.new(26, 'Processor queue length', 'timeseries') - + b.panel.withDescription('Threads that are ready to run but waiting for a CPU. A sustained value above 2 per core indicates CPU contention.') - + b.panel.withQueries([ - b.query.new('windows_system_processor_queue_length{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('queue length'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'short', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - b.panel.new(27, 'Context switches and interrupts', 'timeseries') - + b.panel.withDescription('Context switches, hardware interrupts and deferred procedure calls per second across the host. High rates can reflect scheduling or driver activity; correlate changes with CPU usage and workload rather than assuming they are faults.') - + b.panel.withQueries([ - b.query.new('rate(windows_system_context_switches_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('context switches'), - b.query.new('sum(rate(windows_cpu_interrupts_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('interrupts'), - b.query.new('sum(rate(windows_cpu_dpcs_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') - + b.query.withLegendFormat('DPCs'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'ops', - }), - - b.panel.new(28, 'Processes and threads', 'timeseries') - + b.panel.withDescription('Current process and thread counts on the host. Sustained growth can help identify runaway process creation or thread leaks; thread counts use the right-hand axis.') - + b.panel.withQueries([ - b.query.new('windows_system_processes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('processes'), - b.query.new('windows_system_threads{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('threads'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'short', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'threads', - }, - properties: [ - { - id: 'custom.axisPlacement', - value: 'right', - }, - ], - }, +function(on) + b.tab( + 'CPU', + b.rows([ + if on('cpu') then b.summary([160, 161, 162, if on('system') then 163, if on('system') then 164, 165]), + if on('cpu') then b.row('Utilization', b.flow([[24, 12, 10], [25, 12, 10]])), + if on('cpu') && on('system') then b.row('Scheduling', b.flow([[26, 8, 8], [27, 8, 8], [28, 8, 8]])), + if on('cpu') then b.row('System calls and frequency', b.flow([if on('system') then [29, 12, 8], [30, 12, 8]])), ]), + [ + b.stat(160, 'CPU busy', 'Non-idle CPU time averaged across logical processors.', '1 - avg(clamp_max(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 1))', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(161, 'User', 'CPU time spent in user mode, as a share of all logical processors.', mode('user'), 'percentunit') + + b.panel.withDefaults({ decimals: 1, min: 0 }), + b.stat(162, 'Privileged', 'CPU time spent in kernel mode, excluding interrupts and DPCs, as a share of all logical processors.', mode('privileged'), 'percentunit') + + b.panel.withDefaults({ decimals: 1, min: 0 }), + b.stat(163, 'Queue per CPU', 'Threads waiting for a CPU per logical processor. A sustained value above 2 indicates CPU contention.', 'windows_system_processor_queue_length' + host + ' / ' + cores, 'short', steps=b.levels(1, 2)) + + b.panel.withDefaults({ decimals: 2, min: 0 }), + b.stat(164, 'Ctx switches', 'Context switches per second across the host.', 'rate(windows_system_context_switches_total' + host + '[$__rate_interval])', 'ops'), + b.stat(165, 'Frequency', 'Average effective frequency across logical processors. Values above the nominal frequency mean turbo boost.', 'avg(1e4 * windows_cpu_core_frequency_mhz' + host + ' * rate(windows_cpu_processor_performance_total' + host + '[$__rate_interval]) / rate(windows_cpu_processor_mperf_total' + host + '[$__rate_interval]))', 'hertz'), - b.panel.new(29, 'System calls and exceptions', 'timeseries') - + b.panel.withDescription('System calls and exception dispatches per second. Exception dispatches include handled exceptions and do not directly count application crashes; compare with application logs. Exceptions use the right-hand axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_system_system_calls_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('system calls'), - b.query.new('rate(windows_system_exception_dispatches_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('exception dispatches'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'ops', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'exception dispatches', - }, - properties: [ - { - id: 'custom.axisPlacement', - value: 'right', + b.panel.new(24, 'CPU utilization by mode', 'timeseries') + + b.panel.withDescription('Share of total CPU time across all logical processors.') + + b.panel.withQueries([ + b.query.new('sum by (mode) (rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode!="idle"}[$__rate_interval])) / scalar(count(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}))', 'A') + + b.query.withLegendFormat('{{mode}}'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', }, - ], - }, - ]), - - b.panel.new(30, 'CPU frequency', 'timeseries') - + b.panel.withDescription('Effective frequency from the APERF/MPERF counters, averaged and maximum across logical processors, against the nominal frequency. Values above nominal mean turbo boost.') - + b.panel.withQueries([ - b.query.new('avg(1e4 * windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"} * rate(windows_cpu_processor_performance_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_cpu_processor_mperf_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('average'), - b.query.new('max(1e4 * windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"} * rate(windows_cpu_processor_performance_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_cpu_processor_mperf_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('maximum'), - b.query.new('avg(windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"}) * 1e6', 'C') - + b.query.withLegendFormat('nominal'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'hertz', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'nominal', }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'text', - mode: 'fixed', + max: 1, + min: 0, + }), + + b.panel.new(25, 'CPU utilization per core', 'state-timeline') + + b.panel.withDescription('Busy time of each logical processor, labelled processor group,core. Green is idle, red is fully busy.') + + b.panel.withQueries([ + b.query.new('label_replace(clamp(1 - rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 0, 1), "core", "$1,0$2", "core", "(\\\\d+),(\\\\d)")', 'A') + + b.query.withLegendFormat('{{core}}'), + ]) + + b.panel.withDefaults({ + color: { + mode: 'continuous-GrYlRd', + }, + thresholds: { + steps: [ + { + color: 'green', + value: null, }, + ], + }, + unit: 'percentunit', + }), + + b.panel.new(26, 'Processor queue length', 'timeseries') + + b.panel.withDescription('Threads that are ready to run but waiting for a CPU. A sustained value above 2 per core indicates CPU contention.') + + b.panel.withQueries([ + b.query.new('windows_system_processor_queue_length{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('queue length'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'short', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + + b.panel.new(27, 'Context switches and interrupts', 'timeseries') + + b.panel.withDescription('Context switches, hardware interrupts and deferred procedure calls per second across the host. High rates can reflect scheduling or driver activity; correlate changes with CPU usage and workload rather than assuming they are faults.') + + b.panel.withQueries([ + b.query.new('rate(windows_system_context_switches_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('context switches'), + b.query.new('sum(rate(windows_cpu_interrupts_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('interrupts'), + b.query.new('sum(rate(windows_cpu_dpcs_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') + + b.query.withLegendFormat('DPCs'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'ops', + }), + + b.panel.new(28, 'Processes and threads', 'timeseries') + + b.panel.withDescription('Current process and thread counts on the host. Sustained growth can help identify runaway process creation or thread leaks; thread counts use the right-hand axis.') + + b.panel.withQueries([ + b.query.new('windows_system_processes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('processes'), + b.query.new('windows_system_threads{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('threads'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'short', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'threads', }, - { - id: 'custom.fillOpacity', - value: 0, - }, - { - id: 'custom.lineStyle', - value: { - dash: [ - 10, - 10, - ], - fill: 'dash', + properties: [ + { + id: 'custom.axisPlacement', + value: 'right', }, + ], + }, + ]), + + b.panel.new(29, 'System calls and exceptions', 'timeseries') + + b.panel.withDescription('System calls and exception dispatches per second. Exception dispatches include handled exceptions and do not directly count application crashes; compare with application logs. Exceptions use the right-hand axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_system_system_calls_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('system calls'), + b.query.new('rate(windows_system_exception_dispatches_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('exception dispatches'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'ops', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'exception dispatches', }, - ], - }, - ]), - ] -) + properties: [ + { + id: 'custom.axisPlacement', + value: 'right', + }, + ], + }, + ]), + + b.panel.new(30, 'CPU frequency', 'timeseries') + + b.panel.withDescription('Effective frequency from the APERF/MPERF counters, averaged and maximum across logical processors, against the nominal frequency. Values above nominal mean turbo boost.') + + b.panel.withQueries([ + b.query.new('avg(1e4 * windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"} * rate(windows_cpu_processor_performance_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_cpu_processor_mperf_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('average'), + b.query.new('max(1e4 * windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"} * rate(windows_cpu_processor_performance_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_cpu_processor_mperf_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('maximum'), + b.query.new('avg(windows_cpu_core_frequency_mhz{job=~"$job", instance="$instance"}) * 1e6', 'C') + + b.query.withLegendFormat('nominal'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'hertz', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'nominal', + }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'text', + mode: 'fixed', + }, + }, + { + id: 'custom.fillOpacity', + value: 0, + }, + { + id: 'custom.lineStyle', + value: { + dash: [ + 10, + 10, + ], + fill: 'dash', + }, + }, + ], + }, + ]), + ] + ) diff --git a/contrib/mixin/dashboards/dashboards.libsonnet b/contrib/mixin/dashboards/dashboards.libsonnet index 8fa9af30..b91eddcd 100644 --- a/contrib/mixin/dashboards/dashboards.libsonnet +++ b/contrib/mixin/dashboards/dashboards.libsonnet @@ -1,5 +1,5 @@ { grafanaDashboards+:: { - 'windows-exporter.json': import 'windows-exporter.libsonnet', + 'windows-exporter.json': (import 'windows-exporter.libsonnet')($._config), }, } diff --git a/contrib/mixin/dashboards/disk.libsonnet b/contrib/mixin/dashboards/disk.libsonnet index 47024d76..52c5c39a 100644 --- a/contrib/mixin/dashboards/disk.libsonnet +++ b/contrib/mixin/dashboards/disk.libsonnet @@ -1,321 +1,400 @@ local b = import 'builders.libsonnet'; +local metric(name) = 'windows_logical_disk_' + name + '{job=~"$job", instance="$instance", volume=~"$volume"}'; +local sumRate(name) = 'sum(rate(' + metric(name) + '[$__rate_interval]))'; +local physical(name) = 'windows_physical_disk_' + name + '{job=~"$job", instance="$instance"}'; +local physicalRate(name) = 'rate(' + physical(name) + '[$__rate_interval])'; +// diskdrive names drives PHYSICALDRIVE; physical_disk and logical_disk use as disk. +local drive(name, labels='') = 'label_replace(windows_diskdrive_' + name + '{job=~"$job", instance="$instance"' + labels + '}, "disk", "$1", "name", "PHYSICALDRIVE(\\\\d+)")'; +// Labels physical disk series with the drive model when diskdrive is enabled. +local physicalByDisk(on, expr) = + if on('diskdrive') + then '(' + expr + ') * on (disk) group_left (model) max by (disk, model) (' + drive('info') + ') or on (disk) (' + expr + ')' + else expr; +local physicalGraph(on, id, title, description, queries, unit) = + b.panel.new(id, title, 'timeseries') + + b.panel.withDescription(description + ' Requires the physical_disk collector; the diskdrive collector adds drive models.') + + b.panel.withQueries([ + b.query.new(physicalByDisk(on, query[1]), query[0]) + + b.query.withLegendFormat((if on('diskdrive') then '{{disk}} {{model}}' else 'disk {{disk}}') + query[2]) + for query in queries + ]) + + b.panel.withDefaults({ unit: unit } + if std.length(queries) > 1 then {} else { min: 0 }) + + b.panel.withOverrides(if std.length(queries) > 1 then [{ + matcher: { id: 'byRegexp', options: '.* read$' }, + properties: [{ id: 'custom.transform', value: 'negative-Y' }], + }] else []); -b.tab( - 'Disk', - b.grid([ - b.place(37, 0, 0, 8, 8), - b.place(38, 8, 0, 8, 8), - b.place(39, 16, 0, 8, 8), - b.place(40, 0, 8, 12, 8), - b.place(41, 12, 8, 12, 8), - b.place(42, 0, 16, 12, 8), - b.place(43, 12, 16, 12, 8), - ]), - [ - b.panel.new(37, 'Volumes', 'table') - + b.panel.withDescription('Size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.') - + b.panel.withQueries([ - b.query.new('windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'B') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'C') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'joinByField', - kind: 'Transformation', - spec: { - options: { - byField: 'volume', - mode: 'outer', - }, - }, - }, - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - 'Time 2': true, - 'Time 3': true, - __name__: true, - instance: true, - 'instance 1': true, - 'instance 2': true, - 'instance 3': true, - job: true, - 'job 1': true, - 'job 2': true, - 'job 3': true, - port: true, - 'port 1': true, - 'port 2': true, - 'port 3': true, - }, - includeByName: {}, - indexByName: { - 'Value #A': 1, - 'Value #B': 2, - 'Value #C': 3, - volume: 0, - }, - renameByName: { - 'Value #A': 'Size', - 'Value #B': 'Free', - 'Value #C': 'Used', - volume: 'Volume', - }, - }, - }, - }, - ]) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'Value #A', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #B', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #C', - }, - properties: [ - { - id: 'unit', - value: 'percent', - }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', - }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', - }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, +function(on) + b.tab( + 'Disk', + b.rows([ + b.summary([ + if on('logical_disk') then 172, + if on('physical_disk') then 200 else if on('logical_disk') then 173, + if on('logical_disk') then 174, + if on('logical_disk') then 175, + if on('logical_disk') then 176, + if on('logical_disk') then 177, + ]), + if on('logical_disk') then b.row('Volumes', b.flow([[37, 24, 7], [38, 12, 8], [39, 12, 8]])), + if on('logical_disk') then b.row('Volume I/O', b.flow([[40, 12, 8], [41, 12, 8], [42, 12, 8], [43, 12, 8]])), + if on('diskdrive') then b.row('Drives', b.flow([[201, 4, 6], [202, 20, 6]])), + if on('physical_disk') then b.row('Physical disks', b.flow([[203, 12, 8], [204, 12, 8], [205, 12, 8], [206, 12, 8], [207, 12, 8], [208, 12, 8]])), ]), + [ + b.stat(172, 'Fullest volume', 'Used space of the fullest selected volume. Free-space counters can lag by 10 to 15 minutes.', 'max(1 - ' + metric('free_bytes') + ' / ' + metric('size_bytes') + ')', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(173, 'Busy time', 'Busy time of the busiest selected volume.', 'max(1 - clamp_max(rate(' + metric('idle_seconds_total') + '[$__rate_interval]), 1))', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(174, 'Read', 'Bytes read per second, summed over the selected volumes.', sumRate('read_bytes_total'), 'Bps'), + b.stat(175, 'Write', 'Bytes written per second, summed over the selected volumes.', sumRate('write_bytes_total'), 'Bps'), + b.stat(176, 'IOPS', 'Read and write operations per second, summed over the selected volumes.', sumRate('reads_total') + ' + ' + sumRate('writes_total'), 'iops'), + b.stat(177, 'Latency', 'Average time per read or write operation over the selected volumes. 0 when there is no I/O.', '((' + sumRate('read_seconds_total') + ' + ' + sumRate('write_seconds_total') + ') / ((' + sumRate('reads_total') + ' + ' + sumRate('writes_total') + ') > 0)) or (0 * ' + sumRate('reads_total') + ')', 's', steps=b.levels(0.02, 0.05)), - b.panel.new(38, 'Volume usage', 'timeseries') - + b.panel.withDescription('Used space as a percentage of each selected logical volume. Sustained growth toward full capacity can prevent writes and disrupt applications; Windows free-space counters can lag by 10 to 15 minutes.') - + b.panel.withQueries([ - b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'A') - + b.query.withLegendFormat('{{volume}}'), - ]) - + b.panel.withDefaults({ - custom: { - thresholdsStyle: { - mode: 'dashed', + b.panel.new(37, 'Volumes', 'table') + + b.panel.withDescription('Label, physical disk number, file system, size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.') + + b.panel.withQueries([ + b.query.new('windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'B') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'C') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('max by (volume, volume_name, disk, filesystem) (windows_logical_disk_info{job=~"$job", instance="$instance", volume=~"$volume"})', 'D') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ + { + group: 'joinByField', + kind: 'Transformation', + spec: { + options: { + byField: 'volume', + mode: 'outer', + }, + }, }, - }, - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + 'Time 2': true, + 'Time 3': true, + 'Time 4': true, + 'Value #D': true, + __name__: true, + instance: true, + 'instance 1': true, + 'instance 2': true, + 'instance 3': true, + job: true, + 'job 1': true, + 'job 2': true, + 'job 3': true, + port: true, + 'port 1': true, + 'port 2': true, + 'port 3': true, + }, + includeByName: {}, + indexByName: { + 'Value #A': 4, + 'Value #B': 5, + 'Value #C': 6, + disk: 2, + filesystem: 3, + volume: 0, + volume_name: 1, + }, + renameByName: { + 'Value #A': 'Size', + 'Value #B': 'Free', + 'Value #C': 'Used', + disk: 'Disk', + filesystem: 'File system', + volume: 'Volume', + volume_name: 'Label', + }, + }, }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - legend: { - calcs: [ - 'min', - 'max', - 'lastNotNull', - ], - }, - }), - - b.panel.new(39, 'Volume busy time', 'timeseries') - + b.panel.withDescription('Share of time the volume was servicing requests (1 - idle time).') - + b.panel.withQueries([ - b.query.new('1 - clamp_max(rate(windows_logical_disk_idle_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]), 1)', 'A') - + b.query.withLegendFormat('{{volume}}'), - ]) - + b.panel.withDefaults({ - max: 1, - min: 0, - }), - - b.panel.new(40, 'Disk throughput', 'timeseries') - + b.panel.withDescription('Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_logical_disk_write_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{volume}} write'), - b.query.new('rate(windows_logical_disk_read_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{volume}} read'), - ]) - + b.panel.withDefaults({ - unit: 'Bps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + ]) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'Value #A', }, - ], - }, - ]), - - b.panel.new(41, 'Disk IOPS', 'timeseries') - + b.panel.withDescription('Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_logical_disk_writes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{volume}} write'), - b.query.new('rate(windows_logical_disk_reads_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{volume}} read'), - ]) - + b.panel.withDefaults({ - unit: 'iops', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + { + matcher: { + id: 'byName', + options: 'Value #B', }, - ], - }, - ]), - - b.panel.new(42, 'Disk latency', 'timeseries') - + b.panel.withDescription('Average time per read and write operation. Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_logical_disk_write_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]) / rate(windows_logical_disk_writes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{volume}} write'), - b.query.new('rate(windows_logical_disk_read_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]) / rate(windows_logical_disk_reads_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{volume}} read'), - ]) - + b.panel.withDefaults({ - unit: 's', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + { + matcher: { + id: 'byName', + options: 'Value #C', }, - ], - }, - ]), - - b.panel.new(43, 'Disk queue length', 'timeseries') - + b.panel.withDescription('Average number of read and write requests queued for the volume. Reads are drawn below the axis. A queue that stays high while latency rises indicates a disk bottleneck.') - + b.panel.withQueries([ - b.query.new('rate(windows_logical_disk_write_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{volume}} write'), - b.query.new('rate(windows_logical_disk_read_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{volume}} read'), - ]) - + b.panel.withDefaults({ - unit: 'short', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + ]), + + b.panel.new(38, 'Volume usage', 'timeseries') + + b.panel.withDescription('Used space as a percentage of each selected logical volume. Sustained growth toward full capacity can prevent writes and disrupt applications; Windows free-space counters can lag by 10 to 15 minutes.') + + b.panel.withQueries([ + b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'A') + + b.query.withLegendFormat('{{volume}}'), + ]) + + b.panel.withDefaults({ + custom: { + thresholdsStyle: { + mode: 'dashed', }, - ], - }, - ]), - ] -) + }, + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + legend: { + calcs: [ + 'min', + 'max', + 'lastNotNull', + ], + }, + }), + + b.panel.new(39, 'Volume busy time', 'timeseries') + + b.panel.withDescription('Share of time the volume was servicing requests (1 - idle time).') + + b.panel.withQueries([ + b.query.new('1 - clamp_max(rate(windows_logical_disk_idle_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]), 1)', 'A') + + b.query.withLegendFormat('{{volume}}'), + ]) + + b.panel.withDefaults({ + max: 1, + min: 0, + }), + + b.panel.new(40, 'Volume throughput', 'timeseries') + + b.panel.withDescription('Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_logical_disk_write_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{volume}} write'), + b.query.new('rate(windows_logical_disk_read_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{volume}} read'), + ]) + + b.panel.withDefaults({ + unit: 'Bps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.panel.new(41, 'Volume IOPS', 'timeseries') + + b.panel.withDescription('Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_logical_disk_writes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{volume}} write'), + b.query.new('rate(windows_logical_disk_reads_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{volume}} read'), + ]) + + b.panel.withDefaults({ + unit: 'iops', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.panel.new(42, 'Volume latency', 'timeseries') + + b.panel.withDescription('Average time per read and write operation. Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_logical_disk_write_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]) / rate(windows_logical_disk_writes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{volume}} write'), + b.query.new('rate(windows_logical_disk_read_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]) / rate(windows_logical_disk_reads_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{volume}} read'), + ]) + + b.panel.withDefaults({ + unit: 's', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.panel.new(43, 'Volume queue length', 'timeseries') + + b.panel.withDescription('Average number of read and write requests queued for the volume. Reads are drawn below the axis. A queue that stays high while latency rises indicates a disk bottleneck.') + + b.panel.withQueries([ + b.query.new('rate(windows_logical_disk_write_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{volume}} write'), + b.query.new('rate(windows_logical_disk_read_seconds_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{volume}} read'), + ]) + + b.panel.withDefaults({ + unit: 'short', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.stat(200, 'Busiest disk', 'Busy time of the busiest physical disk. Requires the physical_disk collector.', 'max(1 - clamp_max(' + physicalRate('idle_seconds_total') + ', 1))', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(201, 'Drives not OK', 'Drives whose operational status is not OK. Requires the diskdrive collector.', 'count(' + drive('status', ', status!="OK"') + ' == 1) or (0 * count(' + drive('info') + '))', steps=[{ color: 'green', value: null }, { color: 'red', value: 1 }]), + + b.joinedTable(202, 'Drives', 'Model, size, partitions and operational status of each drive. Requires the diskdrive collector.', 'disk', [ + 'max by (disk, model) (' + drive('info') + ')', + 'max by (disk) (' + drive('size') + ')', + 'max by (disk) (' + drive('partitions') + ')', + 'max by (disk, status) (' + drive('status') + ' == 1)', + ], [['disk', 'Disk'], ['model', 'Model'], ['Value #B', 'Size'], ['Value #C', 'Partitions'], ['status', 'Status']], [ + { matcher: { id: 'byName', options: 'Size' }, properties: [{ id: 'unit', value: 'bytes' }] }, + { + matcher: { id: 'byName', options: 'Status' }, + properties: [ + { id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }, + { id: 'mappings', value: [{ type: 'value', options: { OK: { color: 'green', index: 0 } } }] }, + { id: 'custom.cellOptions', value: { type: 'color-text' } }, + ], + }, + ]), + + physicalGraph(on, 203, 'Disk busy time', 'Share of time each physical disk was servicing requests (1 - idle time).', [['A', '1 - clamp_max(' + physicalRate('idle_seconds_total') + ', 1)', '']], 'percentunit') + + b.panel.withDefaults({ max: 1 }), + physicalGraph(on, 204, 'Disk throughput', 'Bytes read and written per second by each physical disk. Reads are drawn below the axis.', [['A', physicalRate('write_bytes_total'), ' write'], ['B', physicalRate('read_bytes_total'), ' read']], 'Bps'), + physicalGraph(on, 205, 'Disk IOPS', 'Read and write operations per second by each physical disk. Reads are drawn below the axis.', [['A', physicalRate('writes_total'), ' write'], ['B', physicalRate('reads_total'), ' read']], 'iops'), + physicalGraph(on, 206, 'Disk latency', 'Average time per read and write operation of each physical disk. Reads are drawn below the axis.', [['A', physicalRate('write_latency_seconds_total') + ' / (' + physicalRate('writes_total') + ' > 0)', ' write'], ['B', physicalRate('read_latency_seconds_total') + ' / (' + physicalRate('reads_total') + ' > 0)', ' read']], 's'), + physicalGraph(on, 207, 'Disk queue length', 'Requests outstanding on each physical disk at the time of the scrape. A queue that stays high while latency rises indicates a disk bottleneck.', [['A', physical('requests_queued'), '']], 'short'), + physicalGraph(on, 208, 'Split I/O', 'I/O requests per second that Windows split into multiple requests, because of a fragmented volume or a request too large for a single I/O.', [['A', physicalRate('split_ios_total'), '']], 'iops'), + ] + ) diff --git a/contrib/mixin/dashboards/exporter.libsonnet b/contrib/mixin/dashboards/exporter.libsonnet index e664749e..3b4169c7 100644 --- a/contrib/mixin/dashboards/exporter.libsonnet +++ b/contrib/mixin/dashboards/exporter.libsonnet @@ -1,669 +1,648 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Exporter', - b.rows([ - b.row('Scrape', b.grid([ - b.place(90, 0, 0, 4, 4), - b.place(91, 4, 0, 4, 4), - b.place(92, 8, 0, 4, 4), - b.place(93, 12, 0, 4, 4), - b.place(94, 16, 0, 4, 4), - b.place(95, 20, 0, 4, 4), - b.place(96, 0, 4, 12, 8), - b.place(97, 12, 4, 12, 8), - ])), - b.row('Collectors', b.grid([ - b.place(99, 0, 0, 8, 8), - b.place(100, 8, 0, 16, 8), - b.place(101, 0, 8, 12, 9), - b.place(102, 12, 8, 12, 9), - ])), - b.row('Process and Go runtime', b.grid([ - b.place(104, 0, 0, 8, 8), - b.place(105, 8, 0, 8, 8), - b.place(106, 16, 0, 8, 8), - b.place(107, 0, 8, 8, 8), - b.place(108, 8, 8, 8, 8), - b.place(109, 16, 8, 8, 8), - b.place(110, 0, 16, 12, 8), - b.place(111, 12, 16, 12, 8), - ])), - ]), - [ - b.panel.new(90, 'Scrape status', 'stat') - + b.panel.withDescription('Result of the last scrape by Prometheus.') - + b.panel.withQueries([ - b.query.new('up{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - mappings: [ - { - options: { - '0': { - index: 0, - text: 'down', - }, - '1': { - index: 1, - text: 'up', - }, - }, - type: 'value', - }, - ], - thresholds: { - steps: [ - { - color: 'red', - value: null, - }, - { - color: 'green', - value: 1, - }, - ], - }, - unit: '', - }), - - b.panel.new(91, 'Exporter version', 'stat') - + b.panel.withDescription('Builds without a version show the first seven characters of the Git revision.') - + b.panel.withQueries([ - b.query.new('windows_exporter_build_info{job=~"$job", instance="$instance", version!=""} or on (instance) label_replace(windows_exporter_build_info{job=~"$job", instance="$instance"}, "version", "$1", "revision", "(.{7}).*")', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withDefaults({ - unit: '', - }) - + b.panel.withOptions({ - colorMode: 'none', - reduceOptions: { - fields: '/^version$/', - }, - textMode: 'value', - }), - - b.panel.new(92, 'Exporter uptime', 'stat') - + b.panel.withDescription('Time since the exporter process started. A short uptime on a host with a long uptime means the exporter restarted.') - + b.panel.withQueries([ - b.query.new('time() - process_start_time_seconds{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'orange', - value: null, - }, - { - color: 'text', - value: 3600, - }, - ], - }, - unit: 'dtdurations', - }), - - b.panel.new(93, 'Failed collectors', 'stat') - + b.panel.withDescription('Number of collectors that failed on the latest scrape, including timeouts. The graph shows the count over the selected time range.') - + b.panel.withQueries([ - b.query.new('count(windows_exporter_collector_success{job=~"$job", instance="$instance"} == 0) or vector(0)', 'A'), - ]) - + b.panel.withDefaults({ - decimals: 0, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'red', - value: 1, - }, - ], - }, - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(94, 'Timed-out collectors', 'stat') - + b.panel.withDescription('Number of collectors that timed out on the latest scrape. The graph shows the count over the selected time range.') - + b.panel.withQueries([ - b.query.new('count(windows_exporter_collector_timeout{job=~"$job", instance="$instance"} == 1) or vector(0)', 'A'), - ]) - + b.panel.withDefaults({ - decimals: 0, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'red', - value: 1, - }, - ], - }, - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(95, 'Samples per scrape', 'stat') - + b.panel.withDescription('Number of metric samples returned before Prometheus metric relabeling. Changes can reflect collector configuration or changing device/process counts; unexpected drops should be checked against scrape and collector success.') - + b.panel.withQueries([ - b.query.new('scrape_samples_scraped{job=~"$job", instance="$instance"}', 'A'), - ]) - + b.panel.withDefaults({ - unit: 'short', - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(96, 'Scrape duration', 'timeseries') - + b.panel.withDescription('Scrape duration measured by Prometheus and by the exporter. It must stay below the scrape timeout of the job.') - + b.panel.withQueries([ - b.query.new('scrape_duration_seconds{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('Prometheus'), - b.query.new('windows_exporter_scrape_duration_seconds{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('exporter'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 's', - }), - - b.panel.new(97, 'HTTP requests to /metrics', 'timeseries') - + b.panel.withDescription('Scrape requests by HTTP status code, and errors while gathering or encoding metrics. More requests than one per scrape interval mean several jobs or Prometheus servers scrape this exporter.') - + b.panel.withQueries([ - b.query.new('sum by (code) (rate(promhttp_metric_handler_requests_total{job=~"$job", instance="$instance"}[$__rate_interval])) > 0', 'A') - + b.query.withLegendFormat('HTTP {{code}}'), - b.query.new('sum by (cause) (rate(promhttp_metric_handler_errors_total{job=~"$job", instance="$instance"}[$__rate_interval])) > 0', 'B') - + b.query.withLegendFormat('{{cause}} errors'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'reqps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* errors', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'red', - mode: 'fixed', - }, - }, - ], - }, +function(on) + b.tab( + 'Exporter', + b.rows([ + b.summary([90, 91, 92, 93, 94, 95]), + b.row('Scrape', b.flow([[96, 12, 8], [97, 12, 8]])), + b.row('Collectors', b.flow([[99, 8, 8], [100, 16, 8], [101, 12, 9], [102, 12, 9]])), + b.row('Process and Go runtime', b.flow([[104, 8, 8], [105, 8, 8], [106, 8, 8], [107, 8, 8], [108, 8, 8], [109, 8, 8], [110, 12, 8], [111, 12, 8]])), ]), - - b.panel.new(99, 'Collectors', 'table') - + b.panel.withDescription('Latest success, timeout and duration for each enabled collector. Success is 1 for a completed collection and 0 for a failure; timeout is 1 when the scrape budget was exceeded. Disabled collectors are absent.') - + b.panel.withQueries([ - b.query.new('windows_exporter_collector_success{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('windows_exporter_collector_timeout{job=~"$job", instance="$instance"}', 'B') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('windows_exporter_collector_duration_seconds{job=~"$job", instance="$instance"}', 'C') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'joinByField', - kind: 'Transformation', - spec: { - options: { - byField: 'collector', - mode: 'outer', - }, - }, - }, - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - 'Time 2': true, - 'Time 3': true, - __name__: true, - '__name__ 1': true, - '__name__ 2': true, - '__name__ 3': true, - instance: true, - 'instance 1': true, - 'instance 2': true, - 'instance 3': true, - job: true, - 'job 1': true, - 'job 2': true, - 'job 3': true, - port: true, - 'port 1': true, - 'port 2': true, - 'port 3': true, - }, - includeByName: {}, - indexByName: { - 'Value #A': 1, - 'Value #B': 2, - 'Value #C': 3, - collector: 0, - }, - renameByName: { - 'Value #A': 'Status', - 'Value #B': 'Timeout', - 'Value #C': 'Duration', - collector: 'Collector', - }, - }, - }, - }, - ]) - + b.panel.withOptions({ - sortBy: [ - { - desc: true, - displayName: 'Duration', - }, - ], - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'Value #A', - }, - properties: [ + [ + b.panel.new(90, 'Scrape status', 'stat') + + b.panel.withDescription('Result of the last scrape by Prometheus.') + + b.panel.withQueries([ + b.query.new('up{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + mappings: [ { - id: 'mappings', - value: [ - { - options: { - '0': { - color: 'red', - index: 0, - text: 'failed', - }, - '1': { - color: 'green', - index: 1, - text: 'ok', - }, - }, - type: 'value', + options: { + '0': { + index: 0, + text: 'down', }, - ], - }, - { - id: 'custom.cellOptions', - value: { - type: 'color-text', - }, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #B', - }, - properties: [ - { - id: 'mappings', - value: [ - { - options: { - '0': { - color: 'green', - index: 0, - text: 'no', - }, - '1': { - color: 'red', - index: 1, - text: 'yes', - }, - }, - type: 'value', + '1': { + index: 1, + text: 'up', }, - ], - }, - { - id: 'custom.cellOptions', - value: { - type: 'color-text', }, + type: 'value', }, ], - }, - { - matcher: { - id: 'byName', - options: 'Value #C', - }, - properties: [ - { - id: 'unit', - value: 's', - }, - ], - }, - ]), - - b.panel.new(100, 'Collector duration', 'timeseries') - + b.panel.withDescription('Time each collector spent per scrape. Compare against the scrape timeout.') - + b.panel.withQueries([ - b.query.new('windows_exporter_collector_duration_seconds{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('{{collector}}'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - min: 0, - unit: 's', - }) - + b.panel.withOptions({ - legend: { - sortBy: 'Mean', - sortDesc: true, - }, - }), - - b.panel.new(101, 'Collector failures', 'state-timeline') - + b.panel.withDescription('Collectors that failed at least once in the selected time range.') - + b.panel.withQueries([ - b.query.new('windows_exporter_collector_success{job=~"$job", instance="$instance"} and on (collector) (min_over_time(windows_exporter_collector_success{job=~"$job", instance="$instance"}[$__range] @ end()) == 0)', 'A') - + b.query.withLegendFormat('{{collector}}'), - ]) - + b.panel.withDefaults({ - mappings: [ - { - options: { - '0': { + thresholds: { + steps: [ + { color: 'red', - index: 0, - text: 'failed', + value: null, }, - '1': { + { color: 'green', - index: 1, - text: 'ok', + value: 1, }, - }, - type: 'value', + ], }, - ], - }), + unit: '', + }), - b.panel.new(102, 'Collector timeouts', 'state-timeline') - + b.panel.withDescription('Collectors that hit the collector timeout at least once in the selected time range.') - + b.panel.withQueries([ - b.query.new('1 - windows_exporter_collector_timeout{job=~"$job", instance="$instance"} and on (collector) (max_over_time(windows_exporter_collector_timeout{job=~"$job", instance="$instance"}[$__range] @ end()) == 1)', 'A') - + b.query.withLegendFormat('{{collector}}'), - ]) - + b.panel.withDefaults({ - mappings: [ - { - options: { - '0': { + b.panel.new(91, 'Exporter version', 'stat') + + b.panel.withDescription('Builds without a version show the first seven characters of the Git revision.') + + b.panel.withQueries([ + b.query.new('windows_exporter_build_info{job=~"$job", instance="$instance", version!=""} or on (instance) label_replace(windows_exporter_build_info{job=~"$job", instance="$instance"}, "version", "$1", "revision", "(.{7}).*")', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withDefaults({ + unit: '', + }) + + b.panel.withOptions({ + colorMode: 'none', + reduceOptions: { + fields: '/^version$/', + }, + textMode: 'value', + }), + + b.panel.new(92, 'Exporter uptime', 'stat') + + b.panel.withDescription('Time since the exporter process started. A short uptime on a host with a long uptime means the exporter restarted.') + + b.panel.withQueries([ + b.query.new('time() - process_start_time_seconds{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + thresholds: { + steps: [ + { + color: 'orange', + value: null, + }, + { + color: 'text', + value: 3600, + }, + ], + }, + unit: 'dtdurations', + }), + + b.panel.new(93, 'Failed collectors', 'stat') + + b.panel.withDescription('Number of collectors that failed on the latest scrape, including timeouts. The graph shows the count over the selected time range.') + + b.panel.withQueries([ + b.query.new('count(windows_exporter_collector_success{job=~"$job", instance="$instance"} == 0) or vector(0)', 'A'), + ]) + + b.panel.withDefaults({ + decimals: 0, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { color: 'red', - index: 0, - text: 'timed out', + value: 1, }, - '1': { - color: 'green', - index: 1, - text: 'in time', - }, - }, - type: 'value', + ], }, - ], - }), + }) + + b.panel.withOptions({ + graphMode: 'area', + }), - b.panel.new(104, 'Exporter CPU usage', 'timeseries') - + b.panel.withDescription('CPU time used by the exporter process, as a share of one core. CPU usage grows with the number of scrapes, for example when two Prometheus jobs scrape the same exporter; CPU per scrape (right axis) does not.') - + b.panel.withQueries([ - b.query.new('rate(process_cpu_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('CPU'), - b.query.new('rate(process_cpu_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval]) / on (instance) sum by (instance) (rate(promhttp_metric_handler_requests_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('CPU per scrape'), - ]) - + b.panel.withDefaults({ - min: 0, - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'CPU per scrape', + b.panel.new(94, 'Timed-out collectors', 'stat') + + b.panel.withDescription('Number of collectors that timed out on the latest scrape. The graph shows the count over the selected time range.') + + b.panel.withQueries([ + b.query.new('count(windows_exporter_collector_timeout{job=~"$job", instance="$instance"} == 1) or vector(0)', 'A'), + ]) + + b.panel.withDefaults({ + decimals: 0, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'red', + value: 1, + }, + ], }, - properties: [ - { - id: 'unit', - value: 's', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), + + b.panel.new(95, 'Samples per scrape', 'stat') + + b.panel.withDescription('Number of metric samples returned before Prometheus metric relabeling. Changes can reflect collector configuration or changing device/process counts; unexpected drops should be checked against scrape and collector success.') + + b.panel.withQueries([ + b.query.new('scrape_samples_scraped{job=~"$job", instance="$instance"}', 'A'), + ]) + + b.panel.withDefaults({ + unit: 'short', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), + + b.panel.new(96, 'Scrape duration', 'timeseries') + + b.panel.withDescription('Scrape duration measured by Prometheus and by the exporter. It must stay below the scrape timeout of the job.') + + b.panel.withQueries([ + b.query.new('scrape_duration_seconds{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('Prometheus'), + b.query.new('windows_exporter_scrape_duration_seconds{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('exporter'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 's', + }), + + b.panel.new(97, 'HTTP requests to /metrics', 'timeseries') + + b.panel.withDescription('Scrape requests by HTTP status code, and errors while gathering or encoding metrics. More requests than one per scrape interval mean several jobs or Prometheus servers scrape this exporter.') + + b.panel.withQueries([ + b.query.new('sum by (code) (rate(promhttp_metric_handler_requests_total{job=~"$job", instance="$instance"}[$__rate_interval])) > 0', 'A') + + b.query.withLegendFormat('HTTP {{code}}'), + b.query.new('sum by (cause) (rate(promhttp_metric_handler_errors_total{job=~"$job", instance="$instance"}[$__rate_interval])) > 0', 'B') + + b.query.withLegendFormat('{{cause}} errors'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'reqps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* errors', }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'red', + mode: 'fixed', + }, + }, + ], + }, + ]), + + b.panel.new(99, 'Collectors', 'table') + + b.panel.withDescription('Latest success, timeout and duration for each enabled collector. Success is 1 for a completed collection and 0 for a failure; timeout is 1 when the scrape budget was exceeded. Disabled collectors are absent.') + + b.panel.withQueries([ + b.query.new('windows_exporter_collector_success{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('windows_exporter_collector_timeout{job=~"$job", instance="$instance"}', 'B') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('windows_exporter_collector_duration_seconds{job=~"$job", instance="$instance"}', 'C') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ + { + group: 'joinByField', + kind: 'Transformation', + spec: { + options: { + byField: 'collector', + mode: 'outer', + }, + }, + }, + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + 'Time 2': true, + 'Time 3': true, + __name__: true, + '__name__ 1': true, + '__name__ 2': true, + '__name__ 3': true, + instance: true, + 'instance 1': true, + 'instance 2': true, + 'instance 3': true, + job: true, + 'job 1': true, + 'job 2': true, + 'job 3': true, + port: true, + 'port 1': true, + 'port 2': true, + 'port 3': true, + }, + includeByName: {}, + indexByName: { + 'Value #A': 1, + 'Value #B': 2, + 'Value #C': 3, + collector: 0, + }, + renameByName: { + 'Value #A': 'Status', + 'Value #B': 'Timeout', + 'Value #C': 'Duration', + collector: 'Collector', + }, + }, + }, + }, + ]) + + b.panel.withOptions({ + sortBy: [ { - id: 'custom.axisPlacement', - value: 'right', + desc: true, + displayName: 'Duration', }, ], - }, - ]), - - b.panel.new(105, 'Exporter memory', 'timeseries') - + b.panel.withDescription('Working set and private bytes of the exporter process, and the Go heap in use. Steady growth points to a leak.') - + b.panel.withQueries([ - b.query.new('process_resident_memory_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('working set'), - b.query.new('process_virtual_memory_bytes{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('private bytes'), - b.query.new('go_memstats_heap_inuse_bytes{job=~"$job", instance="$instance"}', 'C') - + b.query.withLegendFormat('Go heap in use'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }), - - b.panel.new(106, 'Exporter handles', 'timeseries') - + b.panel.withDescription('Open handles of the exporter process (process_open_fds). Steady growth points to a handle leak.') - + b.panel.withQueries([ - b.query.new('process_open_fds{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('open handles'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'short', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - 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.withQueries([ - b.query.new('go_sched_goroutines_running_goroutines{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('running'), - b.query.new('go_sched_goroutines_runnable_goroutines{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('runnable'), - b.query.new('go_sched_goroutines_waiting_goroutines{job=~"$job", instance="$instance"}', 'C') - + b.query.withLegendFormat('waiting'), - b.query.new('go_sched_goroutines_not_in_go_goroutines{job=~"$job", instance="$instance"}', 'D') - + b.query.withLegendFormat('not in Go'), - b.query.new('go_goroutines{job=~"$job", instance="$instance"}', 'E') - + b.query.withLegendFormat('total'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - min: 0, - unit: 'short', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'total', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'text', - mode: 'fixed', - }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'Value #A', }, - { - id: 'custom.stacking', - value: { - group: 'B', - mode: 'none', - }, - }, - { - id: 'custom.fillOpacity', - value: 0, - }, - { - id: 'custom.lineStyle', - value: { - dash: [ - 10, - 10, + properties: [ + { + id: 'mappings', + value: [ + { + options: { + '0': { + color: 'red', + index: 0, + text: 'failed', + }, + '1': { + color: 'green', + index: 1, + text: 'ok', + }, + }, + type: 'value', + }, ], - fill: 'dash', }, - }, - ], - }, - ]), - - b.panel.new(108, 'Goroutines created and threads', 'timeseries') - + b.panel.withDescription('Goroutines started per second, and OS threads owned by the Go runtime. Goroutines created needs an exporter build with the Go scheduler metrics.') - + b.panel.withQueries([ - b.query.new('rate(go_sched_goroutines_created_goroutines_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('goroutines created/s'), - b.query.new('go_threads{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('OS threads'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'short', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'OS threads', + { + id: 'custom.cellOptions', + value: { + type: 'color-text', + }, + }, + ], }, - properties: [ - { - id: 'custom.axisPlacement', - value: 'right', + { + matcher: { + id: 'byName', + options: 'Value #B', }, - ], - }, - ]), - - b.panel.new(109, 'Scheduler latency', 'timeseries') - + b.panel.withDescription('Time goroutines wait in the runnable state before they run. High values mean the exporter does not get enough CPU. Needs an exporter build with the Go scheduler metrics.') - + b.panel.withQueries([ - b.query.new('histogram_quantile(0.99, sum by (le) (rate(go_sched_latencies_seconds_bucket{job=~"$job", instance="$instance"}[$__rate_interval])))', 'A') - + b.query.withLegendFormat('p99'), - b.query.new('histogram_quantile(0.5, sum by (le) (rate(go_sched_latencies_seconds_bucket{job=~"$job", instance="$instance"}[$__rate_interval])))', 'B') - + b.query.withLegendFormat('p50'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 's', - }), - - b.panel.new(110, 'Garbage collection', 'timeseries') - + b.panel.withDescription('Average GC pause and GC runs per second.') - + b.panel.withQueries([ - b.query.new('rate(go_gc_duration_seconds_sum{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(go_gc_duration_seconds_count{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('average pause'), - b.query.new('rate(go_gc_duration_seconds_count{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('GC runs'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 's', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'GC runs', + properties: [ + { + id: 'mappings', + value: [ + { + options: { + '0': { + color: 'green', + index: 0, + text: 'no', + }, + '1': { + color: 'red', + index: 1, + text: 'yes', + }, + }, + type: 'value', + }, + ], + }, + { + id: 'custom.cellOptions', + value: { + type: 'color-text', + }, + }, + ], }, - properties: [ - { - id: 'unit', - value: 'ops', + { + matcher: { + id: 'byName', + options: 'Value #C', }, + properties: [ + { + id: 'unit', + value: 's', + }, + ], + }, + ]), + + b.panel.new(100, 'Collector duration', 'timeseries') + + b.panel.withDescription('Time each collector spent per scrape. Compare against the scrape timeout.') + + b.panel.withQueries([ + b.query.new('windows_exporter_collector_duration_seconds{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('{{collector}}'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, + }, + min: 0, + unit: 's', + }) + + b.panel.withOptions({ + legend: { + sortBy: 'Mean', + sortDesc: true, + }, + }), + + b.panel.new(101, 'Collector failures', 'state-timeline') + + b.panel.withDescription('Collectors that failed at least once in the selected time range.') + + b.panel.withQueries([ + b.query.new('windows_exporter_collector_success{job=~"$job", instance="$instance"} and on (collector) (min_over_time(windows_exporter_collector_success{job=~"$job", instance="$instance"}[$__range] @ end()) == 0)', 'A') + + b.query.withLegendFormat('{{collector}}'), + ]) + + b.panel.withDefaults({ + mappings: [ { - id: 'custom.axisPlacement', - value: 'right', + options: { + '0': { + color: 'red', + index: 0, + text: 'failed', + }, + '1': { + color: 'green', + index: 1, + text: 'ok', + }, + }, + type: 'value', }, ], - }, - ]), + }), - b.panel.new(111, 'Allocation rate', 'timeseries') - + b.panel.withDescription('Bytes allocated on the Go heap per second. Spikes line up with expensive collectors.') - + b.panel.withQueries([ - b.query.new('rate(go_memstats_alloc_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('allocated'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'Bps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - ] -) + b.panel.new(102, 'Collector timeouts', 'state-timeline') + + b.panel.withDescription('Collectors that hit the collector timeout at least once in the selected time range.') + + b.panel.withQueries([ + b.query.new('1 - windows_exporter_collector_timeout{job=~"$job", instance="$instance"} and on (collector) (max_over_time(windows_exporter_collector_timeout{job=~"$job", instance="$instance"}[$__range] @ end()) == 1)', 'A') + + b.query.withLegendFormat('{{collector}}'), + ]) + + b.panel.withDefaults({ + mappings: [ + { + options: { + '0': { + color: 'red', + index: 0, + text: 'timed out', + }, + '1': { + color: 'green', + index: 1, + text: 'in time', + }, + }, + type: 'value', + }, + ], + }), + + b.panel.new(104, 'Exporter CPU usage', 'timeseries') + + b.panel.withDescription('CPU time used by the exporter process, as a share of one core. CPU usage grows with the number of scrapes, for example when two Prometheus jobs scrape the same exporter; CPU per scrape (right axis) does not.') + + b.panel.withQueries([ + b.query.new('rate(process_cpu_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('CPU'), + b.query.new('rate(process_cpu_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval]) / on (instance) sum by (instance) (rate(promhttp_metric_handler_requests_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('CPU per scrape'), + ]) + + b.panel.withDefaults({ + min: 0, + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'CPU per scrape', + }, + properties: [ + { + id: 'unit', + value: 's', + }, + { + id: 'custom.axisPlacement', + value: 'right', + }, + ], + }, + ]), + + b.panel.new(105, 'Exporter memory', 'timeseries') + + b.panel.withDescription('Working set and private bytes of the exporter process, and the Go heap in use. Steady growth points to a leak.') + + b.panel.withQueries([ + b.query.new('process_resident_memory_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('working set'), + b.query.new('process_virtual_memory_bytes{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('private bytes'), + b.query.new('go_memstats_heap_inuse_bytes{job=~"$job", instance="$instance"}', 'C') + + b.query.withLegendFormat('Go heap in use'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }), + + b.panel.new(106, 'Exporter handles', 'timeseries') + + b.panel.withDescription('Open handles of the exporter process (process_open_fds). Steady growth points to a handle leak.') + + b.panel.withQueries([ + b.query.new('process_open_fds{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('open handles'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'short', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + + 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.withQueries([ + b.query.new('go_sched_goroutines_running_goroutines{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('running'), + b.query.new('go_sched_goroutines_runnable_goroutines{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('runnable'), + b.query.new('go_sched_goroutines_waiting_goroutines{job=~"$job", instance="$instance"}', 'C') + + b.query.withLegendFormat('waiting'), + b.query.new('go_sched_goroutines_not_in_go_goroutines{job=~"$job", instance="$instance"}', 'D') + + b.query.withLegendFormat('not in Go'), + b.query.new('go_goroutines{job=~"$job", instance="$instance"}', 'E') + + b.query.withLegendFormat('total'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, + }, + min: 0, + unit: 'short', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'total', + }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'text', + mode: 'fixed', + }, + }, + { + id: 'custom.stacking', + value: { + group: 'B', + mode: 'none', + }, + }, + { + id: 'custom.fillOpacity', + value: 0, + }, + { + id: 'custom.lineStyle', + value: { + dash: [ + 10, + 10, + ], + fill: 'dash', + }, + }, + ], + }, + ]), + + b.panel.new(108, 'Goroutines created and threads', 'timeseries') + + b.panel.withDescription('Goroutines started per second, and OS threads owned by the Go runtime. Goroutines created needs an exporter build with the Go scheduler metrics.') + + b.panel.withQueries([ + b.query.new('rate(go_sched_goroutines_created_goroutines_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('goroutines created/s'), + b.query.new('go_threads{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('OS threads'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'short', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'OS threads', + }, + properties: [ + { + id: 'custom.axisPlacement', + value: 'right', + }, + ], + }, + ]), + + b.panel.new(109, 'Scheduler latency', 'timeseries') + + b.panel.withDescription('Time goroutines wait in the runnable state before they run. High values mean the exporter does not get enough CPU. Needs an exporter build with the Go scheduler metrics.') + + b.panel.withQueries([ + b.query.new('histogram_quantile(0.99, sum by (le) (rate(go_sched_latencies_seconds_bucket{job=~"$job", instance="$instance"}[$__rate_interval])))', 'A') + + b.query.withLegendFormat('p99'), + b.query.new('histogram_quantile(0.5, sum by (le) (rate(go_sched_latencies_seconds_bucket{job=~"$job", instance="$instance"}[$__rate_interval])))', 'B') + + b.query.withLegendFormat('p50'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 's', + }), + + b.panel.new(110, 'Garbage collection', 'timeseries') + + b.panel.withDescription('Average GC pause and GC runs per second.') + + b.panel.withQueries([ + b.query.new('rate(go_gc_duration_seconds_sum{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(go_gc_duration_seconds_count{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('average pause'), + b.query.new('rate(go_gc_duration_seconds_count{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('GC runs'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 's', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'GC runs', + }, + properties: [ + { + id: 'unit', + value: 'ops', + }, + { + id: 'custom.axisPlacement', + value: 'right', + }, + ], + }, + ]), + + b.panel.new(111, 'Allocation rate', 'timeseries') + + b.panel.withDescription('Bytes allocated on the Go heap per second. Spikes line up with expensive collectors.') + + b.panel.withQueries([ + b.query.new('rate(go_memstats_alloc_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('allocated'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'Bps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + ] + ) diff --git a/contrib/mixin/dashboards/fleet.libsonnet b/contrib/mixin/dashboards/fleet.libsonnet index f3b82380..df9ecddd 100644 --- a/contrib/mixin/dashboards/fleet.libsonnet +++ b/contrib/mixin/dashboards/fleet.libsonnet @@ -1,710 +1,707 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Fleet', - b.grid([ - b.place(2, 0, 0, 24, 10), - b.place(3, 0, 10, 8, 8), - b.place(4, 8, 10, 8, 8), - b.place(5, 16, 10, 8, 8), - b.place(6, 0, 18, 8, 8), - b.place(7, 8, 18, 8, 8), - b.place(8, 16, 18, 8, 8), - ]), - [ - b.panel.new(2, 'Hosts', 'table') - + b.panel.withDescription('One row per scraped host. Click a hostname to open its details. Services up counts running services; Auto stopped counts services with start mode auto that are not running.') - + b.panel.withQueries([ - b.query.new('max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"})', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance, product, version) (windows_os_info{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'B') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (time() - windows_system_boot_time_timestamp{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'C') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (windows_cpu_logical_processor{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'D') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", mode="idle"}[$__rate_interval]), 1)))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'E') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (windows_memory_physical_total_bytes{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'F') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (100 * (1 - windows_memory_physical_free_bytes{job=~"$job"} / windows_memory_physical_total_bytes{job=~"$job"}))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'G') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (100 * windows_memory_committed_bytes{job=~"$job"} / windows_memory_commit_limit{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'H') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (100 * (1 - windows_logical_disk_free_bytes{job=~"$job", volume!~"HarddiskVolume.*"} / windows_logical_disk_size_bytes{job=~"$job", volume!~"HarddiskVolume.*"}))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'I') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(sum by (instance) (windows_service_state{job=~"$job", state="running"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'J') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(count by (instance) (windows_service_state{job=~"$job", state="running"} == 0 and on (instance, name) windows_service_start_mode{job=~"$job", start_mode="auto"} == 1)) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'K') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('(max by (instance) (windows_system_processes{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'L') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'joinByField', - kind: 'Transformation', - spec: { - options: { - byField: 'instance', - mode: 'outer', - }, - }, - }, - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - 'Time 10': true, - 'Time 11': true, - 'Time 12': true, - 'Time 2': true, - 'Time 3': true, - 'Time 4': true, - 'Time 5': true, - 'Time 6': true, - 'Time 7': true, - 'Time 8': true, - 'Time 9': true, - 'Value #A': true, - 'Value #B': true, - }, - includeByName: {}, - indexByName: { - 'Value #C': 4, - 'Value #D': 5, - 'Value #E': 6, - 'Value #F': 7, - 'Value #G': 8, - 'Value #H': 9, - 'Value #I': 10, - 'Value #J': 11, - 'Value #K': 12, - 'Value #L': 13, - hostname: 0, - instance: 1, - product: 2, - version: 3, - }, - renameByName: { - 'Value #C': 'Uptime', - 'Value #D': 'CPUs', - 'Value #E': 'CPU', - 'Value #F': 'Memory', - 'Value #G': 'Memory used', - 'Value #H': 'Commit used', - 'Value #I': 'Fullest volume', - 'Value #J': 'Services up', - 'Value #K': 'Auto stopped', - 'Value #L': 'Processes', - hostname: 'Hostname', - instance: 'Instance', - product: 'OS', - version: 'Version', - }, - }, - }, - }, - ]) - + b.panel.withOptions({ - footer: { - fields: [ - 'CPUs', - 'Memory', - 'Processes', - ], - show: true, - }, - sortBy: [ +function(on) + b.tab( + 'Fleet', + b.rows([ + if on('os') then b.row('Hosts', b.flow([[2, 24, 10]])), + if on('os') then b.row('Utilization', b.flow([if on('cpu') then [3, 8, 8], if on('memory') then [4, 8, 8], if on('logical_disk') then [5, 8, 8]])), + if on('os') then b.row('Throughput and errors', b.flow([if on('net') then [6, 8, 8], if on('logical_disk') then [7, 8, 8], if on('net') then [8, 8, 8]])), + ]), + [ + b.panel.new(2, 'Hosts', 'table') + + b.panel.withDescription('One row per scraped host. Click a hostname to open its details. Services up counts running services; Auto stopped counts services with start mode auto that are not running.') + + b.panel.withQueries([ + b.query.new('max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"})', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance, product, version) (windows_os_info{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'B') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (time() - windows_system_boot_time_timestamp{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'C') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (windows_cpu_logical_processor{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'D') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", mode="idle"}[$__rate_interval]), 1)))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'E') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (windows_memory_physical_total_bytes{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'F') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (100 * (1 - windows_memory_physical_free_bytes{job=~"$job"} / windows_memory_physical_total_bytes{job=~"$job"}))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'G') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (100 * windows_memory_committed_bytes{job=~"$job"} / windows_memory_commit_limit{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'H') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (100 * (1 - windows_logical_disk_free_bytes{job=~"$job", volume!~"HarddiskVolume.*"} / windows_logical_disk_size_bytes{job=~"$job", volume!~"HarddiskVolume.*"}))) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'I') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(sum by (instance) (windows_service_state{job=~"$job", state="running"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'J') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(count by (instance) (windows_service_state{job=~"$job", state="running"} == 0 and on (instance, name) windows_service_start_mode{job=~"$job", start_mode="auto"} == 1)) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'K') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('(max by (instance) (windows_system_processes{job=~"$job"})) and on (instance) windows_os_hostname{job=~"$job", hostname=~"$hostname"}', 'L') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ { - desc: false, - displayName: 'Hostname', + group: 'joinByField', + kind: 'Transformation', + spec: { + options: { + byField: 'instance', + mode: 'outer', + }, + }, }, - ], - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'hostname', - }, - properties: [ - { - id: 'links', - value: [ - { - title: 'Show details for ${__data.fields.hostname}', - url: '/d/${__dashboard.uid}?${__url_time_range}&${datasource:queryparam}&${job:queryparam}&var-hostname=$__all&var-instance=${__data.fields.instance}&dtab=Overview', + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + 'Time 10': true, + 'Time 11': true, + 'Time 12': true, + 'Time 2': true, + 'Time 3': true, + 'Time 4': true, + 'Time 5': true, + 'Time 6': true, + 'Time 7': true, + 'Time 8': true, + 'Time 9': true, + 'Value #A': true, + 'Value #B': true, }, - ], + includeByName: {}, + indexByName: { + 'Value #C': 4, + 'Value #D': 5, + 'Value #E': 6, + 'Value #F': 7, + 'Value #G': 8, + 'Value #H': 9, + 'Value #I': 10, + 'Value #J': 11, + 'Value #K': 12, + 'Value #L': 13, + hostname: 0, + instance: 1, + product: 2, + version: 3, + }, + renameByName: { + 'Value #C': 'Uptime', + 'Value #D': 'CPUs', + 'Value #E': 'CPU', + 'Value #F': 'Memory', + 'Value #G': 'Memory used', + 'Value #H': 'Commit used', + 'Value #I': 'Fullest volume', + 'Value #J': 'Services up', + 'Value #K': 'Auto stopped', + 'Value #L': 'Processes', + hostname: 'Hostname', + instance: 'Instance', + product: 'OS', + version: 'Version', + }, + }, }, + }, + ]) + + b.panel.withOptions({ + footer: { + fields: [ + 'CPUs', + 'Memory', + 'Processes', + ], + show: true, + }, + sortBy: [ { - id: 'custom.width', - value: 180, - }, - { - id: 'custom.filterable', - value: true, + desc: false, + displayName: 'Hostname', }, ], - }, - { - matcher: { - id: 'byName', - options: 'Value #C', - }, - properties: [ - { - id: 'unit', - value: 'dtdurations', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'hostname', }, - { - id: 'custom.width', - value: 90, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'instance', - }, - properties: [ - { - id: 'custom.width', - value: 140, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'product', - }, - properties: [ - { - id: 'custom.width', - value: 160, - }, - { - id: 'custom.filterable', - value: true, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'version', - }, - properties: [ - { - id: 'custom.width', - value: 100, - }, - { - id: 'custom.filterable', - value: true, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #D', - }, - properties: [ - { - id: 'unit', - value: 'none', - }, - { - id: 'custom.width', - value: 60, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #E', - }, - properties: [ - { - id: 'unit', - value: 'percent', - }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ + properties: [ + { + id: 'links', + value: [ { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, + title: 'Show details for ${__data.fields.hostname}', + url: '/d/${__dashboard.uid}?${__url_time_range}&${datasource:queryparam}&${job:queryparam}&var-hostname=$__all&var-instance=${__data.fields.instance}&dtab=Overview', }, ], }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', + { + id: 'custom.width', + value: 180, }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', + { + id: 'custom.filterable', + value: true, }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #F', + ], }, - properties: [ - { - id: 'unit', - value: 'bytes', + { + matcher: { + id: 'byName', + options: 'Value #C', }, - { - id: 'custom.width', - value: 90, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #G', + properties: [ + { + id: 'unit', + value: 'dtdurations', + }, + { + id: 'custom.width', + value: 90, + }, + ], }, - properties: [ - { - id: 'unit', - value: 'percent', + { + matcher: { + id: 'byName', + options: 'instance', }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], + properties: [ + { + id: 'custom.width', + value: 140, }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', - }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', - }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #H', + ], }, - properties: [ - { - id: 'unit', - value: 'percent', + { + matcher: { + id: 'byName', + options: 'product', }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], + properties: [ + { + id: 'custom.width', + value: 160, }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', + { + id: 'custom.filterable', + value: true, }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', - }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #I', + ], }, - properties: [ - { - id: 'unit', - value: 'percent', + { + matcher: { + id: 'byName', + options: 'version', }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], + properties: [ + { + id: 'custom.width', + value: 100, }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', + { + id: 'custom.filterable', + value: true, }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', - }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #J', + ], }, - properties: [ - { - id: 'unit', - value: 'none', + { + matcher: { + id: 'byName', + options: 'Value #D', }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #K', - }, - properties: [ - { - id: 'unit', - value: 'none', - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 1, - }, - ], + properties: [ + { + id: 'unit', + value: 'none', }, - }, - { - id: 'custom.cellOptions', - value: { - type: 'color-text', + { + id: 'custom.width', + value: 60, }, - }, - { - id: 'noValue', - value: '0', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #L', + ], }, - properties: [ - { - id: 'unit', - value: 'none', + { + matcher: { + id: 'byName', + options: 'Value #E', }, - { - id: 'custom.width', - value: 90, + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #F', }, - ], - }, - ]), + properties: [ + { + id: 'unit', + value: 'bytes', + }, + { + id: 'custom.width', + value: 90, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #G', + }, + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #H', + }, + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #I', + }, + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #J', + }, + properties: [ + { + id: 'unit', + value: 'none', + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #K', + }, + properties: [ + { + id: 'unit', + value: 'none', + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 1, + }, + ], + }, + }, + { + id: 'custom.cellOptions', + value: { + type: 'color-text', + }, + }, + { + id: 'noValue', + value: '0', + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #L', + }, + properties: [ + { + id: 'unit', + value: 'none', + }, + { + id: 'custom.width', + value: 90, + }, + ], + }, + ]), - b.panel.new(3, 'CPU utilization', 'timeseries') - + b.panel.withDescription('Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", mode="idle"}[$__rate_interval]), 1)))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}}'), - ]) - + b.panel.withDefaults({ - max: 100, - min: 0, - unit: 'percent', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - b.panel.new(4, 'Memory utilization', 'timeseries') - + b.panel.withDescription('Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (max by (instance) (100 * (1 - windows_memory_physical_free_bytes{job=~"$job"} / windows_memory_physical_total_bytes{job=~"$job"}))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}}'), - ]) - + b.panel.withDefaults({ - max: 100, - min: 0, - unit: 'percent', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - b.panel.new(5, 'Fullest volume', 'timeseries') - + b.panel.withDescription('Usage of the fullest volume per host. Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (max by (instance) (100 * (1 - windows_logical_disk_free_bytes{job=~"$job", volume!~"HarddiskVolume.*"} / windows_logical_disk_size_bytes{job=~"$job", volume!~"HarddiskVolume.*"}))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}}'), - ]) - + b.panel.withDefaults({ - custom: { - thresholdsStyle: { - mode: 'dashed', + b.panel.new(3, 'CPU utilization', 'timeseries') + + b.panel.withDescription('Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", mode="idle"}[$__rate_interval]), 1)))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}}'), + ]) + + b.panel.withDefaults({ + max: 100, + min: 0, + unit: 'percent', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', }, - }, - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), + }), - b.panel.new(6, 'Network throughput', 'timeseries') - + b.panel.withDescription('Sum over all interfaces. Received is drawn below the axis. Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (sum by (instance) (rate(windows_net_bytes_sent_total{job=~"$job"}[$__rate_interval]) * 8)) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}} sent'), - b.query.new('topk(25, (sum by (instance) (rate(windows_net_bytes_received_total{job=~"$job"}[$__rate_interval]) * 8)) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'B') - + b.query.withLegendFormat('{{hostname}} received'), - ]) - + b.panel.withDefaults({ - unit: 'bps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* received$', + b.panel.new(4, 'Memory utilization', 'timeseries') + + b.panel.withDescription('Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (max by (instance) (100 * (1 - windows_memory_physical_free_bytes{job=~"$job"} / windows_memory_physical_total_bytes{job=~"$job"}))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}}'), + ]) + + b.panel.withDefaults({ + max: 100, + min: 0, + unit: 'percent', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, - ]), + }), - b.panel.new(7, 'Disk throughput', 'timeseries') - + b.panel.withDescription('Sum over all volumes. Read is drawn below the axis. Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (sum by (instance) (rate(windows_logical_disk_write_bytes_total{job=~"$job", volume!~"HarddiskVolume.*"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}} write'), - b.query.new('topk(25, (sum by (instance) (rate(windows_logical_disk_read_bytes_total{job=~"$job", volume!~"HarddiskVolume.*"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'B') - + b.query.withLegendFormat('{{hostname}} read'), - ]) - + b.panel.withDefaults({ - unit: 'Bps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', + b.panel.new(5, 'Fullest volume', 'timeseries') + + b.panel.withDescription('Usage of the fullest volume per host. Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (max by (instance) (100 * (1 - windows_logical_disk_free_bytes{job=~"$job", volume!~"HarddiskVolume.*"} / windows_logical_disk_size_bytes{job=~"$job", volume!~"HarddiskVolume.*"}))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}}'), + ]) + + b.panel.withDefaults({ + custom: { + thresholdsStyle: { + mode: 'dashed', + }, }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, - ]), + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), - b.panel.new(8, 'Network errors and discards', 'timeseries') - + b.panel.withDescription('Sum over all interfaces of received and outbound errors and discards. Shows the 25 highest hosts at each point in time.') - + b.panel.withQueries([ - b.query.new('topk(25, (sum by (instance) (rate(windows_net_packets_received_errors_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_received_discarded_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_outbound_errors_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_outbound_discarded_total{job=~"$job"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') - + b.query.withLegendFormat('{{hostname}}'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'pps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - ] -) + b.panel.new(6, 'Network throughput', 'timeseries') + + b.panel.withDescription('Sum over all interfaces. Received is drawn below the axis. Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (sum by (instance) (rate(windows_net_bytes_sent_total{job=~"$job"}[$__rate_interval]) * 8)) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}} sent'), + b.query.new('topk(25, (sum by (instance) (rate(windows_net_bytes_received_total{job=~"$job"}[$__rate_interval]) * 8)) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'B') + + b.query.withLegendFormat('{{hostname}} received'), + ]) + + b.panel.withDefaults({ + unit: 'bps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* received$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.panel.new(7, 'Disk throughput', 'timeseries') + + b.panel.withDescription('Sum over all volumes. Read is drawn below the axis. Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (sum by (instance) (rate(windows_logical_disk_write_bytes_total{job=~"$job", volume!~"HarddiskVolume.*"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}} write'), + b.query.new('topk(25, (sum by (instance) (rate(windows_logical_disk_read_bytes_total{job=~"$job", volume!~"HarddiskVolume.*"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'B') + + b.query.withLegendFormat('{{hostname}} read'), + ]) + + b.panel.withDefaults({ + unit: 'Bps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + + b.panel.new(8, 'Network errors and discards', 'timeseries') + + b.panel.withDescription('Sum over all interfaces of received and outbound errors and discards. Shows the 25 highest hosts at each point in time.') + + b.panel.withQueries([ + b.query.new('topk(25, (sum by (instance) (rate(windows_net_packets_received_errors_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_received_discarded_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_outbound_errors_total{job=~"$job"}[$__rate_interval]) + rate(windows_net_packets_outbound_discarded_total{job=~"$job"}[$__rate_interval]))) * on (instance) group_left (hostname) max by (instance, hostname) (windows_os_hostname{job=~"$job", hostname=~"$hostname"}))', 'A') + + b.query.withLegendFormat('{{hostname}}'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'pps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + ] + ) diff --git a/contrib/mixin/dashboards/gpu.libsonnet b/contrib/mixin/dashboards/gpu.libsonnet index ec9d5ef6..9492f678 100644 --- a/contrib/mixin/dashboards/gpu.libsonnet +++ b/contrib/mixin/dashboards/gpu.libsonnet @@ -1,399 +1,401 @@ local b = import 'builders.libsonnet'; +local metric(name) = 'windows_gpu_' + name + '{job=~"$job", instance="$instance"}'; +local perGpu(name) = 'sum(max by (luid) (' + metric(name) + '))'; -b.tab( - 'GPU', - b.grid([ - b.place(57, 0, 0, 24, 5), - b.place(58, 0, 5, 12, 8), - b.place(59, 12, 5, 12, 8), - b.place(60, 0, 13, 12, 8), - b.place(61, 12, 13, 12, 8), - b.place(120, 0, 21, 12, 8), - b.place(121, 12, 21, 12, 8), - b.place(122, 0, 29, 12, 8), - b.place(123, 12, 29, 12, 8), - b.place(124, 0, 37, 12, 8), - b.place(125, 12, 37, 12, 8), - b.place(126, 0, 45, 12, 8), - b.place(127, 12, 45, 12, 8), - b.place(128, 0, 53, 12, 8), - b.place(129, 12, 53, 12, 8), - b.place(130, 0, 61, 12, 8), - b.place(131, 12, 61, 12, 8), - ]), - [ - b.panel.new(57, 'GPUs', 'table') - + b.panel.withDescription('Needs the gpu collector, which is not enabled by default. Utilization is the busiest engine of the GPU.') - + b.panel.withQueries([ - b.query.new('max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('clamp_max(max by (luid) (sum by (luid, eng, engtype) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))), 1)', 'B') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~"$job", instance="$instance"})', 'C') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('max by (luid) (windows_gpu_dedicated_video_memory_size_bytes{job=~"$job", instance="$instance"})', 'D') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('max by (luid) (windows_gpu_adapter_memory_shared_bytes{job=~"$job", instance="$instance"})', 'E') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('max by (luid) (windows_gpu_shared_system_memory_size_bytes{job=~"$job", instance="$instance"})', 'F') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'joinByField', - kind: 'Transformation', - spec: { - options: { - byField: 'luid', - mode: 'outer', - }, - }, - }, - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - 'Time 2': true, - 'Time 3': true, - 'Time 4': true, - 'Time 5': true, - 'Time 6': true, - 'Value #A': true, - luid: true, - }, - includeByName: {}, - indexByName: { - 'Value #B': 1, - 'Value #C': 2, - 'Value #D': 3, - 'Value #E': 4, - 'Value #F': 5, - name: 0, - }, - renameByName: { - 'Value #B': 'Utilization', - 'Value #C': 'Dedicated memory used', - 'Value #D': 'Dedicated memory', - 'Value #E': 'Shared memory used', - 'Value #F': 'Shared memory', - name: 'GPU', - }, - }, - }, - }, - ]) - + b.panel.withOptions({ - sortBy: [], - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'Value #B', - }, - properties: [ - { - id: 'unit', - value: 'percentunit', - }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 1, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', - }, - }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', - }, - }, - { - id: 'decimals', - value: 1, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #C', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #D', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #E', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #F', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, +function(on) + b.tab( + 'GPU', + b.rows([ + if on('gpu') then b.summary([184, 185, 186, 187, 188, 189]), + if on('gpu') then b.row('Adapters', b.flow([[57, 24, 5], [58, 12, 8], [59, 12, 8], [125, 8, 8], [126, 8, 8], [127, 8, 8]])), + if on('gpu') then b.row('Sensors and clocks', b.flow([[120, 12, 8], [121, 12, 8], [122, 8, 8], [123, 8, 8], [124, 8, 8]])), + if on('gpu') then b.row('Processes', b.flow([[60, 12, 8], [61, 12, 8], [128, 12, 8], [129, 12, 8], [130, 12, 8], [131, 12, 8]])), ]), + [ + b.stat(184, 'Utilization', 'Utilization of the busiest engine on the busiest GPU.', 'max(clamp_max(max by (luid) (sum by (luid, eng, engtype) (rate(' + metric('engine_time_seconds') + '[$__rate_interval]))), 1))', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(185, 'VRAM used', 'Dedicated GPU memory in use, summed over all GPUs.', perGpu('adapter_memory_dedicated_bytes'), 'bytes') + + b.panel.withDefaults({ decimals: 1 }), + b.stat(186, 'VRAM usage', 'Dedicated GPU memory in use as a share of the dedicated video memory of all GPUs.', perGpu('adapter_memory_dedicated_bytes') + ' / (' + perGpu('dedicated_video_memory_size_bytes') + ' > 0)', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(187, 'Shared memory', 'System memory used by the GPUs, summed over all GPUs.', perGpu('adapter_memory_shared_bytes'), 'bytes') + + b.panel.withDefaults({ decimals: 1 }), + b.stat(188, 'Temperature', 'Temperature of the hottest GPU. Requires WDDM 2.4 or newer and driver support.', 'max(' + metric('temperature_celsius') + ')', 'celsius', steps=b.levels(80, 90)), + b.stat(189, 'Power usage', 'Highest GPU power draw as a fraction of the driver-reported maximum power (TDP). Requires WDDM 2.4 or newer and driver support.', 'max(' + metric('power_usage_ratio') + ')', 'percentunit') + + b.panel.withDefaults({ decimals: 1, min: 0 }), - b.panel.new(58, 'GPU utilization by engine type', 'timeseries') - + b.panel.withDescription('Busiest engine of each engine type, as in Task Manager.') - + b.panel.withQueries([ - b.query.new('clamp_max(max by (luid, engtype) (sum by (luid, eng, engtype) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))), 1) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} {{engtype}}'), - ]) - + b.panel.withDefaults({ - max: 1, - min: 0, - }), - - b.panel.new(59, 'GPU memory', 'timeseries') - + b.panel.withDescription('Dedicated (video) and shared (system) memory in use, against the size of each pool.') - + b.panel.withQueries([ - b.query.new('max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} dedicated used'), - b.query.new('max by (luid) (windows_gpu_dedicated_video_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} dedicated size'), - b.query.new('max by (luid) (windows_gpu_adapter_memory_shared_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'C') - + b.query.withLegendFormat('{{name}} shared used'), - b.query.new('max by (luid) (windows_gpu_shared_system_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'D') - + b.query.withLegendFormat('{{name}} shared size'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* size', - }, - properties: [ - { - id: 'custom.fillOpacity', - value: 0, - }, - { - id: 'custom.lineStyle', - value: { - dash: [ - 10, - 10, - ], - fill: 'dash', + b.panel.new(57, 'GPUs', 'table') + + b.panel.withDescription('Needs the gpu collector, which is not enabled by default. Utilization is the busiest engine of the GPU.') + + b.panel.withQueries([ + b.query.new('max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('clamp_max(max by (luid) (sum by (luid, eng, engtype) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))), 1)', 'B') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~"$job", instance="$instance"})', 'C') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('max by (luid) (windows_gpu_dedicated_video_memory_size_bytes{job=~"$job", instance="$instance"})', 'D') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('max by (luid) (windows_gpu_adapter_memory_shared_bytes{job=~"$job", instance="$instance"})', 'E') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('max by (luid) (windows_gpu_shared_system_memory_size_bytes{job=~"$job", instance="$instance"})', 'F') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ + { + group: 'joinByField', + kind: 'Transformation', + spec: { + options: { + byField: 'luid', + mode: 'outer', }, }, - ], - }, - ]), + }, + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + 'Time 2': true, + 'Time 3': true, + 'Time 4': true, + 'Time 5': true, + 'Time 6': true, + 'Value #A': true, + luid: true, + }, + includeByName: {}, + indexByName: { + 'Value #B': 1, + 'Value #C': 2, + 'Value #D': 3, + 'Value #E': 4, + 'Value #F': 5, + name: 0, + }, + renameByName: { + 'Value #B': 'Utilization', + 'Value #C': 'Dedicated memory used', + 'Value #D': 'Dedicated memory', + 'Value #E': 'Shared memory used', + 'Value #F': 'Shared memory', + name: 'GPU', + }, + }, + }, + }, + ]) + + b.panel.withOptions({ + sortBy: [], + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'Value #B', + }, + properties: [ + { + id: 'unit', + value: 'percentunit', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 1, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #C', + }, + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #D', + }, + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #E', + }, + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #F', + }, + properties: [ + { + id: 'unit', + value: 'bytes', + }, + ], + }, + ]), - b.panel.new(60, 'Top 10 processes by GPU utilization', 'timeseries') - + b.panel.withDescription('Busiest GPU engine used by each process. Process names need the process collector; otherwise only the PID is shown.') - + b.panel.withQueries([ - b.query.new('topk(10, (max by (process_id) (sum by (process_id, luid, eng) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) max by (process_id) (sum by (process_id, luid, eng) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ - min: 0, - }) - + b.panel.withOptions({ - legend: { - sortBy: 'Mean', - sortDesc: true, - }, - }), + b.panel.new(58, 'GPU utilization by engine type', 'timeseries') + + b.panel.withDescription('Busiest engine of each engine type, as in Task Manager.') + + b.panel.withQueries([ + b.query.new('clamp_max(max by (luid, engtype) (sum by (luid, eng, engtype) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))), 1) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} {{engtype}}'), + ]) + + b.panel.withDefaults({ + max: 1, + min: 0, + }), - b.panel.new(61, 'Top 10 processes by dedicated GPU memory', 'timeseries') - + b.panel.withDescription('Process names need the process collector; otherwise only the PID is shown.') - + b.panel.withQueries([ - b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_dedicated_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_dedicated_bytes{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }) - + b.panel.withOptions({ - legend: { - sortBy: 'Mean', - sortDesc: true, - }, - }), + b.panel.new(59, 'GPU memory', 'timeseries') + + b.panel.withDescription('Dedicated (video) and shared (system) memory in use, against the size of each pool.') + + b.panel.withQueries([ + b.query.new('max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} dedicated used'), + b.query.new('max by (luid) (windows_gpu_dedicated_video_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} dedicated size'), + b.query.new('max by (luid) (windows_gpu_adapter_memory_shared_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'C') + + b.query.withLegendFormat('{{name}} shared used'), + b.query.new('max by (luid) (windows_gpu_shared_system_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'D') + + b.query.withLegendFormat('{{name}} shared size'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* size', + }, + properties: [ + { + id: 'custom.fillOpacity', + value: 0, + }, + { + id: 'custom.lineStyle', + value: { + dash: [ + 10, + 10, + ], + fill: 'dash', + }, + }, + ], + }, + ]), - b.panel.new(120, 'GPU temperature', 'timeseries') - + b.panel.withDescription('Current GPU temperature, driver-reported throttling threshold and maximum temperature in degrees Celsius. Sustained readings near the warning threshold can indicate insufficient cooling. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys) (windows_gpu_temperature_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} temperature'), - b.query.new('max by (luid, phys) (windows_gpu_temperature_warning_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} GPU {{phys}} throttling threshold'), - b.query.new('max by (luid, phys) (windows_gpu_temperature_max_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'C') - + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'celsius' }), + b.panel.new(60, 'Top 10 processes by GPU utilization', 'timeseries') + + b.panel.withDescription('Busiest GPU engine used by each process. Process names need the process collector; otherwise only the PID is shown.') + + b.panel.withQueries([ + b.query.new('topk(10, (max by (process_id) (sum by (process_id, luid, eng) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) max by (process_id) (sum by (process_id, luid, eng) (rate(windows_gpu_engine_time_seconds{job=~"$job", instance="$instance"}[$__rate_interval]))))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ + min: 0, + }) + + b.panel.withOptions({ + legend: { + sortBy: 'Mean', + sortDesc: true, + }, + }), - b.panel.new(121, 'GPU fan speed', 'timeseries') - + b.panel.withDescription('Current and maximum main-fan speed in revolutions per minute. A supported fan can report zero when stopped under light load. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys) (windows_gpu_fan_speed_rpm{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} fan'), - b.query.new('max by (luid, phys) (windows_gpu_fan_speed_max_rpm{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'rotrpm' }), + b.panel.new(61, 'Top 10 processes by dedicated GPU memory', 'timeseries') + + b.panel.withDescription('Process names need the process collector; otherwise only the PID is shown.') + + b.panel.withQueries([ + b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_dedicated_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_dedicated_bytes{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }) + + b.panel.withOptions({ + legend: { + sortBy: 'Mean', + sortDesc: true, + }, + }), - b.panel.new(122, 'GPU power usage', 'timeseries') - + b.panel.withDescription('Current GPU power draw as a fraction of the driver-reported maximum power (TDP). This is a ratio, not an absolute measurement in watts. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys) (windows_gpu_power_usage_ratio{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} power'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'percentunit' }), + b.panel.new(120, 'GPU temperature', 'timeseries') + + b.panel.withDescription('Current GPU temperature, driver-reported throttling threshold and maximum temperature in degrees Celsius. Sustained readings near the warning threshold can indicate insufficient cooling. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys) (windows_gpu_temperature_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} temperature'), + b.query.new('max by (luid, phys) (windows_gpu_temperature_warning_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} GPU {{phys}} throttling threshold'), + b.query.new('max by (luid, phys) (windows_gpu_temperature_max_celsius{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'C') + + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'celsius' }), - b.panel.new(123, 'GPU memory clock', 'timeseries') - + b.panel.withDescription('Current and maximum non-overclocked GPU memory clock in hertz. Clocks can fall at idle; correlate drops under load with temperature and power. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys) (windows_gpu_memory_frequency_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} memory clock'), - b.query.new('max by (luid, phys) (windows_gpu_memory_frequency_max_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'hertz' }), + b.panel.new(121, 'GPU fan speed', 'timeseries') + + b.panel.withDescription('Current and maximum main-fan speed in revolutions per minute. A supported fan can report zero when stopped under light load. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys) (windows_gpu_fan_speed_rpm{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} fan'), + b.query.new('max by (luid, phys) (windows_gpu_fan_speed_max_rpm{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'rotrpm' }), - b.panel.new(124, 'GPU engine clock', 'timeseries') - + b.panel.withDescription('Current and maximum non-overclocked frequency per GPU engine in hertz. Only engines with a reported maximum clock are exposed, typically the 3D engine. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys, eng) (windows_gpu_engine_frequency_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} engine {{eng}} clock'), - b.query.new('max by (luid, phys, eng) (windows_gpu_engine_frequency_max_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} GPU {{phys}} engine {{eng}} maximum'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'hertz' }), + b.panel.new(122, 'GPU power usage', 'timeseries') + + b.panel.withDescription('Current GPU power draw as a fraction of the driver-reported maximum power (TDP). This is a ratio, not an absolute measurement in watts. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys) (windows_gpu_power_usage_ratio{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} power'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'percentunit' }), - b.panel.new(125, 'GPU committed memory', 'timeseries') - + b.panel.withDescription('Total committed GPU memory per physical GPU in bytes. Commitment is a separate accounting measure from dedicated or shared memory residency; do not add these series together.') - + b.panel.withQueries([ - b.query.new('max by (luid, phys) (windows_gpu_adapter_memory_committed_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} committed'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(123, 'GPU memory clock', 'timeseries') + + b.panel.withDescription('Current and maximum non-overclocked GPU memory clock in hertz. Clocks can fall at idle; correlate drops under load with temperature and power. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys) (windows_gpu_memory_frequency_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} memory clock'), + b.query.new('max by (luid, phys) (windows_gpu_memory_frequency_max_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} GPU {{phys}} maximum'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'hertz' }), - b.panel.new(126, 'GPU local and non-local memory', 'timeseries') - + b.panel.withDescription('Local and non-local adapter memory usage in bytes, summed across memory partitions for each physical GPU. These describe memory locality and overlap the dedicated/shared accounting views.') - + b.panel.withQueries([ - b.query.new('sum by (luid, phys) (windows_gpu_local_adapter_memory_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} GPU {{phys}} local'), - b.query.new('sum by (luid, phys) (windows_gpu_non_local_adapter_memory_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') - + b.query.withLegendFormat('{{name}} GPU {{phys}} non-local'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(124, 'GPU engine clock', 'timeseries') + + b.panel.withDescription('Current and maximum non-overclocked frequency per GPU engine in hertz. Only engines with a reported maximum clock are exposed, typically the 3D engine. Requires the gpu collector, WDDM 2.4 or newer and driver support. Unsupported sensor values are absent, rather than zero.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys, eng) (windows_gpu_engine_frequency_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} engine {{eng}} clock'), + b.query.new('max by (luid, phys, eng) (windows_gpu_engine_frequency_max_hertz{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} GPU {{phys}} engine {{eng}} maximum'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'hertz' }), - b.panel.new(127, 'GPU dedicated system memory capacity', 'timeseries') - + b.panel.withDescription('System memory dedicated to each GPU in bytes. This capacity is distinct from dedicated video memory and the shared system memory pool; it can be zero on discrete adapters.') - + b.panel.withQueries([ - b.query.new('max by (luid) (windows_gpu_dedicated_system_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{name}} dedicated system capacity'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(125, 'GPU committed memory', 'timeseries') + + b.panel.withDescription('Total committed GPU memory per physical GPU in bytes. Commitment is a separate accounting measure from dedicated or shared memory residency; do not add these series together.') + + b.panel.withQueries([ + b.query.new('max by (luid, phys) (windows_gpu_adapter_memory_committed_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} committed'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), - b.panel.new(128, 'Top 10 processes by shared GPU memory', 'timeseries') - + b.panel.withDescription('Top ten processes at each point in time by shared GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') - + b.panel.withQueries([ - b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_shared_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_shared_bytes{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(126, 'GPU local and non-local memory', 'timeseries') + + b.panel.withDescription('Local and non-local adapter memory usage in bytes, summed across memory partitions for each physical GPU. These describe memory locality and overlap the dedicated/shared accounting views.') + + b.panel.withQueries([ + b.query.new('sum by (luid, phys) (windows_gpu_local_adapter_memory_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} GPU {{phys}} local'), + b.query.new('sum by (luid, phys) (windows_gpu_non_local_adapter_memory_bytes{job=~"$job", instance="$instance"}) * on (luid, phys) group_left (name) max by (luid, phys, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'B') + + b.query.withLegendFormat('{{name}} GPU {{phys}} non-local'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), - b.panel.new(129, 'Top 10 processes by committed GPU memory', 'timeseries') - + b.panel.withDescription('Top ten processes at each point in time by committed GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') - + b.panel.withQueries([ - b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_committed_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_committed_bytes{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(127, 'GPU dedicated system memory capacity', 'timeseries') + + b.panel.withDescription('System memory dedicated to each GPU in bytes. This capacity is distinct from dedicated video memory and the shared system memory pool; it can be zero on discrete adapters.') + + b.panel.withQueries([ + b.query.new('max by (luid) (windows_gpu_dedicated_system_memory_size_bytes{job=~"$job", instance="$instance"}) * on (luid) group_left (name) max by (luid, name) (windows_gpu_info{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{name}} dedicated system capacity'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), - b.panel.new(130, 'Top 10 processes by local GPU memory', 'timeseries') - + b.panel.withDescription('Top ten processes at each point in time by local GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') - + b.panel.withQueries([ - b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_local_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_local_bytes{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + b.panel.new(128, 'Top 10 processes by shared GPU memory', 'timeseries') + + b.panel.withDescription('Top ten processes at each point in time by shared GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') + + b.panel.withQueries([ + b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_shared_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_shared_bytes{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), - b.panel.new(131, 'Top 10 processes by non-local GPU memory', 'timeseries') - + b.panel.withDescription('Top ten processes at each point in time by non-local GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') - + b.panel.withQueries([ - b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_non_local_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_non_local_bytes{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{process}} ({{process_id}})'), - ]) - + b.panel.withDefaults({ min: 0, unit: 'bytes' }), - ] -) + b.panel.new(129, 'Top 10 processes by committed GPU memory', 'timeseries') + + b.panel.withDescription('Top ten processes at each point in time by committed GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') + + b.panel.withQueries([ + b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_committed_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_committed_bytes{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + + b.panel.new(130, 'Top 10 processes by local GPU memory', 'timeseries') + + b.panel.withDescription('Top ten processes at each point in time by local GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') + + b.panel.withQueries([ + b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_local_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_local_bytes{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + + b.panel.new(131, 'Top 10 processes by non-local GPU memory', 'timeseries') + + b.panel.withDescription('Top ten processes at each point in time by non-local GPU memory in bytes, summed across GPUs. Membership can change over time. Process names require the process collector; otherwise the PID is shown. Memory accounting views overlap and should not be added together.') + + b.panel.withQueries([ + b.query.new('topk(10, (sum by (process_id) (windows_gpu_process_memory_non_local_bytes{job=~"$job", instance="$instance"}) * on (process_id) group_left (process) max by (process_id, process) (windows_process_info{job=~"$job", instance="$instance"})) or on (process_id) sum by (process_id) (windows_gpu_process_memory_non_local_bytes{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{process}} ({{process_id}})'), + ]) + + b.panel.withDefaults({ min: 0, unit: 'bytes' }), + ] + ) diff --git a/contrib/mixin/dashboards/hyper_v.libsonnet b/contrib/mixin/dashboards/hyper_v.libsonnet index 67bbb826..380a6066 100644 --- a/contrib/mixin/dashboards/hyper_v.libsonnet +++ b/contrib/mixin/dashboards/hyper_v.libsonnet @@ -1,383 +1,323 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Hyper-V', - b.rows([ - b.row('Host', b.grid([ - b.place(63, 0, 0, 4, 4), - b.place(64, 4, 0, 4, 4), - b.place(65, 8, 0, 4, 4), - b.place(66, 12, 0, 4, 4), - b.place(67, 16, 0, 4, 4), - b.place(68, 20, 0, 4, 4), - b.place(69, 0, 4, 12, 8), - b.place(70, 12, 4, 12, 8), - ])), - b.row('Memory', b.grid([ - b.place(72, 0, 0, 8, 8), - b.place(73, 8, 0, 8, 8), - b.place(74, 16, 0, 8, 8), - ])), - b.row('Storage', b.grid([ - b.place(76, 0, 0, 8, 8), - b.place(77, 8, 0, 8, 8), - b.place(78, 16, 0, 8, 8), - ])), - b.row('Network', b.grid([ - b.place(80, 0, 0, 8, 8), - b.place(81, 8, 0, 8, 8), - b.place(82, 16, 0, 8, 8), - ])), - ]), - [ - b.panel.new(63, 'Virtual machines', 'stat') - + b.panel.withDescription('Needs the hyperv collector, which is not enabled by default.') - + b.panel.withQueries([ - b.query.new('sum(windows_hyperv_virtual_machine_health_total_count{job=~"$job", instance="$instance"})', 'A') - + b.query.withInstant(), +function(on) + b.tab( + 'Hyper-V', + b.rows([ + if on('hyperv') then b.summary([63, 64, 65, 66, 67, 68]), + if on('hyperv') then b.row('CPU', b.flow([[69, 12, 8], [70, 12, 8]])), + if on('hyperv') then b.row('Memory', b.flow([[72, 8, 8], [73, 8, 8], [74, 8, 8]])), + if on('hyperv') then b.row('Storage', b.flow([[76, 8, 8], [77, 8, 8], [78, 8, 8]])), + if on('hyperv') then b.row('Network', b.flow([[80, 8, 8], [81, 8, 8], [82, 8, 8]])), ]), + [ + b.stat(63, 'Virtual machines', 'Needs the hyperv collector, which is not enabled by default.', 'sum(windows_hyperv_virtual_machine_health_total_count{job=~"$job", instance="$instance"})', 'short'), - b.panel.new(64, 'VMs in critical health', 'stat') - + b.panel.withDescription('Number of Hyper-V virtual machines reporting critical health. Inspect the affected VM and Hyper-V event logs; this requires the optional hyperv collector.') - + b.panel.withQueries([ - b.query.new('sum(windows_hyperv_virtual_machine_health_total_count{job=~"$job", instance="$instance", state="critical"})', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ + b.stat(64, 'VMs in critical health', 'Number of Hyper-V virtual machines reporting critical health. Inspect the affected VM and Hyper-V event logs; this requires the optional hyperv collector.', 'sum(windows_hyperv_virtual_machine_health_total_count{job=~"$job", instance="$instance", state="critical"})', steps=[{ color: 'green', value: null }, { color: 'red', value: 1 }]), + + b.panel.new(65, 'Hyper-V WMI', 'stat') + + b.panel.withDescription('Whether the Hyper-V WMI namespace answers. When it stops answering, Hyper-V Manager and Failover Cluster Manager usually cannot manage the host.') + + b.panel.withQueries([ + b.query.new('windows_hyperv_wmi_health{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + mappings: [ { - color: 'green', - value: null, - }, - { - color: 'red', - value: 1, + options: { + '0': { + index: 0, + text: 'not responding', + }, + '1': { + index: 1, + text: 'ok', + }, + }, + type: 'value', }, ], - }, - }), + thresholds: { + steps: [ + { + color: 'red', + value: null, + }, + { + color: 'green', + value: 1, + }, + ], + }, + unit: '', + }), - b.panel.new(65, 'Hyper-V WMI', 'stat') - + b.panel.withDescription('Whether the Hyper-V WMI namespace answers. When it stops answering, Hyper-V Manager and Failover Cluster Manager usually cannot manage the host.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_wmi_health{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - mappings: [ + b.stat(66, 'Logical processors', 'Number of host logical processors reported by Hyper-V. Use this as capacity context for host and virtual processor load; this requires the optional hyperv collector.', 'windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}', 'short'), + + b.stat(67, 'Virtual processors', 'Virtual processors assigned to all VMs.', 'windows_hyperv_total_vm_processor_count{job=~"$job", instance="$instance"}', 'short'), + + b.stat(68, 'vCPU per logical CPU', 'Virtual processors assigned to VMs per logical processor of the host.', 'windows_hyperv_total_vm_processor_count{job=~"$job", instance="$instance"} / windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}', 'short') + + b.panel.withDefaults({ decimals: 2 }), + + b.panel.new(69, 'Host CPU time by state', 'timeseries') + + b.panel.withDescription('Share of all logical processors spent running guest code (VMs and the root partition) and in the hypervisor. With Hyper-V enabled, the CPU tab only sees the root partition.') + + b.panel.withQueries([ + b.query.new('sum by (state) (rate(windows_hyperv_hypervisor_logical_processor_time_total{job=~"$job", instance="$instance", state!="idle"}[$__rate_interval])) / scalar(count(windows_hyperv_hypervisor_logical_processor_time_total{job=~"$job", instance="$instance", state="idle"}))', 'A') + + b.query.withLegendFormat('{{state}}'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, + }, + max: 1, + min: 0, + }), + + b.panel.new(70, 'CPU usage per VM', 'timeseries') + + b.panel.withDescription('Virtual processor run time of each VM as a share of all logical processors of the host.') + + b.panel.withQueries([ + b.query.new('sum by (vm) (rate(windows_hyperv_hypervisor_virtual_processor_run_time_total{job=~"$job", instance="$instance"}[$__rate_interval])) / scalar(max(windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}))', 'A') + + b.query.withLegendFormat('{{vm}}'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, + }, + min: 0, + }) + + b.panel.withOptions({ + legend: { + sortBy: 'Mean', + sortDesc: true, + }, + }), + + b.panel.new(72, 'Memory assigned to VMs', 'timeseries') + + b.panel.withDescription('Physical memory currently assigned to each VM with dynamic memory.') + + b.panel.withQueries([ + b.query.new('windows_hyperv_dynamic_memory_vm_physical_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('{{vm}}'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, + }, + min: 0, + unit: 'bytes', + }) + + b.panel.withOptions({ + legend: { + sortBy: 'Mean', + sortDesc: true, + }, + }), + + b.panel.new(73, 'VM memory pressure', 'timeseries') + + b.panel.withDescription('Memory a VM needs as a share of the memory it has. Above 100% the VM needs more memory than it is assigned.') + + b.panel.withQueries([ + b.query.new('windows_hyperv_dynamic_memory_vm_pressure_current_ratio{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('{{vm}}'), + ]) + + b.panel.withDefaults({ + custom: { + thresholdsStyle: { + mode: 'dashed', + }, + }, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'red', + value: 1, + }, + ], + }, + }), + + b.panel.new(74, 'Memory available for VMs', 'timeseries') + + b.panel.withDescription('Memory the dynamic memory balancer can still hand out to VMs.') + + b.panel.withQueries([ + b.query.new('windows_hyperv_dynamic_memory_balancer_available_memory_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('{{balancer}}'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + + b.panel.new(76, 'Virtual disk throughput', 'timeseries') + + b.panel.withDescription('Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_virtual_storage_device_bytes_written{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{device}} write'), + b.query.new('rate(windows_hyperv_virtual_storage_device_bytes_read{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{device}} read'), + ]) + + b.panel.withDefaults({ + unit: 'Bps', + }) + + b.panel.withOverrides([ { - options: { - '0': { - index: 0, - text: 'not responding', + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', }, - '1': { - index: 1, - text: 'ok', + ], + }, + ]), + + b.panel.new(77, 'Virtual disk IOPS', 'timeseries') + + b.panel.withDescription('Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_virtual_storage_device_operations_written_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{device}} write'), + b.query.new('rate(windows_hyperv_virtual_storage_device_operations_read_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{device}} read'), + ]) + + b.panel.withDefaults({ + unit: 'iops', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* read$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', }, - }, - type: 'value', + ], }, - ], - thresholds: { - steps: [ - { - color: 'red', - value: null, + ]), + + b.panel.new(78, 'Virtual disk latency and errors', 'timeseries') + + b.panel.withDescription('Average I/O latency of each virtual disk: the total I/O latency divided by the number of completed I/O transfers. Errors use the right axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_hyperv_virtual_storage_device_throughput_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{device}} latency'), + b.query.new('rate(windows_hyperv_virtual_storage_device_error_count_total{job=~"$job", instance="$instance"}[$__rate_interval]) > 0', 'B') + + b.query.withLegendFormat('{{device}} errors'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 's', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* errors', }, - { - color: 'green', - value: 1, - }, - ], - }, - unit: '', - }), - - b.panel.new(66, 'Logical processors', 'stat') - + b.panel.withDescription('Number of host logical processors reported by Hyper-V. Use this as capacity context for host and virtual processor load; this requires the optional hyperv collector.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]), - - b.panel.new(67, 'Virtual processors', 'stat') - + b.panel.withDescription('Virtual processors assigned to all VMs.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_total_vm_processor_count{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]), - - b.panel.new(68, 'vCPU per logical CPU', 'stat') - + b.panel.withDescription('Virtual processors assigned to VMs per logical processor of the host.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_total_vm_processor_count{job=~"$job", instance="$instance"} / windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - decimals: 2, - }), - - b.panel.new(69, 'Host CPU time by state', 'timeseries') - + b.panel.withDescription('Share of all logical processors spent running guest code (VMs and the root partition) and in the hypervisor. With Hyper-V enabled, the CPU tab only sees the root partition.') - + b.panel.withQueries([ - b.query.new('sum by (state) (rate(windows_hyperv_hypervisor_logical_processor_time_total{job=~"$job", instance="$instance", state!="idle"}[$__rate_interval])) / scalar(count(windows_hyperv_hypervisor_logical_processor_time_total{job=~"$job", instance="$instance", state="idle"}))', 'A') - + b.query.withLegendFormat('{{state}}'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - max: 1, - min: 0, - }), - - b.panel.new(70, 'CPU usage per VM', 'timeseries') - + b.panel.withDescription('Virtual processor run time of each VM as a share of all logical processors of the host.') - + b.panel.withQueries([ - b.query.new('sum by (vm) (rate(windows_hyperv_hypervisor_virtual_processor_run_time_total{job=~"$job", instance="$instance"}[$__rate_interval])) / scalar(max(windows_hyperv_host_logical_processor_count{job=~"$job", instance="$instance"}))', 'A') - + b.query.withLegendFormat('{{vm}}'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - min: 0, - }) - + b.panel.withOptions({ - legend: { - sortBy: 'Mean', - sortDesc: true, - }, - }), - - b.panel.new(72, 'Memory assigned to VMs', 'timeseries') - + b.panel.withDescription('Physical memory currently assigned to each VM with dynamic memory.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_dynamic_memory_vm_physical_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('{{vm}}'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - min: 0, - unit: 'bytes', - }) - + b.panel.withOptions({ - legend: { - sortBy: 'Mean', - sortDesc: true, - }, - }), - - b.panel.new(73, 'VM memory pressure', 'timeseries') - + b.panel.withDescription('Memory a VM needs as a share of the memory it has. Above 100% the VM needs more memory than it is assigned.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_dynamic_memory_vm_pressure_current_ratio{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('{{vm}}'), - ]) - + b.panel.withDefaults({ - custom: { - thresholdsStyle: { - mode: 'dashed', - }, - }, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'red', - value: 1, - }, - ], - }, - }), - - b.panel.new(74, 'Memory available for VMs', 'timeseries') - + b.panel.withDescription('Memory the dynamic memory balancer can still hand out to VMs.') - + b.panel.withQueries([ - b.query.new('windows_hyperv_dynamic_memory_balancer_available_memory_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('{{balancer}}'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - b.panel.new(76, 'Virtual disk throughput', 'timeseries') - + b.panel.withDescription('Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_virtual_storage_device_bytes_written{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{device}} write'), - b.query.new('rate(windows_hyperv_virtual_storage_device_bytes_read{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{device}} read'), - ]) - + b.panel.withDefaults({ - unit: 'Bps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', - }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, - ]), - - b.panel.new(77, 'Virtual disk IOPS', 'timeseries') - + b.panel.withDescription('Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_virtual_storage_device_operations_written_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{device}} write'), - b.query.new('rate(windows_hyperv_virtual_storage_device_operations_read_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{device}} read'), - ]) - + b.panel.withDefaults({ - unit: 'iops', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* read$', - }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, - ]), - - b.panel.new(78, 'Virtual disk latency and errors', 'timeseries') - + b.panel.withDescription('Average I/O latency of each virtual disk: the total I/O latency divided by the number of completed I/O transfers. Errors use the right axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_virtual_storage_device_io_latency_seconds_total{job=~"$job", instance="$instance"}[$__rate_interval]) / rate(windows_hyperv_virtual_storage_device_throughput_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{device}} latency'), - b.query.new('rate(windows_hyperv_virtual_storage_device_error_count_total{job=~"$job", instance="$instance"}[$__rate_interval]) > 0', 'B') - + b.query.withLegendFormat('{{device}} errors'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 's', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* errors', - }, - properties: [ - { - id: 'unit', - value: 'ops', - }, - { - id: 'custom.axisPlacement', - value: 'right', - }, - { - id: 'color', - value: { - fixedColor: 'red', - mode: 'fixed', + properties: [ + { + id: 'unit', + value: 'ops', }, - }, - ], - }, - ]), - - b.panel.new(80, 'Virtual switch throughput', 'timeseries') - + b.panel.withDescription('Received traffic is drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_vswitch_bytes_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'A') - + b.query.withLegendFormat('{{vswitch}} sent'), - b.query.new('rate(windows_hyperv_vswitch_bytes_received_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'B') - + b.query.withLegendFormat('{{vswitch}} received'), - ]) - + b.panel.withDefaults({ - unit: 'bps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* received$', + { + id: 'custom.axisPlacement', + value: 'right', + }, + { + id: 'color', + value: { + fixedColor: 'red', + mode: 'fixed', + }, + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + ]), + + b.panel.new(80, 'Virtual switch throughput', 'timeseries') + + b.panel.withDescription('Received traffic is drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_vswitch_bytes_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'A') + + b.query.withLegendFormat('{{vswitch}} sent'), + b.query.new('rate(windows_hyperv_vswitch_bytes_received_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'B') + + b.query.withLegendFormat('{{vswitch}} received'), + ]) + + b.panel.withDefaults({ + unit: 'bps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* received$', }, - ], - }, - ]), - - b.panel.new(81, 'Virtual switch dropped packets', 'timeseries') - + b.panel.withDescription('Incoming and outgoing packets dropped per second by each Hyper-V virtual switch. Correlate sustained drops with network load, resource pressure and switch policies; this requires the optional hyperv collector.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_vswitch_dropped_packets_incoming_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{vswitch}} incoming'), - b.query.new('rate(windows_hyperv_vswitch_dropped_packets_outcoming_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{vswitch}} outgoing'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'pps', - }), - - b.panel.new(82, 'VM network adapter throughput', 'timeseries') - + b.panel.withDescription('Received traffic is drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_hyperv_virtual_network_adapter_sent_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'A') - + b.query.withLegendFormat('{{adapter}} sent'), - b.query.new('rate(windows_hyperv_virtual_network_adapter_received_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'B') - + b.query.withLegendFormat('{{adapter}} received'), - ]) - + b.panel.withDefaults({ - unit: 'bps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* received$', + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + ]), + + b.panel.new(81, 'Virtual switch dropped packets', 'timeseries') + + b.panel.withDescription('Incoming and outgoing packets dropped per second by each Hyper-V virtual switch. Correlate sustained drops with network load, resource pressure and switch policies; this requires the optional hyperv collector.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_vswitch_dropped_packets_incoming_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{vswitch}} incoming'), + b.query.new('rate(windows_hyperv_vswitch_dropped_packets_outcoming_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{vswitch}} outgoing'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'pps', + }), + + b.panel.new(82, 'VM network adapter throughput', 'timeseries') + + b.panel.withDescription('Received traffic is drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_hyperv_virtual_network_adapter_sent_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'A') + + b.query.withLegendFormat('{{adapter}} sent'), + b.query.new('rate(windows_hyperv_virtual_network_adapter_received_bytes_total{job=~"$job", instance="$instance"}[$__rate_interval]) * 8', 'B') + + b.query.withLegendFormat('{{adapter}} received'), + ]) + + b.panel.withDefaults({ + unit: 'bps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* received$', }, - ], - }, - ]), - ] -) + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + ] + ) diff --git a/contrib/mixin/dashboards/memory.libsonnet b/contrib/mixin/dashboards/memory.libsonnet index 376b8dd1..a3af6f67 100644 --- a/contrib/mixin/dashboards/memory.libsonnet +++ b/contrib/mixin/dashboards/memory.libsonnet @@ -1,135 +1,148 @@ local b = import 'builders.libsonnet'; +local metric(name) = 'windows_memory_' + name + '{job=~"$job", instance="$instance"}'; -b.tab( - 'Memory', - b.grid([ - b.place(32, 0, 0, 12, 8), - b.place(33, 12, 0, 12, 8), - b.place(34, 0, 8, 12, 8), - b.place(35, 12, 8, 12, 8), - ]), - [ - b.panel.new(32, 'Physical memory', 'timeseries') - + b.panel.withDescription('Available memory is the standby (cache), free and zero page lists.') - + b.panel.withQueries([ - b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"} - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('used'), - b.query.new('windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('available'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', - }, - }, - min: 0, - unit: 'bytes', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'used', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'orange', - mode: 'fixed', - }, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'available', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'green', - mode: 'fixed', - }, - }, - ], - }, +function(on) + b.tab( + 'Memory', + b.rows([ + if on('memory') then b.summary([166, 167, 168, 169, 170, 171]), + if on('memory') then b.row('Physical memory and commit', b.flow([[32, 12, 8], [33, 12, 8]])), + if on('memory') then b.row('Paging and kernel memory', b.flow([[34, 12, 8], [35, 12, 8]])), ]), + [ + b.stat(166, 'Memory used', 'Share of physical memory in use: total minus available memory.', '1 - ' + metric('physical_free_bytes') + ' / ' + metric('physical_total_bytes'), 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(167, 'Available', 'Physical memory available to processes: the standby, free and zero page lists.', metric('physical_free_bytes'), 'bytes') + + b.panel.withDefaults({ decimals: 1 }), + b.stat(168, 'Commit used', 'Committed virtual memory as a share of the commit limit. Allocations fail at 100%.', metric('committed_bytes') + ' / ' + metric('commit_limit'), 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, max: 1, min: 0 }), + b.stat(169, 'Page reads', 'Hard page faults read from disk per second. Sustained page reads indicate memory pressure.', 'rate(' + metric('swap_page_reads_total') + '[$__rate_interval])', 'ops'), + b.stat(170, 'Nonpaged pool', 'Kernel memory that cannot be paged out. Steady growth can indicate a driver leak.', metric('pool_nonpaged_bytes'), 'bytes') + + b.panel.withDefaults({ decimals: 1 }), + b.stat(171, 'System cache', 'Physical memory used by the file system cache.', metric('cache_bytes'), 'bytes') + + b.panel.withDefaults({ decimals: 1 }), - b.panel.new(33, 'Commit charge', 'timeseries') - + b.panel.withDescription('Committed virtual memory against the commit limit (physical memory + page files).') - + b.panel.withQueries([ - b.query.new('windows_memory_committed_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('committed'), - b.query.new('windows_memory_commit_limit{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('limit'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'limit', + b.panel.new(32, 'Physical memory', 'timeseries') + + b.panel.withDescription('Available memory is the standby (cache), free and zero page lists.') + + b.panel.withQueries([ + b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"} - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('used'), + b.query.new('windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('available'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', + }, }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'red', - mode: 'fixed', + min: 0, + unit: 'bytes', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'used', + }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'orange', + mode: 'fixed', + }, }, + ], + }, + { + matcher: { + id: 'byName', + options: 'available', }, - { - id: 'custom.fillOpacity', - value: 0, - }, - { - id: 'custom.lineStyle', - value: { - dash: [ - 10, - 10, - ], - fill: 'dash', + properties: [ + { + id: 'color', + value: { + fixedColor: 'green', + mode: 'fixed', + }, }, + ], + }, + ]), + + b.panel.new(33, 'Commit charge', 'timeseries') + + b.panel.withDescription('Committed virtual memory against the commit limit (physical memory + page files).') + + b.panel.withQueries([ + b.query.new('windows_memory_committed_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('committed'), + b.query.new('windows_memory_commit_limit{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('limit'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'limit', }, - ], - }, - ]), + properties: [ + { + id: 'color', + value: { + fixedColor: 'red', + mode: 'fixed', + }, + }, + { + id: 'custom.fillOpacity', + value: 0, + }, + { + id: 'custom.lineStyle', + value: { + dash: [ + 10, + 10, + ], + fill: 'dash', + }, + }, + ], + }, + ]), - b.panel.new(34, 'Paging', 'timeseries') - + b.panel.withDescription('Hard page faults read from or written to disk. Sustained page reads indicate memory pressure.') - + b.panel.withQueries([ - b.query.new('rate(windows_memory_swap_page_reads_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('page reads'), - b.query.new('rate(windows_memory_swap_page_writes_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('page writes'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'ops', - }), + b.panel.new(34, 'Paging', 'timeseries') + + b.panel.withDescription('Hard page faults read from or written to disk. Sustained page reads indicate memory pressure.') + + b.panel.withQueries([ + b.query.new('rate(windows_memory_swap_page_reads_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('page reads'), + b.query.new('rate(windows_memory_swap_page_writes_total{job=~"$job", instance="$instance"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('page writes'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'ops', + }), - b.panel.new(35, 'Kernel pools and cache', 'timeseries') - + b.panel.withDescription('A steadily growing nonpaged pool usually means a driver leaks memory.') - + b.panel.withQueries([ - b.query.new('windows_memory_pool_nonpaged_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('nonpaged pool'), - b.query.new('windows_memory_pool_paged_bytes{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('paged pool'), - b.query.new('windows_memory_cache_bytes{job=~"$job", instance="$instance"}', 'C') - + b.query.withLegendFormat('system cache'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'bytes', - }), - ] -) + b.panel.new(35, 'Kernel pools and cache', 'timeseries') + + b.panel.withDescription('A steadily growing nonpaged pool usually means a driver leaks memory.') + + b.panel.withQueries([ + b.query.new('windows_memory_pool_nonpaged_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('nonpaged pool'), + b.query.new('windows_memory_pool_paged_bytes{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('paged pool'), + b.query.new('windows_memory_cache_bytes{job=~"$job", instance="$instance"}', 'C') + + b.query.withLegendFormat('system cache'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'bytes', + }), + ] + ) diff --git a/contrib/mixin/dashboards/network.libsonnet b/contrib/mixin/dashboards/network.libsonnet index 5e8df8a7..617d62a3 100644 --- a/contrib/mixin/dashboards/network.libsonnet +++ b/contrib/mixin/dashboards/network.libsonnet @@ -1,218 +1,233 @@ local b = import 'builders.libsonnet'; +local nic(name) = 'windows_net_' + name + '{job=~"$job", instance="$instance", nic=~"$nic"}'; +local sumRate(metric) = 'sum(rate(' + metric + '[$__rate_interval]))'; +local tcp(name) = 'windows_tcp_' + name + '{job=~"$job", instance="$instance"}'; -b.tab( - 'Network', - b.rows([ - b.row('Interfaces', b.grid([b.place(45, 0, 0, 12, 8), b.place(46, 12, 0, 12, 8), b.place(47, 0, 8, 12, 8), b.place(48, 12, 8, 12, 8)])), - b.row('TCP', b.grid([b.place(140, 0, 0, 12, 8), b.place(141, 12, 0, 12, 8), b.place(142, 0, 8, 12, 8), b.place(143, 12, 8, 12, 8)])), - b.row('UDP', b.grid([b.place(144, 0, 0, 12, 8), b.place(145, 12, 0, 12, 8)])), - ]), - [ - b.panel.new(45, 'Network throughput', 'timeseries') - + b.panel.withDescription('Received traffic is drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_net_bytes_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) * 8', 'A') - + b.query.withLegendFormat('{{nic}} sent'), - b.query.new('rate(windows_net_bytes_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) * 8', 'B') - + b.query.withLegendFormat('{{nic}} received'), - ]) - + b.panel.withDefaults({ - unit: 'bps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* received$', - }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, +function(on) + b.tab( + 'Network', + b.rows([ + b.summary([if on('net') then 178, if on('net') then 179, if on('net') then 180, if on('net') then 181, if on('tcp') then 182, if on('tcp') then 183]), + if on('net') then b.row('Interfaces', b.flow([[45, 12, 8], [46, 12, 8], [47, 12, 8], [48, 12, 8]])), + if on('tcp') then b.row('TCP', b.flow([[140, 12, 8], [141, 12, 8], [142, 12, 8], [143, 12, 8]])), + if on('udp') then b.row('UDP', b.flow([[144, 12, 8], [145, 12, 8]])), ]), + [ + b.stat(178, 'Sent', 'Bits sent per second, summed over the selected interfaces.', sumRate(nic('bytes_sent_total')) + ' * 8', 'bps'), + b.stat(179, 'Received', 'Bits received per second, summed over the selected interfaces.', sumRate(nic('bytes_received_total')) + ' * 8', 'bps'), + b.stat(180, 'Utilization', 'Utilization of the busiest selected interface: bytes sent and received per second against its current bandwidth.', 'max(rate(' + nic('bytes_total') + '[$__rate_interval]) / (' + nic('current_bandwidth_bytes') + ' > 0))', 'percentunit', steps=b.levels(0.8, 0.9)) + + b.panel.withDefaults({ decimals: 1, min: 0 }), + b.stat(181, 'Errors', 'Packets per second that were discarded or had errors, inbound and outbound, summed over the selected interfaces.', std.join(' + ', [sumRate(nic(name)) for name in ['packets_received_errors_total', 'packets_received_discarded_total', 'packets_outbound_errors_total', 'packets_outbound_discarded_total']]), 'pps', steps=b.levels(1, 10)) + + b.panel.withDefaults({ min: 0 }), + b.stat(182, 'TCP sessions', 'TCP connections in the established or close-wait state, IPv4 and IPv6. Requires the tcp collector.', 'sum(' + tcp('connections_established') + ')', 'short'), + b.stat(183, 'Retransmits', 'Retransmitted segments as a share of sent segments. A rate that stays above a few percent points to packet loss. Requires the tcp collector.', '(' + sumRate(tcp('segments_retransmitted_total')) + ' / (' + sumRate(tcp('segments_sent_total')) + ' > 0)) or (0 * ' + sumRate(tcp('segments_sent_total')) + ')', 'percentunit', steps=b.levels(0.01, 0.05)) + + b.panel.withDefaults({ decimals: 2, min: 0 }), - b.panel.new(46, 'Network utilization', 'timeseries') - + b.panel.withDescription('Sent plus received traffic relative to the link speed reported by the adapter. Interfaces without a link speed are not shown.') - + b.panel.withQueries([ - b.query.new('rate(windows_net_bytes_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) / (windows_net_current_bandwidth_bytes{job=~"$job", instance="$instance", nic=~"$nic"} > 0)', 'A') - + b.query.withLegendFormat('{{nic}}'), - ]) - + b.panel.withDefaults({ - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, + b.panel.new(45, 'Network throughput', 'timeseries') + + b.panel.withDescription('Received traffic is drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_net_bytes_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) * 8', 'A') + + b.query.withLegendFormat('{{nic}} sent'), + b.query.new('rate(windows_net_bytes_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) * 8', 'B') + + b.query.withLegendFormat('{{nic}} received'), + ]) + + b.panel.withDefaults({ + unit: 'bps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* received$', }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - }), - - b.panel.new(47, 'Packets', 'timeseries') - + b.panel.withDescription('Received packets are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('rate(windows_net_packets_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{nic}} sent'), - b.query.new('rate(windows_net_packets_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{nic}} received'), - ]) - + b.panel.withDefaults({ - unit: 'pps', - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: '.* received$', + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', - }, - ], - }, - ]), + ]), - b.panel.new(48, 'Network errors and discards', 'timeseries') - + b.panel.withDescription('Receive and transmit packet errors, discarded packets and received packets with unknown protocols per second for each selected interface. Errors can indicate link or driver problems; discards can reflect buffer pressure or filtering.') - + b.panel.withQueries([ - b.query.new('rate(windows_net_packets_received_errors_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'A') - + b.query.withLegendFormat('{{nic}} received errors'), - b.query.new('rate(windows_net_packets_received_discarded_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'B') - + b.query.withLegendFormat('{{nic}} received discarded'), - b.query.new('rate(windows_net_packets_outbound_errors_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'C') - + b.query.withLegendFormat('{{nic}} outbound errors'), - b.query.new('rate(windows_net_packets_outbound_discarded_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'D') - + b.query.withLegendFormat('{{nic}} outbound discarded'), - b.query.new('rate(windows_net_packets_received_unknown_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'E') - + b.query.withLegendFormat('{{nic}} received unknown protocol'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'pps', - }), - - b.panel.new(140, 'TCP connections by state', 'timeseries') - + b.panel.withDescription('Needs the tcp collector, which is not enabled by default. A growing CLOSE_WAIT count means an application does not close its sockets. Many TIME_WAIT connections can use up the dynamic port range for outgoing connections.') - + b.panel.withQueries([ - b.query.new('sum by (state) (windows_tcp_connections_state_count{job=~"$job", instance="$instance"})', 'A') - + b.query.withLegendFormat('{{state}}'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'short', - }) - + b.panel.withOverrides([]), - - b.panel.new(141, 'TCP connections opened, failed and reset', 'timeseries') - + b.panel.withDescription('Outgoing (active) and incoming (passive) connections opened per second, connection attempts that failed, and established connections that were reset.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_tcp_connections_active_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('opened outgoing'), - b.query.new('sum(rate(windows_tcp_connections_passive_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('accepted incoming'), - b.query.new('sum(rate(windows_tcp_connection_failures_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') - + b.query.withLegendFormat('failed'), - b.query.new('sum(rate(windows_tcp_connections_reset_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'D') - + b.query.withLegendFormat('reset'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'ops', - }) - + b.panel.withOverrides([{ matcher: { id: 'byName', options: 'failed' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }, { matcher: { id: 'byName', options: 'reset' }, properties: [{ id: 'color', value: { fixedColor: 'orange', mode: 'fixed' } }] }]), - - b.panel.new(142, 'TCP segments', 'timeseries') - + b.panel.withDescription('Received segments are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_tcp_segments_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('sent'), - b.query.new('sum(rate(windows_tcp_segments_received_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('received'), - b.query.new('sum(rate(windows_tcp_segments_retransmitted_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') - + b.query.withLegendFormat('retransmitted'), - ]) - + b.panel.withDefaults({ - unit: 'pps', - }) - + b.panel.withOverrides([{ matcher: { id: 'byRegexp', options: 'received' }, properties: [{ id: 'custom.transform', value: 'negative-Y' }] }, { matcher: { id: 'byName', options: 'retransmitted' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }]), - - b.panel.new(143, 'TCP retransmission rate', 'timeseries') - + b.panel.withDescription('Retransmitted segments as a share of sent segments. A rate that stays above a few percent points to packet loss on the network.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_tcp_segments_retransmitted_total{job=~"$job", instance="$instance"}[$__rate_interval])) / sum(rate(windows_tcp_segments_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('retransmitted'), - ]) - + b.panel.withDefaults({ - custom: { - thresholdsStyle: { - mode: 'dashed', + b.panel.new(46, 'Network utilization', 'timeseries') + + b.panel.withDescription('Sent plus received traffic relative to the link speed reported by the adapter. Interfaces without a link speed are not shown.') + + b.panel.withQueries([ + b.query.new('rate(windows_net_bytes_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval]) / (windows_net_current_bandwidth_bytes{job=~"$job", instance="$instance", nic=~"$nic"} > 0)', 'A') + + b.query.withLegendFormat('{{nic}}'), + ]) + + b.panel.withDefaults({ + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], }, - }, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 0.01, - }, - { - color: 'red', - value: 0.05, - }, - ], - }, - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([]), + }), - b.panel.new(144, 'UDP datagrams', 'timeseries') - + b.panel.withDescription('Needs the udp collector, which is not enabled by default. Received datagrams are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_udp_datagram_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('sent'), - b.query.new('sum(rate(windows_udp_datagram_received_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('received'), - ]) - + b.panel.withDefaults({ - unit: 'pps', - }) - + b.panel.withOverrides([{ matcher: { id: 'byRegexp', options: 'received' }, properties: [{ id: 'custom.transform', value: 'negative-Y' }] }]), + b.panel.new(47, 'Packets', 'timeseries') + + b.panel.withDescription('Received packets are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('rate(windows_net_packets_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{nic}} sent'), + b.query.new('rate(windows_net_packets_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{nic}} received'), + ]) + + b.panel.withDefaults({ + unit: 'pps', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: '.* received$', + }, + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), - b.panel.new(145, 'UDP errors', 'timeseries') - + b.panel.withDescription('Received datagrams that could not be delivered, and datagrams for a port that no application listens on.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_udp_datagram_received_errors_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('received errors'), - b.query.new('sum(rate(windows_udp_datagram_no_port_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('no listening port'), - ]) - + b.panel.withDefaults({ - min: 0, - unit: 'pps', - }) - + b.panel.withOverrides([{ matcher: { id: 'byName', options: 'received errors' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }]), - ] -) + b.panel.new(48, 'Network errors and discards', 'timeseries') + + b.panel.withDescription('Receive and transmit packet errors, discarded packets and received packets with unknown protocols per second for each selected interface. Errors can indicate link or driver problems; discards can reflect buffer pressure or filtering.') + + b.panel.withQueries([ + b.query.new('rate(windows_net_packets_received_errors_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'A') + + b.query.withLegendFormat('{{nic}} received errors'), + b.query.new('rate(windows_net_packets_received_discarded_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'B') + + b.query.withLegendFormat('{{nic}} received discarded'), + b.query.new('rate(windows_net_packets_outbound_errors_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'C') + + b.query.withLegendFormat('{{nic}} outbound errors'), + b.query.new('rate(windows_net_packets_outbound_discarded_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'D') + + b.query.withLegendFormat('{{nic}} outbound discarded'), + b.query.new('rate(windows_net_packets_received_unknown_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])', 'E') + + b.query.withLegendFormat('{{nic}} received unknown protocol'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'pps', + }), + + b.panel.new(140, 'TCP connections by state', 'timeseries') + + b.panel.withDescription('Needs the tcp collector, which is not enabled by default. A growing CLOSE_WAIT count means an application does not close its sockets. Many TIME_WAIT connections can use up the dynamic port range for outgoing connections.') + + b.panel.withQueries([ + b.query.new('sum by (state) (windows_tcp_connections_state_count{job=~"$job", instance="$instance"})', 'A') + + b.query.withLegendFormat('{{state}}'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'short', + }) + + b.panel.withOverrides([]), + + b.panel.new(141, 'TCP connections opened, failed and reset', 'timeseries') + + b.panel.withDescription('Outgoing (active) and incoming (passive) connections opened per second, connection attempts that failed, and established connections that were reset.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_tcp_connections_active_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('opened outgoing'), + b.query.new('sum(rate(windows_tcp_connections_passive_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('accepted incoming'), + b.query.new('sum(rate(windows_tcp_connection_failures_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') + + b.query.withLegendFormat('failed'), + b.query.new('sum(rate(windows_tcp_connections_reset_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'D') + + b.query.withLegendFormat('reset'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'ops', + }) + + b.panel.withOverrides([{ matcher: { id: 'byName', options: 'failed' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }, { matcher: { id: 'byName', options: 'reset' }, properties: [{ id: 'color', value: { fixedColor: 'orange', mode: 'fixed' } }] }]), + + b.panel.new(142, 'TCP segments', 'timeseries') + + b.panel.withDescription('Received segments are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_tcp_segments_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('sent'), + b.query.new('sum(rate(windows_tcp_segments_received_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('received'), + b.query.new('sum(rate(windows_tcp_segments_retransmitted_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'C') + + b.query.withLegendFormat('retransmitted'), + ]) + + b.panel.withDefaults({ + unit: 'pps', + }) + + b.panel.withOverrides([{ matcher: { id: 'byRegexp', options: 'received' }, properties: [{ id: 'custom.transform', value: 'negative-Y' }] }, { matcher: { id: 'byName', options: 'retransmitted' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }]), + + b.panel.new(143, 'TCP retransmission rate', 'timeseries') + + b.panel.withDescription('Retransmitted segments as a share of sent segments. A rate that stays above a few percent points to packet loss on the network.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_tcp_segments_retransmitted_total{job=~"$job", instance="$instance"}[$__rate_interval])) / sum(rate(windows_tcp_segments_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('retransmitted'), + ]) + + b.panel.withDefaults({ + custom: { + thresholdsStyle: { + mode: 'dashed', + }, + }, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 0.01, + }, + { + color: 'red', + value: 0.05, + }, + ], + }, + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([]), + + b.panel.new(144, 'UDP datagrams', 'timeseries') + + b.panel.withDescription('Needs the udp collector, which is not enabled by default. Received datagrams are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_udp_datagram_sent_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('sent'), + b.query.new('sum(rate(windows_udp_datagram_received_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('received'), + ]) + + b.panel.withDefaults({ + unit: 'pps', + }) + + b.panel.withOverrides([{ matcher: { id: 'byRegexp', options: 'received' }, properties: [{ id: 'custom.transform', value: 'negative-Y' }] }]), + + b.panel.new(145, 'UDP errors', 'timeseries') + + b.panel.withDescription('Received datagrams that could not be delivered, and datagrams for a port that no application listens on.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_udp_datagram_received_errors_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('received errors'), + b.query.new('sum(rate(windows_udp_datagram_no_port_total{job=~"$job", instance="$instance"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('no listening port'), + ]) + + b.panel.withDefaults({ + min: 0, + unit: 'pps', + }) + + b.panel.withOverrides([{ matcher: { id: 'byName', options: 'received errors' }, properties: [{ id: 'color', value: { fixedColor: 'red', mode: 'fixed' } }] }]), + ] + ) diff --git a/contrib/mixin/dashboards/overview.libsonnet b/contrib/mixin/dashboards/overview.libsonnet index c339921c..659f9d92 100644 --- a/contrib/mixin/dashboards/overview.libsonnet +++ b/contrib/mixin/dashboards/overview.libsonnet @@ -1,497 +1,488 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Overview', - b.grid([ - b.place(10, 0, 0, 4, 4), - b.place(11, 4, 0, 3, 4), - b.place(12, 7, 0, 2, 4), - b.place(13, 9, 0, 2, 4), - b.place(14, 11, 0, 3, 4), - b.place(15, 14, 0, 3, 4), - b.place(16, 17, 0, 3, 4), - b.place(17, 20, 0, 4, 4), - b.place(18, 0, 4, 12, 8), - b.place(19, 12, 4, 12, 8), - b.place(20, 0, 12, 8, 8), - b.place(21, 8, 12, 8, 8), - b.place(22, 16, 12, 8, 8), - ]), - [ - b.panel.new(10, 'Operating system', 'stat') - + b.panel.withDescription('Windows product name and version reported by the os collector. Use this to distinguish hosts when investigating version-specific behavior.') - + b.panel.withQueries([ - b.query.new('windows_os_info{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withDefaults({ - unit: '', - }) - + b.panel.withOptions({ - colorMode: 'none', - reduceOptions: { - fields: '/^product$/', - }, - textMode: 'value', - }), - - b.panel.new(11, 'Uptime', 'stat') - + b.panel.withDescription('Time since the last boot.') - + b.panel.withQueries([ - b.query.new('time() - windows_system_boot_time_timestamp{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'orange', - value: null, - }, - { - color: 'text', - value: 3600, - }, - ], - }, - unit: 'dtdurations', - }), - - b.panel.new(12, 'CPUs', 'stat') - + b.panel.withDescription('Number of logical processors available to Windows, including SMT threads. This is the logical CPU count rather than the number of physical sockets.') - + b.panel.withQueries([ - b.query.new('windows_cpu_logical_processor{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), +function(on) + b.tab( + 'Overview', + b.rows([ + b.row('Summary', b.flow([if on('os') then [10, 4, 4], if on('system') then [11, 3, 4], if on('cpu') then [12, 2, 4], if on('memory') then [13, 2, 4], if on('cpu') then [14, 3, 4], if on('memory') then [15, 3, 4], if on('memory') then [16, 3, 4], if on('service') then [17, 4, 4]])), + b.row('CPU and memory', b.flow([if on('cpu') then [18, 12, 8], if on('memory') then [19, 12, 8]])), + b.row('Storage and network', b.flow([if on('logical_disk') then [20, 8, 8], if on('logical_disk') then [21, 8, 8], if on('net') then [22, 8, 8]])), ]), - - b.panel.new(13, 'RAM', 'stat') - + b.panel.withDescription('Total physical memory visible to Windows in bytes. Compare with used memory and commit charge when investigating memory pressure.') - + b.panel.withQueries([ - b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - decimals: 1, - unit: 'bytes', - }), - - b.panel.new(14, 'CPU busy', 'stat') - + b.panel.withDescription('Percentage of non-idle CPU time averaged across logical processors over the rate interval. Sustained high values together with a growing processor queue can indicate CPU contention.') - + b.panel.withQueries([ - b.query.new('100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 1)))', 'A'), - ]) - + b.panel.withDefaults({ - decimals: 1, - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(15, 'Memory used', 'stat') - + b.panel.withDescription('Percentage of physical memory in use, calculated as total minus available memory. This differs from commit charge, which measures promised virtual memory against the commit limit.') - + b.panel.withQueries([ - b.query.new('100 * (1 - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"} / windows_memory_physical_total_bytes{job=~"$job", instance="$instance"})', 'A'), - ]) - + b.panel.withDefaults({ - decimals: 1, - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(16, 'Commit used', 'stat') - + b.panel.withDescription('Committed virtual memory as a share of the commit limit (physical memory + page files). Allocations fail at 100%.') - + b.panel.withQueries([ - b.query.new('100 * windows_memory_committed_bytes{job=~"$job", instance="$instance"} / windows_memory_commit_limit{job=~"$job", instance="$instance"}', 'A'), - ]) - + b.panel.withDefaults({ - decimals: 1, - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - graphMode: 'area', - }), - - b.panel.new(17, 'Stopped auto services', 'stat') - + b.panel.withDescription('Services with start mode "auto" that are not running. See the Services tab for names.') - + b.panel.withQueries([ - b.query.new('count(windows_service_state{job=~"$job", instance="$instance", state="running"} == 0 and on (name) windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1) or vector(0)', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 1, - }, - ], - }, - }), - - b.panel.new(18, 'CPU utilization', 'timeseries') - + b.panel.withDescription('Percentage of non-idle CPU time averaged across logical processors. This measures CPU time rather than the frequency-adjusted processor utility shown by Windows Task Manager.') - + b.panel.withQueries([ - b.query.new('100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 1)))', 'A') - + b.query.withLegendFormat('CPU busy'), - ]) - + b.panel.withDefaults({ - max: 100, - min: 0, - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], - }, - unit: 'percent', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }), - - b.panel.new(19, 'Physical memory', 'timeseries') - + b.panel.withDescription('Available memory is the standby (cache), free and zero page lists.') - + b.panel.withQueries([ - b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"} - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('used'), - b.query.new('windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('available'), - ]) - + b.panel.withDefaults({ - custom: { - fillOpacity: 40, - stacking: { - mode: 'normal', + [ + b.panel.new(10, 'Operating system', 'stat') + + b.panel.withDescription('Windows product name and version reported by the os collector. Use this to distinguish hosts when investigating version-specific behavior.') + + b.panel.withQueries([ + b.query.new('windows_os_info{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withDefaults({ + unit: '', + }) + + b.panel.withOptions({ + colorMode: 'none', + reduceOptions: { + fields: '/^product$/', }, - }, - min: 0, - unit: 'bytes', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'used', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'orange', - mode: 'fixed', + textMode: 'value', + }), + + b.panel.new(11, 'Uptime', 'stat') + + b.panel.withDescription('Time since the last boot.') + + b.panel.withQueries([ + b.query.new('time() - windows_system_boot_time_timestamp{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + thresholds: { + steps: [ + { + color: 'orange', + value: null, }, - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'available', - }, - properties: [ - { - id: 'color', - value: { - fixedColor: 'green', - mode: 'fixed', + { + color: 'text', + value: 3600, }, - }, - ], - }, - ]), + ], + }, + unit: 'dtdurations', + }), - b.panel.new(20, 'Volumes', 'table') - + b.panel.withDescription('Size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.') - + b.panel.withQueries([ - b.query.new('windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'B') - + b.query.withInstant() - + b.query.withFormat('table'), - b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'C') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'joinByField', - kind: 'Transformation', - spec: { - options: { - byField: 'volume', - mode: 'outer', + b.panel.new(12, 'CPUs', 'stat') + + b.panel.withDescription('Number of logical processors available to Windows, including SMT threads. This is the logical CPU count rather than the number of physical sockets.') + + b.panel.withQueries([ + b.query.new('windows_cpu_logical_processor{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]), + + b.panel.new(13, 'RAM', 'stat') + + b.panel.withDescription('Total physical memory visible to Windows in bytes. Compare with used memory and commit charge when investigating memory pressure.') + + b.panel.withQueries([ + b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + decimals: 1, + unit: 'bytes', + }), + + b.panel.new(14, 'CPU busy', 'stat') + + b.panel.withDescription('Percentage of non-idle CPU time averaged across logical processors over the rate interval. Sustained high values together with a growing processor queue can indicate CPU contention.') + + b.panel.withQueries([ + b.query.new('100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 1)))', 'A'), + ]) + + b.panel.withDefaults({ + decimals: 1, + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), + + b.panel.new(15, 'Memory used', 'stat') + + b.panel.withDescription('Percentage of physical memory in use, calculated as total minus available memory. This differs from commit charge, which measures promised virtual memory against the commit limit.') + + b.panel.withQueries([ + b.query.new('100 * (1 - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"} / windows_memory_physical_total_bytes{job=~"$job", instance="$instance"})', 'A'), + ]) + + b.panel.withDefaults({ + decimals: 1, + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), + + b.panel.new(16, 'Commit used', 'stat') + + b.panel.withDescription('Committed virtual memory as a share of the commit limit (physical memory + page files). Allocations fail at 100%.') + + b.panel.withQueries([ + b.query.new('100 * windows_memory_committed_bytes{job=~"$job", instance="$instance"} / windows_memory_commit_limit{job=~"$job", instance="$instance"}', 'A'), + ]) + + b.panel.withDefaults({ + decimals: 1, + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), + + b.panel.new(17, 'Stopped auto services', 'stat') + + b.panel.withDescription('Services with start mode "auto" that are not running. See the Services tab for names.') + + b.panel.withQueries([ + b.query.new('count(windows_service_state{job=~"$job", instance="$instance", state="running"} == 0 and on (name) windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1) or vector(0)', 'A') + + b.query.withInstant(), + ]) + + b.panel.withDefaults({ + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 1, + }, + ], + }, + }), + + b.panel.new(18, 'CPU utilization', 'timeseries') + + b.panel.withDescription('Percentage of non-idle CPU time averaged across logical processors. This measures CPU time rather than the frequency-adjusted processor utility shown by Windows Task Manager.') + + b.panel.withQueries([ + b.query.new('100 * (1 - avg by (instance) (clamp_max(rate(windows_cpu_time_total{job=~"$job", instance="$instance", mode="idle"}[$__rate_interval]), 1)))', 'A') + + b.query.withLegendFormat('CPU busy'), + ]) + + b.panel.withDefaults({ + max: 100, + min: 0, + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + unit: 'percent', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }), + + b.panel.new(19, 'Physical memory', 'timeseries') + + b.panel.withDescription('Available memory is the standby (cache), free and zero page lists.') + + b.panel.withQueries([ + b.query.new('windows_memory_physical_total_bytes{job=~"$job", instance="$instance"} - windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('used'), + b.query.new('windows_memory_physical_free_bytes{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('available'), + ]) + + b.panel.withDefaults({ + custom: { + fillOpacity: 40, + stacking: { + mode: 'normal', }, }, - }, - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - 'Time 2': true, - 'Time 3': true, - __name__: true, - instance: true, - 'instance 1': true, - 'instance 2': true, - 'instance 3': true, - job: true, - 'job 1': true, - 'job 2': true, - 'job 3': true, - port: true, - 'port 1': true, - 'port 2': true, - 'port 3': true, + min: 0, + unit: 'bytes', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', + }, + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'used', + }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'orange', + mode: 'fixed', + }, }, - includeByName: {}, - indexByName: { - 'Value #A': 1, - 'Value #B': 2, - 'Value #C': 3, - volume: 0, + ], + }, + { + matcher: { + id: 'byName', + options: 'available', + }, + properties: [ + { + id: 'color', + value: { + fixedColor: 'green', + mode: 'fixed', + }, }, - renameByName: { - 'Value #A': 'Size', - 'Value #B': 'Free', - 'Value #C': 'Used', - volume: 'Volume', + ], + }, + ]), + + b.panel.new(20, 'Volumes', 'table') + + b.panel.withDescription('Size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.') + + b.panel.withQueries([ + b.query.new('windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"}', 'B') + + b.query.withInstant() + + b.query.withFormat('table'), + b.query.new('100 * (1 - windows_logical_disk_free_bytes{job=~"$job", instance="$instance", volume=~"$volume"} / windows_logical_disk_size_bytes{job=~"$job", instance="$instance", volume=~"$volume"})', 'C') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ + { + group: 'joinByField', + kind: 'Transformation', + spec: { + options: { + byField: 'volume', + mode: 'outer', }, }, }, - }, - ]) - + b.panel.withOverrides([ - { - matcher: { - id: 'byName', - options: 'Value #A', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #B', - }, - properties: [ - { - id: 'unit', - value: 'bytes', - }, - ], - }, - { - matcher: { - id: 'byName', - options: 'Value #C', - }, - properties: [ - { - id: 'unit', - value: 'percent', - }, - { - id: 'min', - value: 0, - }, - { - id: 'max', - value: 100, - }, - { - id: 'thresholds', - value: { - mode: 'absolute', - steps: [ - { - color: 'green', - }, - { - color: 'orange', - value: 80, - }, - { - color: 'red', - value: 90, - }, - ], + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + 'Time 2': true, + 'Time 3': true, + __name__: true, + instance: true, + 'instance 1': true, + 'instance 2': true, + 'instance 3': true, + job: true, + 'job 1': true, + 'job 2': true, + 'job 3': true, + port: true, + 'port 1': true, + 'port 2': true, + 'port 3': true, + }, + includeByName: {}, + indexByName: { + 'Value #A': 1, + 'Value #B': 2, + 'Value #C': 3, + volume: 0, + }, + renameByName: { + 'Value #A': 'Size', + 'Value #B': 'Free', + 'Value #C': 'Used', + volume: 'Volume', + }, }, }, - { - id: 'color', - value: { - mode: 'continuous-GrYlRd', + }, + ]) + + b.panel.withOverrides([ + { + matcher: { + id: 'byName', + options: 'Value #A', + }, + properties: [ + { + id: 'unit', + value: 'bytes', }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #B', }, - { - id: 'custom.cellOptions', - value: { - mode: 'basic', - type: 'gauge', - valueDisplayMode: 'text', + properties: [ + { + id: 'unit', + value: 'bytes', }, + ], + }, + { + matcher: { + id: 'byName', + options: 'Value #C', }, - { - id: 'decimals', - value: 1, - }, - ], - }, - ]), + properties: [ + { + id: 'unit', + value: 'percent', + }, + { + id: 'min', + value: 0, + }, + { + id: 'max', + value: 100, + }, + { + id: 'thresholds', + value: { + mode: 'absolute', + steps: [ + { + color: 'green', + }, + { + color: 'orange', + value: 80, + }, + { + color: 'red', + value: 90, + }, + ], + }, + }, + { + id: 'color', + value: { + mode: 'continuous-GrYlRd', + }, + }, + { + id: 'custom.cellOptions', + value: { + mode: 'basic', + type: 'gauge', + valueDisplayMode: 'text', + }, + }, + { + id: 'decimals', + value: 1, + }, + ], + }, + ]), - b.panel.new(21, 'Disk throughput', 'timeseries') - + b.panel.withDescription('Sum over the selected volumes. Reads are drawn below the axis.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_logical_disk_write_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]))', 'A') - + b.query.withLegendFormat('write'), - b.query.new('sum(rate(windows_logical_disk_read_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]))', 'B') - + b.query.withLegendFormat('read'), - ]) - + b.panel.withDefaults({ - unit: 'Bps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: 'read', + b.panel.new(21, 'Disk throughput', 'timeseries') + + b.panel.withDescription('Sum over the selected volumes. Reads are drawn below the axis.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_logical_disk_write_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]))', 'A') + + b.query.withLegendFormat('write'), + b.query.new('sum(rate(windows_logical_disk_read_bytes_total{job=~"$job", instance="$instance", volume=~"$volume"}[$__rate_interval]))', 'B') + + b.query.withLegendFormat('read'), + ]) + + b.panel.withDefaults({ + unit: 'Bps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: 'read', }, - ], - }, - ]), + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), - b.panel.new(22, 'Network throughput', 'timeseries') - + b.panel.withDescription('Sum over the selected interfaces. Received traffic is drawn below the axis.') - + b.panel.withQueries([ - b.query.new('sum(rate(windows_net_bytes_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])) * 8', 'A') - + b.query.withLegendFormat('sent'), - b.query.new('sum(rate(windows_net_bytes_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])) * 8', 'B') - + b.query.withLegendFormat('received'), - ]) - + b.panel.withDefaults({ - unit: 'bps', - }) - + b.panel.withOptions({ - legend: { - calcs: [], - displayMode: 'list', - }, - }) - + b.panel.withOverrides([ - { - matcher: { - id: 'byRegexp', - options: 'received', + b.panel.new(22, 'Network throughput', 'timeseries') + + b.panel.withDescription('Sum over the selected interfaces. Received traffic is drawn below the axis.') + + b.panel.withQueries([ + b.query.new('sum(rate(windows_net_bytes_sent_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])) * 8', 'A') + + b.query.withLegendFormat('sent'), + b.query.new('sum(rate(windows_net_bytes_received_total{job=~"$job", instance="$instance", nic=~"$nic"}[$__rate_interval])) * 8', 'B') + + b.query.withLegendFormat('received'), + ]) + + b.panel.withDefaults({ + unit: 'bps', + }) + + b.panel.withOptions({ + legend: { + calcs: [], + displayMode: 'list', }, - properties: [ - { - id: 'custom.transform', - value: 'negative-Y', + }) + + b.panel.withOverrides([ + { + matcher: { + id: 'byRegexp', + options: 'received', }, - ], - }, - ]), - ] -) + properties: [ + { + id: 'custom.transform', + value: 'negative-Y', + }, + ], + }, + ]), + ] + ) diff --git a/contrib/mixin/dashboards/processes.libsonnet b/contrib/mixin/dashboards/processes.libsonnet index a7b5e8d3..197495a7 100644 --- a/contrib/mixin/dashboards/processes.libsonnet +++ b/contrib/mixin/dashboards/processes.libsonnet @@ -4,11 +4,9 @@ local selector = '{job=~"$job", instance="$instance", process=~"$process", proce local gauge(metric, at='') = 'windows_process_' + metric + selector + at; local rate(metric, at='') = 'rate(' + gauge(metric) + '[$__rate_interval]' + at + ')'; local sumRates(metric, at='') = 'sum by (process, process_id) (' + rate(metric, at) + ')'; -local stat(id, title, description, expr, unit) = - b.panel.new(id, title, 'stat') - + b.panel.withDescription(description + ' Includes all selected processes, regardless of Top N. Requires the process collector.') - + b.panel.withQueries([b.query.new(expr) + b.query.withInstant()]) - + b.panel.withDefaults({ min: 0, unit: unit }); +local stat(id, title, description, expr, unit, steps=null) = + b.stat(id, title, description + ' Includes all selected processes, regardless of Top N. Requires the process collector.', expr, unit, steps) + + b.panel.withDefaults({ min: 0 }); local graph(id, title, description, expr, ranking, unit) = b.panel.new(id, title, 'timeseries') + b.panel.withDescription(description + ' Shows the Top N selected processes ranked at the end of the time range; that set stays fixed throughout the graph. Requires the process collector.') @@ -19,39 +17,30 @@ local graph(id, title, description, expr, ranking, unit) = + b.panel.withQueryOptions({ maxDataPoints: 300 }) + b.panel.withDefaults({ min: 0, unit: unit }); -b.tab( - 'Processes', - b.grid([ - b.place(150, 0, 0, 4, 4), - b.place(151, 4, 0, 4, 4), - b.place(152, 8, 0, 4, 4), - b.place(153, 12, 0, 4, 4), - b.place(154, 16, 0, 4, 4), - b.place(155, 20, 0, 4, 4), - b.place(112, 0, 4, 12, 8), - b.place(113, 12, 4, 12, 8), - b.place(114, 0, 12, 12, 8), - b.place(115, 12, 12, 12, 8), - b.place(116, 0, 20, 12, 8), - b.place(117, 12, 20, 12, 8), - b.place(118, 0, 28, 12, 8), - b.place(119, 12, 28, 12, 8), - ]), - [ - stat(150, 'Processes', 'Number of distinct process IDs currently collected, excluding Idle.', 'count(count by (process_id) (' + gauge('info') + '))', 'short'), - stat(151, 'Threads', 'Total active threads in the selected processes.', 'sum(' + gauge('threads') + ')', 'short'), - stat(152, 'Handles', 'Total open handles in the selected processes.', 'sum(' + gauge('handles') + ')', 'short'), - stat(153, 'Process CPU busy', 'CPU time used by the selected processes as a share of all logical processors of the host, excluding Idle.', 'sum(' + rate('cpu_time_total') + ') / scalar(max(windows_cpu_logical_processor{job=~"$job", instance="$instance"}))', 'percentunit'), - stat(154, 'Private working set', 'Physical memory private to the selected processes; shared pages are excluded.', 'sum(' + gauge('working_set_private_bytes') + ')', 'bytes'), - stat(155, 'Private bytes', 'Total memory allocated by the selected processes that cannot be shared; it may include nonresident memory.', 'sum(' + gauge('private_bytes') + ')', 'bytes'), +function(on) + b.tab( + 'Processes', + b.rows([ + if on('process') then b.summary([150, 151, 152, if on('cpu') then 153, 154, 155]), + if on('process') then b.row('CPU and memory', b.flow([[112, 12, 8], [113, 12, 8], [114, 12, 8], [119, 12, 8]])), + if on('process') then b.row('I/O', b.flow([[115, 12, 8], [118, 12, 8]])), + if on('process') then b.row('Threads and handles', b.flow([[116, 12, 8], [117, 12, 8]])), + ]), + [ + stat(150, 'Processes', 'Number of distinct process IDs currently collected, excluding Idle.', 'count(count by (process_id) (' + gauge('info') + '))', 'short'), + stat(151, 'Threads', 'Total active threads in the selected processes.', 'sum(' + gauge('threads') + ')', 'short'), + stat(152, 'Handles', 'Total open handles in the selected processes.', 'sum(' + gauge('handles') + ')', 'short'), + stat(153, 'CPU busy', 'CPU time used by the selected processes as a share of all logical processors of the host, excluding Idle.', 'sum(' + rate('cpu_time_total') + ') / scalar(max(windows_cpu_logical_processor{job=~"$job", instance="$instance"}))', 'percentunit', steps=b.levels(0.8, 0.9)), + stat(154, 'Private working set', 'Physical memory private to the selected processes; shared pages are excluded.', 'sum(' + gauge('working_set_private_bytes') + ')', 'bytes'), + stat(155, 'Private bytes', 'Total memory allocated by the selected processes that cannot be shared; it may include nonresident memory.', 'sum(' + gauge('private_bytes') + ')', 'bytes'), - graph(112, 'Process CPU usage', 'User and privileged CPU time per process as a share of one logical processor. Values above 100% mean the process uses more than one core.', sumRates('cpu_time_total'), sumRates('cpu_time_total', ' @ end()'), 'percentunit'), - graph(113, 'Process working set', 'Physical memory in the working set of each process, including shared pages.', gauge('working_set_bytes'), gauge('working_set_bytes', ' @ end()'), 'bytes'), - graph(114, 'Process private bytes', 'Memory allocated by each process that cannot be shared with other processes.', gauge('private_bytes'), gauge('private_bytes', ' @ end()'), 'bytes'), - graph(115, 'Process I/O throughput', 'Total bytes issued for read, write and other I/O per process, including file, network and device operations.', sumRates('io_bytes_total'), sumRates('io_bytes_total', ' @ end()'), 'Bps'), - graph(116, 'Process threads', 'Active threads in each process.', gauge('threads'), gauge('threads', ' @ end()'), 'short'), - graph(117, 'Process handles', 'Open handles in each process. Steady growth can indicate a handle leak.', gauge('handles'), gauge('handles', ' @ end()'), 'short'), - graph(118, 'Process I/O operations', 'Total read, write and other I/O operations per second per process. Includes file, network and device I/O.', sumRates('io_operations_total'), sumRates('io_operations_total', ' @ end()'), 'iops'), - graph(119, 'Process page faults', 'Page faults per second by each process, including soft faults that do not require reading from disk.', rate('page_faults_total'), rate('page_faults_total', ' @ end()'), 'ops'), - ] -) + graph(112, 'Process CPU usage', 'User and privileged CPU time per process as a share of one logical processor. Values above 100% mean the process uses more than one core.', sumRates('cpu_time_total'), sumRates('cpu_time_total', ' @ end()'), 'percentunit'), + graph(113, 'Process working set', 'Physical memory in the working set of each process, including shared pages.', gauge('working_set_bytes'), gauge('working_set_bytes', ' @ end()'), 'bytes'), + graph(114, 'Process private bytes', 'Memory allocated by each process that cannot be shared with other processes.', gauge('private_bytes'), gauge('private_bytes', ' @ end()'), 'bytes'), + graph(115, 'Process I/O throughput', 'Total bytes issued for read, write and other I/O per process, including file, network and device operations.', sumRates('io_bytes_total'), sumRates('io_bytes_total', ' @ end()'), 'Bps'), + graph(116, 'Process threads', 'Active threads in each process.', gauge('threads'), gauge('threads', ' @ end()'), 'short'), + graph(117, 'Process handles', 'Open handles in each process. Steady growth can indicate a handle leak.', gauge('handles'), gauge('handles', ' @ end()'), 'short'), + graph(118, 'Process I/O operations', 'Total read, write and other I/O operations per second per process. Includes file, network and device I/O.', sumRates('io_operations_total'), sumRates('io_operations_total', ' @ end()'), 'iops'), + graph(119, 'Process page faults', 'Page faults per second by each process, including soft faults that do not require reading from disk.', rate('page_faults_total'), rate('page_faults_total', ' @ end()'), 'ops'), + ] + ) diff --git a/contrib/mixin/dashboards/scheduled_tasks.libsonnet b/contrib/mixin/dashboards/scheduled_tasks.libsonnet new file mode 100644 index 00000000..0bc5dc91 --- /dev/null +++ b/contrib/mixin/dashboards/scheduled_tasks.libsonnet @@ -0,0 +1,119 @@ +local b = import 'builders.libsonnet'; +local metric(name, labels='') = 'windows_scheduled_task_' + name + '{job=~"$job", instance="$instance"' + (if labels == '' then '' else ', ' + labels) + '}'; +// Disabled tasks do not run, so their results and missed runs need no attention. +local enabled(expr) = expr + ' and on (task) ' + metric('state', 'state!="disabled"') + ' == 1'; +local requirement = ' Requires the scheduled_task collector, which is not enabled by default.'; +// Counts fall back to 0 only while the collector reports tasks, so a missing collector shows no data. +local orZero = ' or (0 * count(' + metric('state') + '))'; +local table(id, title, description, queries, columns, unit='short') = + b.panel.new(id, title, 'table') + + b.panel.withDescription(description + requirement) + + b.panel.withQueries([ + b.query.new(query.expr, query.refId) + + b.query.withInstant() + + b.query.withFormat('table') + for query in queries + ]) + + b.panel.withTransformations( + (if std.length(queries) > 1 then [{ + group: 'joinByField', + kind: 'Transformation', + spec: { options: { byField: 'task', mode: 'outer' } }, + }] else []) + + [{ + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { [name]: true for name in ['Time', 'Time 1', 'Time 2', 'Value', 'Value #A'] if !std.member([column[0] for column in columns], name) }, + includeByName: {}, + indexByName: { [columns[i][0]]: i for i in std.range(0, std.length(columns) - 1) }, + renameByName: { [column[0]]: column[1] for column in columns }, + }, + }, + }] + ) + + b.panel.withDefaults({ unit: unit }) + + b.panel.withOptions({ sortBy: [{ desc: false, displayName: 'Task' }] }); +// Only results that can need attention get a color. +local resultColors = { + id: 'mappings', + value: [{ + type: 'value', + options: { + success: { color: 'green', index: 0 }, + terminated: { color: 'orange', index: 1 }, + unknown: { color: 'orange', index: 2 }, + }, + }], +}; + +function(on) + b.tab( + 'Scheduled tasks', + b.rows([ + if on('scheduled_task') then b.summary([190, 191, 192, 193, 194, 195]), + if on('scheduled_task') then b.row('Attention', b.flow([[196, 12, 10], [197, 12, 10]])), + if on('scheduled_task') then b.row('Activity', b.flow([[198, 24, 20]])), + if on('scheduled_task') then b.row('All tasks', b.flow([[199, 24, 14]])), + ]), + [ + b.stat(190, 'Tasks', 'Number of registered tasks that match the collector include and exclude filters.' + requirement, 'count(count by (task) (' + metric('state') + '))'), + b.stat(191, 'Running', 'Tasks that are running now.' + requirement, 'sum(' + metric('state', 'state="running"') + ')' + orZero), + b.stat(192, 'Disabled', 'Tasks that are disabled and do not run.' + requirement, 'sum(' + metric('state', 'state="disabled"') + ')' + orZero), + b.stat(193, 'Unknown code', 'Enabled tasks whose last result code has no named status. This is usually a non-zero exit code of the task or a Task Scheduler error, so check the task history.' + requirement, 'count(' + enabled(metric('last_result_status', 'status="unknown"') + ' == 1') + ')' + orZero, steps=[{ color: 'green', value: null }, { color: 'orange', value: 1 }]), + b.stat(194, 'Missed runs', 'Enabled tasks that missed at least one scheduled run, for example because the host was off or asleep.' + requirement, 'count(' + enabled(metric('missed_runs') + ' > 0') + ')' + orZero), + b.stat(195, 'Never run', 'Tasks that have not run since they were registered.' + requirement, 'sum(' + metric('last_result_status', 'status="has_not_run"') + ')' + orZero), + + table(196, 'Tasks with an unknown result code', 'Enabled tasks whose last result code has no named status, usually a non-zero exit code of the task or a Task Scheduler error.', [ + { refId: 'A', expr: 'max by (task) (' + enabled(metric('last_result_status', 'status="unknown"') + ' == 1') + ')' }, + ], [['task', 'Task']], unit='none'), + + table(197, 'Tasks with missed runs', 'Enabled tasks that missed at least one scheduled run, with the number of missed runs reported by Task Scheduler.', [ + { refId: 'A', expr: 'max by (task) (' + enabled(metric('missed_runs') + ' > 0') + ')' }, + ], [['task', 'Task'], ['Value', 'Missed runs']]) + + b.panel.withOptions({ sortBy: [{ desc: true, displayName: 'Missed runs' }] }), + + b.panel.new(198, 'Task runs', 'state-timeline') + + b.panel.withDescription('Tasks that were running at a scrape in the selected time range. Runs shorter than the scrape interval can be missed.' + requirement) + + b.panel.withQueries([ + b.query.new('max by (task) (' + metric('state', 'state="running"') + ') and on (task) (max_over_time(' + metric('state', 'state="running"') + '[$__range] @ end()) == 1)', 'A') + + b.query.withLegendFormat('{{task}}'), + ]) + + b.panel.withDefaults({ + mappings: [ + { + options: { + '0': { + color: 'transparent', + index: 0, + text: 'not running', + }, + '1': { + color: 'green', + index: 1, + text: 'running', + }, + }, + type: 'value', + }, + ], + }), + + table(199, 'Tasks', 'All tasks with their state, last result and missed runs. Tasks that never ran report no missed runs.', [ + { refId: 'A', expr: 'max by (task, state, status) ((' + metric('state') + ' == 1) * on (task) group_left (status) (' + metric('last_result_status') + ' == 1))' }, + { refId: 'B', expr: 'max by (task) (' + metric('missed_runs') + ')' }, + ], [['task', 'Task'], ['state', 'State'], ['status', 'Last result'], ['Value #B', 'Missed runs']]) + + b.panel.withDefaults({ custom: { filterable: true } }) + + b.panel.withOverrides([ + { + matcher: { id: 'byName', options: 'Last result' }, + properties: [ + { id: 'color', value: { fixedColor: 'text', mode: 'fixed' } }, + resultColors, + { id: 'custom.cellOptions', value: { type: 'color-text' } }, + ], + }, + ]), + ] + ) diff --git a/contrib/mixin/dashboards/services.libsonnet b/contrib/mixin/dashboards/services.libsonnet index 7e2142a1..d5af4737 100644 --- a/contrib/mixin/dashboards/services.libsonnet +++ b/contrib/mixin/dashboards/services.libsonnet @@ -1,136 +1,85 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Services', - b.grid([ - b.place(50, 0, 0, 6, 4), - b.place(51, 6, 0, 6, 4), - b.place(52, 12, 0, 6, 4), - b.place(53, 18, 0, 6, 4), - b.place(54, 0, 4, 12, 10), - b.place(55, 12, 4, 12, 10), - ]), - [ - b.panel.new(50, 'Running services', 'stat') - + b.panel.withDescription('Number of services currently in the running state, reported by the service collector. Compare unexpected drops with the stopped automatic services table and service change history.') - + b.panel.withQueries([ - b.query.new('sum(windows_service_state{job=~"$job", instance="$instance", state="running"})', 'A') - + b.query.withInstant(), +function(on) + b.tab( + 'Services', + b.rows([ + if on('service') then b.summary([50, 51, 52, 53]), + if on('service') then b.row('State', b.flow([[54, 12, 10], [55, 12, 10]])), ]), + [ + b.stat(50, 'Running services', 'Number of services currently in the running state, reported by the service collector. Compare unexpected drops with the stopped automatic services table and service change history.', 'sum(windows_service_state{job=~"$job", instance="$instance", state="running"})', 'short'), - b.panel.new(51, 'Stopped auto services', 'stat') - + b.panel.withDescription('Services with start mode "auto" that are not running.') - + b.panel.withQueries([ - b.query.new('count(windows_service_state{job=~"$job", instance="$instance", state="running"} == 0 and on (name) windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1) or vector(0)', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'green', - value: null, + b.stat(51, 'Stopped auto services', 'Services with start mode "auto" that are not running.', 'count(windows_service_state{job=~"$job", instance="$instance", state="running"} == 0 and on (name) windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1) or vector(0)', steps=[{ color: 'green', value: null }, { color: 'orange', value: 1 }]), + + b.stat(52, 'Pending services', 'Services in a start, stop, pause or continue pending state. A service that stays pending is hung.', 'sum(windows_service_state{job=~"$job", instance="$instance", state=~".* pending"}) or vector(0)', steps=[{ color: 'green', value: null }, { color: 'orange', value: 1 }]), + + b.stat(53, 'Disabled services', 'Number of services configured with disabled startup. A disabled service cannot start until its startup mode changes; disabled services are not necessarily unhealthy.', 'sum(windows_service_start_mode{job=~"$job", instance="$instance", start_mode="disabled"})', 'short'), + + b.panel.new(54, 'Automatic services not running', 'table') + + b.panel.withDescription('Services configured to start automatically that are not in the running state. Delayed-start and trigger-start services may show up here until they start.') + + b.panel.withQueries([ + b.query.new('max by (name, state) (windows_service_state{job=~"$job", instance="$instance"} == 1) and on (name) (windows_service_state{job=~"$job", instance="$instance", state="running"} == 0) and on (name) (windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1)', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([ + { + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { + Time: true, + 'Time 1': true, + Value: true, + }, + includeByName: {}, + indexByName: { + name: 0, + state: 1, + }, + renameByName: { + name: 'Service', + state: 'State', + }, + }, }, + }, + ]) + + b.panel.withOptions({ + sortBy: [ { - color: 'orange', - value: 1, + desc: false, + displayName: 'Service', }, ], - }, - }), + }), - b.panel.new(52, 'Pending services', 'stat') - + b.panel.withDescription('Services in a start, stop, pause or continue pending state. A service that stays pending is hung.') - + b.panel.withQueries([ - b.query.new('sum(windows_service_state{job=~"$job", instance="$instance", state=~".* pending"}) or vector(0)', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ + b.panel.new(55, 'Service state changes', 'state-timeline') + + b.panel.withDescription('Services that started or stopped in the selected time range.') + + b.panel.withQueries([ + b.query.new('windows_service_state{job=~"$job", instance="$instance", state="running"} and on (name) (changes(windows_service_state{job=~"$job", instance="$instance", state="running"}[$__range] @ end()) > 0)', 'A') + + b.query.withLegendFormat('{{name}}'), + ]) + + b.panel.withDefaults({ + mappings: [ { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 1, + options: { + '0': { + color: 'red', + index: 0, + text: 'not running', + }, + '1': { + color: 'green', + index: 1, + text: 'running', + }, + }, + type: 'value', }, ], - }, - }), - - b.panel.new(53, 'Disabled services', 'stat') - + b.panel.withDescription('Number of services configured with disabled startup. A disabled service cannot start until its startup mode changes; disabled services are not necessarily unhealthy.') - + b.panel.withQueries([ - b.query.new('sum(windows_service_start_mode{job=~"$job", instance="$instance", start_mode="disabled"})', 'A') - + b.query.withInstant(), - ]), - - b.panel.new(54, 'Automatic services not running', 'table') - + b.panel.withDescription('Services configured to start automatically that are not in the running state. Delayed-start and trigger-start services may show up here until they start.') - + b.panel.withQueries([ - b.query.new('max by (name, state) (windows_service_state{job=~"$job", instance="$instance"} == 1) and on (name) (windows_service_state{job=~"$job", instance="$instance", state="running"} == 0) and on (name) (windows_service_start_mode{job=~"$job", instance="$instance", start_mode="auto"} == 1)', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withTransformations([ - { - group: 'organize', - kind: 'Transformation', - spec: { - options: { - excludeByName: { - Time: true, - 'Time 1': true, - Value: true, - }, - includeByName: {}, - indexByName: { - name: 0, - state: 1, - }, - renameByName: { - name: 'Service', - state: 'State', - }, - }, - }, - }, - ]) - + b.panel.withOptions({ - sortBy: [ - { - desc: false, - displayName: 'Service', - }, - ], - }), - - b.panel.new(55, 'Service state changes', 'state-timeline') - + b.panel.withDescription('Services that started or stopped in the selected time range.') - + b.panel.withQueries([ - b.query.new('windows_service_state{job=~"$job", instance="$instance", state="running"} and on (name) (changes(windows_service_state{job=~"$job", instance="$instance", state="running"}[$__range] @ end()) > 0)', 'A') - + b.query.withLegendFormat('{{name}}'), - ]) - + b.panel.withDefaults({ - mappings: [ - { - options: { - '0': { - color: 'red', - index: 0, - text: 'not running', - }, - '1': { - color: 'green', - index: 1, - text: 'running', - }, - }, - type: 'value', - }, - ], - }), - ] -) + }), + ] + ) diff --git a/contrib/mixin/dashboards/smb.libsonnet b/contrib/mixin/dashboards/smb.libsonnet new file mode 100644 index 00000000..b9e9b7c2 --- /dev/null +++ b/contrib/mixin/dashboards/smb.libsonnet @@ -0,0 +1,64 @@ +local b = import 'builders.libsonnet'; +local server(name) = 'windows_smb_server_shares_' + name + '{job=~"$job", instance="$instance"}'; +local serverRate(name) = 'rate(' + server(name) + '[$__rate_interval])'; +local client(name) = 'windows_smbclient_' + name + '{job=~"$job", instance="$instance"}'; +local clientRate(name) = 'rate(' + client(name) + '[$__rate_interval])'; +local serverRequirement = ' Requires the smb collector, which is not enabled by default.'; +local clientRequirement = ' Requires the smbclient collector, which is not enabled by default.'; +// Shares this host serves, and \\server\share paths this host connects to. +local share = '{{share}}'; +local path = '\\\\{{server}}\\{{share}}'; + +function(on) + b.tab( + 'SMB', + b.rows([ + b.summary([ + if on('smb') then 220, + if on('smb') then 221, + if on('smb') then 222, + if on('smbclient') then 223, + if on('smbclient') then 224, + if on('smbclient') then 225, + ]), + if on('smb') then b.row('Server shares', b.flow([[226, 12, 8], [227, 12, 8], [228, 8, 8], [229, 8, 8], [230, 8, 8]])), + if on('smbclient') then b.row('Client shares', b.flow([[231, 12, 8], [232, 12, 8], [233, 12, 8], [234, 12, 8], [235, 12, 8], [236, 12, 8]])), + ]), + [ + b.stat(220, 'Open files', 'Files open on the shares of this SMB server.' + serverRequirement, 'sum(' + server('current_open_file_count') + ')'), + b.stat(221, 'Connections', 'Client connections (tree connects) to the shares of this SMB server.' + serverRequirement, 'sum(' + server('tree_connect_count') + ')'), + b.stat(222, 'Server traffic', 'Bytes sent and received per second by the shares of this SMB server.' + serverRequirement, 'sum(' + serverRate('received_bytes_total') + ') + sum(' + serverRate('sent_bytes_total') + ')', 'Bps'), + b.stat(223, 'Client traffic', 'Bytes read and written per second by this host on remote SMB shares.' + clientRequirement, 'sum(' + clientRate('data_bytes_total') + ')', 'Bps'), + b.stat(224, 'Client latency', 'Average time per request of this host on remote SMB shares. 0 when there are no requests.' + clientRequirement, '(sum(' + clientRate('request_seconds_total') + ') / (sum(' + clientRate('requests_total') + ') > 0)) or (0 * sum(' + clientRate('requests_total') + '))', 's', steps=b.levels(0.02, 0.05)), + b.stat(225, 'Credit stalls', 'Requests per second delayed because the server granted too few SMB credits. Sustained stalls limit throughput.' + clientRequirement, 'sum(' + clientRate('stalls_total') + ')', 'ops', steps=[{ color: 'green', value: null }, { color: 'orange', value: 1 }]), + + b.graph(226, 'Share traffic', 'Bytes sent and received per second per share. Received bytes are drawn below the axis.' + serverRequirement, 'Bps', [ + [serverRate('sent_bytes_total'), share + ' sent'], + [serverRate('received_bytes_total'), share + ' received'], + ], below='.* received$'), + b.graph(227, 'Share requests', 'Read, write and metadata requests per second per share.' + serverRequirement, 'ops', [ + [serverRate('read_requests_count_total'), share + ' read'], + [serverRate('write_requests_count_total'), share + ' write'], + [serverRate('metadata_requests_count_total'), share + ' metadata'], + ]), + b.graph(228, 'Open files', 'Files open per share.' + serverRequirement, 'short', [[server('current_open_file_count'), share]]), + b.graph(229, 'Connections', 'Client connections (tree connects) per share.' + serverRequirement, 'short', [[server('tree_connect_count'), share]]), + b.graph(230, 'Files opened', 'Files opened per second per share.' + serverRequirement, 'ops', [[serverRate('files_opened_count_total'), share]]), + + b.graph(231, 'Client traffic', 'Bytes read and written per second per remote share. Reads are drawn below the axis.' + clientRequirement, 'Bps', [ + [clientRate('write_bytes_total'), path + ' write'], + [clientRate('read_bytes_total'), path + ' read'], + ], below='.* read$'), + b.graph(232, 'Client requests', 'Read and write requests per second per remote share. Reads are drawn below the axis.' + clientRequirement, 'ops', [ + [clientRate('write_requests_total'), path + ' write'], + [clientRate('read_requests_total'), path + ' read'], + ], below='.* read$'), + b.graph(233, 'Client latency', 'Average time per read and write request per remote share. Reads are drawn below the axis.' + clientRequirement, 's', [ + [clientRate('write_seconds_total') + ' / (' + clientRate('write_requests_total') + ' > 0)', path + ' write'], + [clientRate('read_seconds_total') + ' / (' + clientRate('read_requests_total') + ' > 0)', path + ' read'], + ], below='.* read$'), + b.graph(234, 'Client queue length', 'Requests outstanding per remote share at the time of the scrape.' + clientRequirement, 'short', [[client('requests_queued'), path]]), + b.graph(235, 'Credit stalls', 'Requests per second per remote share delayed because the server granted too few SMB credits.' + clientRequirement, 'ops', [[clientRate('stalls_total'), path]]), + b.graph(236, 'Metadata requests', 'Metadata requests per second per remote share, such as opening files and listing directories.' + clientRequirement, 'ops', [[clientRate('metadata_requests_total'), path]]), + ] + ) diff --git a/contrib/mixin/dashboards/time.libsonnet b/contrib/mixin/dashboards/time.libsonnet index 459ceeec..7094820f 100644 --- a/contrib/mixin/dashboards/time.libsonnet +++ b/contrib/mixin/dashboards/time.libsonnet @@ -1,110 +1,89 @@ local b = import 'builders.libsonnet'; -b.tab( - 'Time', - b.grid([ - b.place(84, 0, 0, 6, 4), - b.place(85, 6, 0, 6, 4), - b.place(86, 12, 0, 6, 4), - b.place(87, 18, 0, 6, 4), - b.place(88, 0, 4, 24, 8), - ]), - [ - b.panel.new(84, 'Time zone', 'stat') - + b.panel.withDescription('Needs the time collector, which is not enabled by default.') - + b.panel.withQueries([ - b.query.new('windows_time_timezone{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withDefaults({ - unit: '', - }) - + b.panel.withOptions({ - colorMode: 'none', - reduceOptions: { - fields: '/^timezone$/', - }, - textMode: 'value', - }), +function(on) + b.tab( + 'Time', + b.rows([ + if on('time') then b.summary([84, 85, 86, 87]), + if on('time') then b.row('Clock', b.flow([[88, 24, 8]])), + ]), + [ + b.panel.new(84, 'Time zone', 'stat') + + b.panel.withDescription('Needs the time collector, which is not enabled by default.') + + b.panel.withQueries([ + b.query.new('windows_time_timezone{job=~"$job", instance="$instance"}', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withDefaults({ + unit: '', + }) + + b.panel.withOptions({ + colorMode: 'none', + reduceOptions: { + fields: '/^timezone$/', + }, + textMode: 'value', + }), - b.panel.new(85, 'Clock sync source', 'stat') - + b.panel.withDescription('Active Windows Time synchronization provider. A non-NTP provider can be expected on virtual machines; this requires the optional time collector.') - + b.panel.withQueries([ - b.query.new('windows_time_clock_sync_source{job=~"$job", instance="$instance"} == 1', 'A') - + b.query.withInstant() - + b.query.withFormat('table'), - ]) - + b.panel.withDefaults({ - unit: '', - }) - + b.panel.withOptions({ - colorMode: 'none', - reduceOptions: { - fields: '/^type$/', - }, - textMode: 'value', - }), + b.panel.new(85, 'Clock sync source', 'stat') + + b.panel.withDescription('Active Windows Time synchronization provider. A non-NTP provider can be expected on virtual machines; this requires the optional time collector.') + + b.panel.withQueries([ + b.query.new('windows_time_clock_sync_source{job=~"$job", instance="$instance"} == 1', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withDefaults({ + unit: '', + }) + + b.panel.withOptions({ + colorMode: 'none', + reduceOptions: { + fields: '/^type$/', + }, + textMode: 'value', + }), - b.panel.new(86, 'NTP time sources', 'stat') - + b.panel.withDescription('Number of time sources the NTP client uses. 0 means the clock is not synchronized.') - + b.panel.withQueries([ - b.query.new('windows_time_ntp_client_time_sources{job=~"$job", instance="$instance"}', 'A') - + b.query.withInstant(), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'red', - value: null, - }, - { - color: 'green', - value: 1, - }, - ], - }, - }), + b.stat(86, 'NTP time sources', 'Number of time sources the NTP client uses. 0 means the clock is not synchronized.', 'windows_time_ntp_client_time_sources{job=~"$job", instance="$instance"}', steps=[{ color: 'red', value: null }, { color: 'green', value: 1 }]), - b.panel.new(87, 'Clock offset', 'stat') - + b.panel.withDescription('Absolute offset between the system clock and the selected time source.') - + b.panel.withQueries([ - b.query.new('abs(windows_time_computed_time_offset_seconds{job=~"$job", instance="$instance"})', 'A'), - ]) - + b.panel.withDefaults({ - thresholds: { - steps: [ - { - color: 'green', - value: null, - }, - { - color: 'orange', - value: 0.5, - }, - { - color: 'red', - value: 1, - }, - ], - }, - unit: 's', - }) - + b.panel.withOptions({ - graphMode: 'area', - }), + b.panel.new(87, 'Clock offset', 'stat') + + b.panel.withDescription('Absolute offset between the system clock and the selected time source.') + + b.panel.withQueries([ + b.query.new('abs(windows_time_computed_time_offset_seconds{job=~"$job", instance="$instance"})', 'A'), + ]) + + b.panel.withDefaults({ + thresholds: { + steps: [ + { + color: 'green', + value: null, + }, + { + color: 'orange', + value: 0.5, + }, + { + color: 'red', + value: 1, + }, + ], + }, + unit: 's', + }) + + b.panel.withOptions({ + graphMode: 'area', + }), - b.panel.new(88, 'Clock offset and NTP round-trip delay', 'timeseries') - + b.panel.withDescription('Signed offset from the selected time source and the NTP request round-trip delay, in seconds. Persistent offset or increased delay can affect time-sensitive applications; this compares the host to its chosen source and does not independently verify that source.') - + b.panel.withQueries([ - b.query.new('windows_time_computed_time_offset_seconds{job=~"$job", instance="$instance"}', 'A') - + b.query.withLegendFormat('clock offset'), - b.query.new('windows_time_ntp_round_trip_delay_seconds{job=~"$job", instance="$instance"}', 'B') - + b.query.withLegendFormat('NTP round-trip delay'), - ]) - + b.panel.withDefaults({ - unit: 's', - }), - ] -) + b.panel.new(88, 'Clock offset and NTP round-trip delay', 'timeseries') + + b.panel.withDescription('Signed offset from the selected time source and the NTP request round-trip delay, in seconds. Persistent offset or increased delay can affect time-sensitive applications; this compares the host to its chosen source and does not independently verify that source.') + + b.panel.withQueries([ + b.query.new('windows_time_computed_time_offset_seconds{job=~"$job", instance="$instance"}', 'A') + + b.query.withLegendFormat('clock offset'), + b.query.new('windows_time_ntp_round_trip_delay_seconds{job=~"$job", instance="$instance"}', 'B') + + b.query.withLegendFormat('NTP round-trip delay'), + ]) + + b.panel.withDefaults({ + unit: 's', + }), + ] + ) diff --git a/contrib/mixin/dashboards/updates.libsonnet b/contrib/mixin/dashboards/updates.libsonnet new file mode 100644 index 00000000..75f5e252 --- /dev/null +++ b/contrib/mixin/dashboards/updates.libsonnet @@ -0,0 +1,65 @@ +local b = import 'builders.libsonnet'; +local metric(name, labels='') = 'windows_update_' + name + '{job=~"$job", instance="$instance"' + (if labels == '' then '' else ', ' + labels) + '}'; +local requirement = ' Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.'; +// Counts fall back to 0 only while the collector reports, so a missing collector shows no data. +local pending(labels) = 'count(' + metric('pending_info', labels) + ') or (0 * ' + metric('scrape_timestamp_seconds') + ')'; +local days(n) = n * 86400; + +function(on) + b.tab( + 'Updates', + b.rows([ + if on('update') then b.summary([210, 211, 212, 214, 215]), + if on('update') then b.row('Pending updates', b.flow([[216, 24, 10]])), + if on('update') then b.row('History', b.flow([[217, 12, 8], [218, 12, 8]])), + ]), + [ + b.stat(210, 'Pending', 'Updates that are available but not installed.' + requirement, pending('')), + b.stat(211, 'Critical', 'Pending updates with the Microsoft security severity Critical.' + requirement, pending('severity="Critical"'), steps=[{ color: 'green', value: null }, { color: 'red', value: 1 }]), + b.stat(212, 'Important', 'Pending updates with the Microsoft security severity Important.' + requirement, pending('severity="Important"'), steps=[{ color: 'green', value: null }, { color: 'orange', value: 1 }]), + b.stat(214, 'Oldest pending', 'Time since the oldest pending update was published. Orange after 30 days, red after 60 days.' + requirement, 'time() - min(' + metric('pending_published_timestamp') + ')', 'dtdurations', steps=[{ color: 'green', value: null }, { color: 'orange', value: days(30) }, { color: 'red', value: days(60) }]) + + b.panel.withDefaults({ noValue: 'none' }) + + b.panel.withOptions({ reduceOptions: { calcs: ['last'] } }), + b.stat(215, 'Last check', 'Time since the collector last queried Windows Update. Orange after 1 day, red after 7 days.' + requirement, 'time() - ' + metric('scrape_timestamp_seconds'), 'dtdurations', steps=[{ color: 'green', value: null }, { color: 'orange', value: days(1) }, { color: 'red', value: days(7) }]) + + b.panel.withOptions({ reduceOptions: { calcs: ['last'] } }), + + b.panel.new(216, 'Pending updates', 'table') + + b.panel.withDescription('Pending updates with their category, security severity and publish date. Category names follow the Windows display language.' + requirement) + + b.panel.withQueries([ + b.query.new('max by (title, category, severity) (' + '(' + metric('pending_published_timestamp') + ' * on (id, revision) group_right ' + metric('pending_info') + ') or on (id, revision) (0 * ' + metric('pending_info') + ')) * 1000', 'A') + + b.query.withInstant() + + b.query.withFormat('table'), + ]) + + b.panel.withTransformations([{ + group: 'organize', + kind: 'Transformation', + spec: { + options: { + excludeByName: { Time: true }, + includeByName: {}, + indexByName: { title: 0, category: 1, severity: 2, Value: 3 }, + renameByName: { title: 'Update', category: 'Category', severity: 'Severity', Value: 'Published' }, + }, + }, + }]) + + b.panel.withDefaults({ unit: 'dateTimeFromNow', mappings: [{ type: 'value', options: { '0': { index: 0, text: 'unknown' } } }] }) + + b.panel.withOptions({ sortBy: [{ desc: false, displayName: 'Published' }] }) + + b.panel.withOverrides([{ + matcher: { id: 'byName', options: 'Severity' }, + properties: [ + { id: 'color', value: { fixedColor: 'text', mode: 'fixed' } }, + { id: 'mappings', value: [{ type: 'value', options: { Critical: { color: 'red', index: 0 }, Important: { color: 'orange', index: 1 } } }] }, + { id: 'custom.cellOptions', value: { type: 'color-text' } }, + ], + }]), + + b.graph(217, 'Pending updates by category', 'Number of pending updates per update category.' + requirement, 'short', [ + ['count by (category) (' + metric('pending_info') + ')', '{{category}}'], + ]) + + b.panel.withDefaults({ custom: { drawStyle: 'bars', fillOpacity: 80, stacking: { mode: 'normal' } } }), + b.graph(218, 'Windows Update query duration', 'Duration of the last background query to the Windows Update API. Slow queries can point to a slow or unreachable update server.' + requirement, 's', [ + [metric('scrape_query_duration_seconds'), 'query duration'], + ]) + + b.panel.withOptions({ legend: { calcs: [], displayMode: 'list' } }), + ] + ) diff --git a/contrib/mixin/dashboards/variables.libsonnet b/contrib/mixin/dashboards/variables.libsonnet index bdc4dd9e..8c8e22ba 100644 --- a/contrib/mixin/dashboards/variables.libsonnet +++ b/contrib/mixin/dashboards/variables.libsonnet @@ -22,7 +22,8 @@ local new(name, definition) = common refId: 'PrometheusVariableQueryEditor-VariableQuery', })); -[ +// Variables of disabled collectors are left out. +function(on) [variable for variable in [ datasource.withKind() + datasource.spec.withAllowCustomValue(true) + datasource.spec.withCurrent({ @@ -72,57 +73,57 @@ local new(name, definition) = common new('show_hostname', 'label_values(windows_os_hostname{job=~"$job", instance="$instance"}, hostname)') + query.spec.withHide('hideVariable') , - new('volume', 'label_values(windows_logical_disk_size_bytes{job=~"$job", instance="$instance"}, volume)') - + query.spec.withCurrent({ - text: [ - 'All', - ], - value: [ - '$__all', - ], - }) - + query.spec.withIncludeAll(true) - + query.spec.withLabel('Volume') - + query.spec.withMulti(true) - + query.spec.withRegex('/^(?!HarddiskVolume).+$/') + if on('logical_disk') then new('volume', 'label_values(windows_logical_disk_size_bytes{job=~"$job", instance="$instance"}, volume)') + + query.spec.withCurrent({ + text: [ + 'All', + ], + value: [ + '$__all', + ], + }) + + query.spec.withIncludeAll(true) + + query.spec.withLabel('Volume') + + query.spec.withMulti(true) + + query.spec.withRegex('/^(?!HarddiskVolume).+$/') , - new('nic', 'label_values(windows_net_bytes_total{job=~"$job", instance="$instance"}, nic)') - + query.spec.withCurrent({ - text: [ - 'All', - ], - value: [ - '$__all', - ], - }) - + query.spec.withIncludeAll(true) - + query.spec.withLabel('Network interface') - + query.spec.withMulti(true) - + query.spec.withRegex('/^(?!isatap|Teredo|6to4).+$/'), - new('process', 'label_values(windows_process_info{job=~"$job", instance="$instance", process_id!="0"}, process)') - + query.spec.withCurrent({ - text: [ - 'All', - ], - value: [ - '$__all', - ], - }) - + query.spec.withIncludeAll(true) - + query.spec.withLabel('Process') - + query.spec.withMulti(true), - variables.CustomVariableKind.withKind() - + variables.CustomVariableKind.withSpec({ - name: 'process_top', - label: 'Top N processes', - description: 'Maximum number of processes per graph. Summary counters include all selected processes.', - query: '5,10,20', - current: { text: '10', value: '10' }, - options: [{ text: value, value: value, selected: value == '10' } for value in ['5', '10', '20']], - multi: false, - includeAll: false, - allowCustomValue: false, - hide: 'dontHide', - skipUrlSync: false, - }), -] + if on('net') then new('nic', 'label_values(windows_net_bytes_total{job=~"$job", instance="$instance"}, nic)') + + query.spec.withCurrent({ + text: [ + 'All', + ], + value: [ + '$__all', + ], + }) + + query.spec.withIncludeAll(true) + + query.spec.withLabel('Network interface') + + query.spec.withMulti(true) + + query.spec.withRegex('/^(?!isatap|Teredo|6to4).+$/'), + if on('process') then new('process', 'label_values(windows_process_info{job=~"$job", instance="$instance", process_id!="0"}, process)') + + query.spec.withCurrent({ + text: [ + 'All', + ], + value: [ + '$__all', + ], + }) + + query.spec.withIncludeAll(true) + + query.spec.withLabel('Process') + + query.spec.withMulti(true), + if on('process') then variables.CustomVariableKind.withKind() + + variables.CustomVariableKind.withSpec({ + name: 'process_top', + label: 'Top N processes', + description: 'Maximum number of processes per graph. Summary counters include all selected processes.', + query: '5,10,20', + current: { text: '10', value: '10' }, + options: [{ text: value, value: value, selected: value == '10' } for value in ['5', '10', '20']], + multi: false, + includeAll: false, + allowCustomValue: false, + hide: 'dontHide', + skipUrlSync: false, + }), +] if variable != null] diff --git a/contrib/mixin/dashboards/windows-exporter.libsonnet b/contrib/mixin/dashboards/windows-exporter.libsonnet index 5229cd14..0634493c 100644 --- a/contrib/mixin/dashboards/windows-exporter.libsonnet +++ b/contrib/mixin/dashboards/windows-exporter.libsonnet @@ -1,68 +1,87 @@ local b = import 'builders.libsonnet'; local dashboard = b.dashboard; -local tabs = [ - import 'fleet.libsonnet', - import 'overview.libsonnet', - import 'cpu.libsonnet', - import 'memory.libsonnet', - import 'disk.libsonnet', - import 'network.libsonnet', - import 'processes.libsonnet', - import 'services.libsonnet', - import 'gpu.libsonnet', - import 'hyper_v.libsonnet', - import 'time.libsonnet', - import 'exporter.libsonnet', -]; -local panelNames = std.flattenArrays([std.objectFields(tab.elements) for tab in tabs]); -assert std.length(panelNames) == std.length(std.set(panelNames)) : 'Panel IDs must be unique across tabs'; +// config.collectors selects the collectors the dashboard renders, see config.libsonnet. +function(config) + local known = std.objectFields((import '../config.libsonnet')._config.collectors); + local unknown = std.setDiff(std.objectFields(config.collectors), known); + assert std.length(unknown) == 0 : 'Unknown collectors in _config.collectors: ' + std.join(', ', unknown); + // A collector missing from a replaced collectors object counts as disabled. + local on(collector) = + assert std.member(known, collector) : 'Unknown collector ' + collector; + std.get(config.collectors, collector, false); + // All variables select hosts through windows_os_hostname. + assert on('os') : 'The dashboard requires the os collector'; + local tabs = [ + tab + for tab in [ + (import 'fleet.libsonnet')(on), + (import 'overview.libsonnet')(on), + (import 'cpu.libsonnet')(on), + (import 'memory.libsonnet')(on), + (import 'disk.libsonnet')(on), + (import 'network.libsonnet')(on), + (import 'smb.libsonnet')(on), + (import 'processes.libsonnet')(on), + (import 'services.libsonnet')(on), + (import 'scheduled_tasks.libsonnet')(on), + (import 'updates.libsonnet')(on), + (import 'gpu.libsonnet')(on), + (import 'hyper_v.libsonnet')(on), + (import 'time.libsonnet')(on), + (import 'exporter.libsonnet')(on), + ] + if !tab.empty + ]; -dashboard.new('Kdaassddw', 'Windows Exporter') -+ dashboard.spec.withCursorSync('Crosshair') -+ dashboard.spec.withDescription('Fleet overview and per-host details for Windows hosts monitored by windows_exporter.') -+ dashboard.spec.withEditable(true) -+ dashboard.spec.withLinks([ - { - asDropdown: false, - icon: 'doc', - includeVars: false, - keepTime: false, - tags: [], - targetBlank: true, - title: 'windows_exporter', - tooltip: '', - type: 'link', - url: 'https://github.com/prometheus-community/windows_exporter', - }, -]) -+ dashboard.spec.withLiveNow(false) -+ dashboard.spec.withPreload(false) -+ dashboard.spec.withTags([ - 'prometheus', - 'windows', - 'windows_exporter', -]) -+ dashboard.spec.withTimeSettings({ - autoRefresh: '1m', - autoRefreshIntervals: [ - '5s', - '10s', - '30s', - '1m', - '5m', - '15m', - '30m', - '1h', - '2h', - '1d', - ], - fiscalYearStartMonth: 0, - from: 'now-3h', - hideTimepicker: false, - to: 'now', -}) -+ dashboard.spec.withAnnotations(import 'annotations.libsonnet') -+ dashboard.spec.withVariables(import 'variables.libsonnet') -+ dashboard.spec.withElements(std.foldl(function(elements, tab) elements + tab.elements, tabs, {})) -+ dashboard.spec.withLayout(b.tabs([tab.layout for tab in tabs])) + local panelNames = std.flattenArrays([std.objectFields(tab.elements) for tab in tabs]); + assert std.length(panelNames) == std.length(std.set(panelNames)) : 'Panel IDs must be unique across tabs'; + + dashboard.new('Kdaassddw', 'Windows Exporter') + + dashboard.spec.withCursorSync('Crosshair') + + dashboard.spec.withDescription('Fleet overview and per-host details for Windows hosts monitored by windows_exporter.') + + dashboard.spec.withEditable(true) + + dashboard.spec.withLinks([ + { + asDropdown: false, + icon: 'doc', + includeVars: false, + keepTime: false, + tags: [], + targetBlank: true, + title: 'windows_exporter', + tooltip: '', + type: 'link', + url: 'https://github.com/prometheus-community/windows_exporter', + }, + ]) + + dashboard.spec.withLiveNow(false) + + dashboard.spec.withPreload(false) + + dashboard.spec.withTags([ + 'prometheus', + 'windows', + 'windows_exporter', + ]) + + dashboard.spec.withTimeSettings({ + autoRefresh: '1m', + autoRefreshIntervals: [ + '5s', + '10s', + '30s', + '1m', + '5m', + '15m', + '30m', + '1h', + '2h', + '1d', + ], + fiscalYearStartMonth: 0, + from: 'now-3h', + hideTimepicker: false, + to: 'now', + }) + + dashboard.spec.withAnnotations((import 'annotations.libsonnet')(on)) + + dashboard.spec.withVariables((import 'variables.libsonnet')(on)) + + dashboard.spec.withElements(std.foldl(function(elements, tab) elements + tab.elements, tabs, {})) + + dashboard.spec.withLayout(b.tabs([tab.layout for tab in tabs])) diff --git a/contrib/mixin/mise.toml b/contrib/mixin/mise.toml index ace2399d..e641081c 100644 --- a/contrib/mixin/mise.toml +++ b/contrib/mixin/mise.toml @@ -79,9 +79,10 @@ run = '''jsonnet -e '(import "mixin.libsonnet") { _config+:: { enableActiveDirec [tasks.test] description = "Run all mixin lint, runbook, and rule tests" -depends = ["lint", "check-runbooks"] +depends = ["lint", "check-runbooks", "vendor"] run = [ "jsonnet tests/runbooks.test.jsonnet", + "jsonnet -J vendor tests/dashboard.test.jsonnet > /dev/null", "promtool test rules tests/*.test.yaml", ] diff --git a/contrib/mixin/tests/dashboard.test.jsonnet b/contrib/mixin/tests/dashboard.test.jsonnet new file mode 100644 index 00000000..ab9d2318 --- /dev/null +++ b/contrib/mixin/tests/dashboard.test.jsonnet @@ -0,0 +1,66 @@ +// Renders the dashboard for several collector selections and checks that every +// layout reference has an element, every element is placed and no tab or row is +// 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 all(value) = function(collectors) { [name]: value for name in std.objectFields(collectors) }; + +local placed(layout) = + if layout.kind == 'RowsLayout' + then std.flattenArrays([placed(row.spec.layout) for row in layout.spec.rows]) + else [item.spec.element.name for item in layout.spec.items]; + +local summary(dashboard) = + local tabs = dashboard.spec.layout.spec.tabs; + local names = std.flattenArrays([placed(tab.spec.layout) for tab in tabs]); + assert std.set(names) == std.objectFields(dashboard.spec.elements) : 'Placed panels and elements differ'; + assert std.length(names) == std.length(std.set(names)) : 'A panel is placed twice'; + assert std.all([std.length(row.spec.layout.spec.items) > 0 for tab in tabs for row in tab.spec.layout.spec.rows]) : 'Empty row'; + { + [tab.spec.title]: [row.spec.title for row in tab.spec.layout.spec.rows] + for tab in tabs + }; + +local only(enabled) = function(collectors) all(false)(collectors) + { os: true } + enabled; +local exporter = ['Summary', 'Scrape', 'Collectors', 'Process and Go runtime']; + +local results = { + all: summary(render(all(true))), + defaults: summary(render(function(collectors) collectors)), + osOnly: summary(render(only({}))), + smbClientOnly: summary(render(only({ smbclient: true }))), + diskWithoutDiskdrive: summary(render(only({ logical_disk: true, physical_disk: true }))).Disk, + diskWithDiskdrive: summary(render(only({ logical_disk: true, physical_disk: true, diskdrive: true }))).Disk, + // A collectors object given without +: enables only the listed collectors. + replaced: summary(render(function(_) { os: true, cpu: true })), +}; + +local expect(name, want) = + assert results[name] == want : name + ': got ' + std.manifestJson(results[name]); + true; + +assert std.length(std.objectFields(results.all)) == 15 : 'all: got ' + std.join(', ', std.objectFields(results.all)); +assert expect('defaults', { + CPU: ['Summary', 'Utilization', 'Scheduling', 'System calls and frequency'], + Disk: ['Summary', 'Volumes', 'Volume I/O', 'Physical disks'], + Exporter: exporter, + Fleet: ['Hosts', 'Utilization', 'Throughput and errors'], + Memory: ['Summary', 'Physical memory and commit', 'Paging and kernel memory'], + Network: ['Summary', 'Interfaces'], + Overview: ['Summary', 'CPU and memory', 'Storage and network'], + Services: ['Summary', 'State'], +}); +assert expect('osOnly', { Exporter: exporter, Fleet: ['Hosts'], Overview: ['Summary'] }); +assert expect('smbClientOnly', { Exporter: exporter, Fleet: ['Hosts'], Overview: ['Summary'], SMB: ['Summary', 'Client shares'] }); +assert expect('diskWithoutDiskdrive', ['Summary', 'Volumes', 'Volume I/O', 'Physical disks']); +assert expect('diskWithDiskdrive', ['Summary', 'Volumes', 'Volume I/O', 'Drives', 'Physical disks']); +assert expect('replaced', { + CPU: ['Summary', 'Utilization', 'System calls and frequency'], + Exporter: exporter, + Fleet: ['Hosts', 'Utilization'], + Overview: ['Summary', 'CPU and memory'], +}); + +results diff --git a/dashboard/README.md b/dashboard/README.md index da4fa7fb..1b98273c 100644 --- a/dashboard/README.md +++ b/dashboard/README.md @@ -8,7 +8,8 @@ and takes several ideas from Grafana's [windows-observ-lib](https://github.com/g - Grafana 13 or later with a Prometheus data source. The file uses the v2 dashboard schema, which Grafana needs for tabs. - windows_exporter with the default collectors (`cpu`, `logical_disk`, `memory`, `net`, `os`, `physical_disk`, `service`, `system`). - The Processes, GPU, Hyper-V and Time tabs and the TCP and UDP rows of the Network tab need the `process`, `gpu`, `hyperv`, `time`, `tcp` and `udp` collectors, which are not enabled by default. + The SMB, Processes, Scheduled tasks, Updates, GPU, Hyper-V and Time tabs, the TCP and UDP rows of the Network tab and the Drives row of the Disk tab need the `smb` or `smbclient`, `process`, `scheduled_task`, `update`, `gpu`, `hyperv`, `time`, `tcp`, `udp` and `diskdrive` collectors, which are not enabled by default. + The sample shows every tab; build the dashboard from the [mixin](../contrib/mixin#collectors) with your collectors to hide the others. The process names in the GPU tab need the `process` collector. GPU temperature, fan, power and clock panels require WDDM 2.4 or newer and driver support; unsupported sensors are absent. @@ -37,10 +38,13 @@ The **Reboots** annotation marks each reboot of the selected host on all graphs. | Overview | Summary of the selected host: operating system, uptime, CPUs, memory, commit charge, volumes, disk and network throughput. | | CPU | Utilization by mode and per core, processor queue length, context switches, interrupts, processes, threads, system calls and the effective CPU frequency. | | Memory | Used and available physical memory, commit charge, hard page faults, kernel pools and the system cache. | -| Disk | Volume size and free space, usage, busy time, throughput, IOPS, latency and queue length. | +| Disk | Volume label, disk, file system, size and free space, usage, busy time, throughput, IOPS, latency and queue length; drive model, size, partitions and status; busy time, throughput, IOPS, latency, queue length and split I/O per physical disk, labelled with the drive model when `diskdrive` is enabled. | | Network | Throughput, utilization, packets, errors and discards per interface; TCP connection states and rates, segments and retransmissions; UDP datagrams and errors. | +| SMB | Open files, connections, traffic, requests and opened files per share this host serves; traffic, requests, latency, queue length, credit stalls and metadata requests per remote share this host uses. | | Services | Running, pending and disabled services, automatic services that are not running, and services that started or stopped in the time range. | | Processes | CPU usage, working set, private bytes, I/O throughput and operations, threads, handles and page faults per process, labelled with name and PID. | +| Scheduled tasks | Task count, running, disabled and never-run tasks, enabled tasks with an unknown result code or missed runs, tasks that ran in the time range, and all tasks with state, last result and missed runs. | +| Updates | Pending updates by severity and category, the oldest pending update, the time since the last Windows Update check, a list of pending updates and the query duration. | | GPU | Utilization by engine type, memory capacity, commitment and locality, temperature, fans, power, clocks, and top processes by GPU utilization and memory. | | Hyper-V | VM count and health, Hyper-V WMI health, host CPU time, CPU and memory per VM, virtual disks, virtual switches and VM network adapters. | | Time | Time zone, clock sync source, NTP time sources, clock offset and NTP round-trip delay. | @@ -48,6 +52,11 @@ The **Reboots** annotation marks each reboot of the selected host on all graphs. Click a hostname in the Fleet tab to open that host in the Overview tab. +Each per-host tab starts with a row of current values, each with a sparkline +of the time range behind it. Green, orange and red show health against fixed +thresholds; values without a meaningful threshold, like throughput or counts, +stay in the text color. + The Processes tab starts with totals for all selected processes: process count, threads, handles, CPU usage across the host, private working set and private bytes. The synthetic Idle process (PID 0) is excluded. Each graph shows at most **Top N** diff --git a/dashboard/windows-exporter-dashboard.json b/dashboard/windows-exporter-dashboard.json index 6a1c1ad6..6ee6f7dc 100644 --- a/dashboard/windows-exporter-dashboard.json +++ b/dashboard/windows-exporter-dashboard.json @@ -5540,9 +5540,9 @@ "spec": { "editorMode": "code", "expr": "count(count by (process_id) (windows_process_info{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"}))", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5550,7 +5550,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -5565,7 +5567,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "min": 0, "thresholds": { @@ -5583,7 +5586,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -5623,9 +5626,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_process_threads{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5633,7 +5636,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -5648,7 +5653,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "min": 0, "thresholds": { @@ -5666,7 +5672,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -5706,9 +5712,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_process_handles{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5716,7 +5722,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -5731,7 +5739,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "min": 0, "thresholds": { @@ -5749,7 +5758,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -5789,9 +5798,9 @@ "spec": { "editorMode": "code", "expr": "sum(rate(windows_process_cpu_time_total{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"}[$__rate_interval])) / scalar(max(windows_cpu_logical_processor{job=~\"$job\", instance=\"$instance\"}))", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5799,14 +5808,16 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, "description": "CPU time used by the selected processes as a share of all logical processors of the host, excluding Idle. Includes all selected processes, regardless of Top N. Requires the process collector.", "id": 153, "links": [], - "title": "Process CPU busy", + "title": "CPU busy", "vizConfig": { "group": "stat", "kind": "VizConfig", @@ -5821,8 +5832,16 @@ "mode": "absolute", "steps": [ { - "color": "text", + "color": "green", "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 } ] }, @@ -5832,7 +5851,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -5872,9 +5891,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_process_working_set_private_bytes{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5882,7 +5901,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -5897,7 +5918,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "min": 0, "thresholds": { @@ -5915,7 +5937,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -5955,9 +5977,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_process_private_bytes{job=~\"$job\", instance=\"$instance\", process=~\"$process\", process_id!=\"0\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -5965,7 +5987,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -5980,7 +6004,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "min": 0, "thresholds": { @@ -5998,7 +6023,7 @@ }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -6111,6 +6136,900 @@ } } }, + "panel-160": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "1 - avg(clamp_max(rate(windows_cpu_time_total{job=~\"$job\", instance=\"$instance\", mode=\"idle\"}[$__rate_interval]), 1))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Non-idle CPU time averaged across logical processors.", + "id": 160, + "links": [], + "title": "CPU busy", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-161": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_cpu_time_total{job=~\"$job\", instance=\"$instance\", mode=\"user\"}[$__rate_interval])) / scalar(max(windows_cpu_logical_processor{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "CPU time spent in user mode, as a share of all logical processors.", + "id": 161, + "links": [], + "title": "User", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-162": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_cpu_time_total{job=~\"$job\", instance=\"$instance\", mode=\"privileged\"}[$__rate_interval])) / scalar(max(windows_cpu_logical_processor{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "CPU time spent in kernel mode, excluding interrupts and DPCs, as a share of all logical processors.", + "id": 162, + "links": [], + "title": "Privileged", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-163": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_system_processor_queue_length{job=~\"$job\", instance=\"$instance\"} / scalar(max(windows_cpu_logical_processor{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Threads waiting for a CPU per logical processor. A sustained value above 2 indicates CPU contention.", + "id": 163, + "links": [], + "title": "Queue per CPU", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 2 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-164": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_system_context_switches_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Context switches per second across the host.", + "id": 164, + "links": [], + "title": "Ctx switches", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-165": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "avg(1e4 * windows_cpu_core_frequency_mhz{job=~\"$job\", instance=\"$instance\"} * rate(windows_cpu_processor_performance_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / rate(windows_cpu_processor_mperf_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Average effective frequency across logical processors. Values above the nominal frequency mean turbo boost.", + "id": 165, + "links": [], + "title": "Frequency", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "hertz" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-166": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "1 - windows_memory_physical_free_bytes{job=~\"$job\", instance=\"$instance\"} / windows_memory_physical_total_bytes{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Share of physical memory in use: total minus available memory.", + "id": 166, + "links": [], + "title": "Memory used", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-167": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_memory_physical_free_bytes{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Physical memory available to processes: the standby, free and zero page lists.", + "id": 167, + "links": [], + "title": "Available", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-168": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_memory_committed_bytes{job=~\"$job\", instance=\"$instance\"} / windows_memory_commit_limit{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Committed virtual memory as a share of the commit limit. Allocations fail at 100%.", + "id": 168, + "links": [], + "title": "Commit used", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-169": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_memory_swap_page_reads_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Hard page faults read from disk per second. Sustained page reads indicate memory pressure.", + "id": 169, + "links": [], + "title": "Page reads", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, "panel-17": { "kind": "Panel", "spec": { @@ -6197,6 +7116,790 @@ } } }, + "panel-170": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_memory_pool_nonpaged_bytes{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Kernel memory that cannot be paged out. Steady growth can indicate a driver leak.", + "id": 170, + "links": [], + "title": "Nonpaged pool", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-171": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_memory_cache_bytes{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Physical memory used by the file system cache.", + "id": 171, + "links": [], + "title": "System cache", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-172": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(1 - windows_logical_disk_free_bytes{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"} / windows_logical_disk_size_bytes{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Used space of the fullest selected volume. Free-space counters can lag by 10 to 15 minutes.", + "id": 172, + "links": [], + "title": "Fullest volume", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-174": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_logical_disk_read_bytes_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bytes read per second, summed over the selected volumes.", + "id": 174, + "links": [], + "title": "Read", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-175": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_logical_disk_write_bytes_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bytes written per second, summed over the selected volumes.", + "id": 175, + "links": [], + "title": "Write", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-176": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_logical_disk_reads_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval])) + sum(rate(windows_logical_disk_writes_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Read and write operations per second, summed over the selected volumes.", + "id": 176, + "links": [], + "title": "IOPS", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "iops" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-177": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "((sum(rate(windows_logical_disk_read_seconds_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval])) + sum(rate(windows_logical_disk_write_seconds_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval]))) / ((sum(rate(windows_logical_disk_reads_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval])) + sum(rate(windows_logical_disk_writes_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval]))) > 0)) or (0 * sum(rate(windows_logical_disk_reads_total{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"}[$__rate_interval])))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Average time per read or write operation over the selected volumes. 0 when there is no I/O.", + "id": 177, + "links": [], + "title": "Latency", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.02 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-178": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_net_bytes_sent_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval])) * 8", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bits sent per second, summed over the selected interfaces.", + "id": 178, + "links": [], + "title": "Sent", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-179": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_net_bytes_received_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval])) * 8", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bits received per second, summed over the selected interfaces.", + "id": 179, + "links": [], + "title": "Received", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, "panel-18": { "kind": "Panel", "spec": { @@ -6317,6 +8020,913 @@ } } }, + "panel-180": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(rate(windows_net_bytes_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval]) / (windows_net_current_bandwidth_bytes{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"} > 0))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Utilization of the busiest selected interface: bytes sent and received per second against its current bandwidth.", + "id": 180, + "links": [], + "title": "Utilization", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-181": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_net_packets_received_errors_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval])) + sum(rate(windows_net_packets_received_discarded_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval])) + sum(rate(windows_net_packets_outbound_errors_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval])) + sum(rate(windows_net_packets_outbound_discarded_total{job=~\"$job\", instance=\"$instance\", nic=~\"$nic\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Packets per second that were discarded or had errors, inbound and outbound, summed over the selected interfaces.", + "id": 181, + "links": [], + "title": "Errors", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 10 + } + ] + }, + "unit": "pps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-182": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_tcp_connections_established{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "TCP connections in the established or close-wait state, IPv4 and IPv6. Requires the tcp collector.", + "id": 182, + "links": [], + "title": "TCP sessions", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-183": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(sum(rate(windows_tcp_segments_retransmitted_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) / (sum(rate(windows_tcp_segments_sent_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) > 0)) or (0 * sum(rate(windows_tcp_segments_sent_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Retransmitted segments as a share of sent segments. A rate that stays above a few percent points to packet loss. Requires the tcp collector.", + "id": 183, + "links": [], + "title": "Retransmits", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 2, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.01 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-184": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(clamp_max(max by (luid) (sum by (luid, eng, engtype) (rate(windows_gpu_engine_time_seconds{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))), 1))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Utilization of the busiest engine on the busiest GPU.", + "id": 184, + "links": [], + "title": "Utilization", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-185": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Dedicated GPU memory in use, summed over all GPUs.", + "id": 185, + "links": [], + "title": "VRAM used", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-186": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(max by (luid) (windows_gpu_adapter_memory_dedicated_bytes{job=~\"$job\", instance=\"$instance\"})) / (sum(max by (luid) (windows_gpu_dedicated_video_memory_size_bytes{job=~\"$job\", instance=\"$instance\"})) > 0)", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Dedicated GPU memory in use as a share of the dedicated video memory of all GPUs.", + "id": 186, + "links": [], + "title": "VRAM usage", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-187": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(max by (luid) (windows_gpu_adapter_memory_shared_bytes{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "System memory used by the GPUs, summed over all GPUs.", + "id": 187, + "links": [], + "title": "Shared memory", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "bytes" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-188": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(windows_gpu_temperature_celsius{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Temperature of the hottest GPU. Requires WDDM 2.4 or newer and driver support.", + "id": 188, + "links": [], + "title": "Temperature", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 80 + }, + { + "color": "red", + "value": 90 + } + ] + }, + "unit": "celsius" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-189": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(windows_gpu_power_usage_ratio{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Highest GPU power draw as a fraction of the driver-reported maximum power (TDP). Requires WDDM 2.4 or newer and driver support.", + "id": 189, + "links": [], + "title": "Power usage", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "decimals": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, "panel-19": { "kind": "Panel", "spec": { @@ -6481,6 +9091,1069 @@ } } }, + "panel-190": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(count by (task) (windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Number of registered tasks that match the collector include and exclude filters. Requires the scheduled_task collector, which is not enabled by default.", + "id": 190, + "links": [], + "title": "Tasks", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-191": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state=\"running\"}) or (0 * count(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Tasks that are running now. Requires the scheduled_task collector, which is not enabled by default.", + "id": 191, + "links": [], + "title": "Running", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-192": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state=\"disabled\"}) or (0 * count(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Tasks that are disabled and do not run. Requires the scheduled_task collector, which is not enabled by default.", + "id": 192, + "links": [], + "title": "Disabled", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-193": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(windows_scheduled_task_last_result_status{job=~\"$job\", instance=\"$instance\", status=\"unknown\"} == 1 and on (task) windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state!=\"disabled\"} == 1) or (0 * count(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Enabled tasks whose last result code has no named status. This is usually a non-zero exit code of the task or a Task Scheduler error, so check the task history. Requires the scheduled_task collector, which is not enabled by default.", + "id": 193, + "links": [], + "title": "Unknown code", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-194": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(windows_scheduled_task_missed_runs{job=~\"$job\", instance=\"$instance\"} > 0 and on (task) windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state!=\"disabled\"} == 1) or (0 * count(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Enabled tasks that missed at least one scheduled run, for example because the host was off or asleep. Requires the scheduled_task collector, which is not enabled by default.", + "id": 194, + "links": [], + "title": "Missed runs", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-195": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_scheduled_task_last_result_status{job=~\"$job\", instance=\"$instance\", status=\"has_not_run\"}) or (0 * count(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"}))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Tasks that have not run since they were registered. Requires the scheduled_task collector, which is not enabled by default.", + "id": 195, + "links": [], + "title": "Never run", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-196": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (task) (windows_scheduled_task_last_result_status{job=~\"$job\", instance=\"$instance\", status=\"unknown\"} == 1 and on (task) windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state!=\"disabled\"} == 1)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [ + { + "group": "organize", + "kind": "Transformation", + "spec": { + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Value": true, + "Value #A": true + }, + "includeByName": {}, + "indexByName": { + "task": 0 + }, + "renameByName": { + "task": "Task" + } + } + } + } + ] + } + }, + "description": "Enabled tasks whose last result code has no named status, usually a non-zero exit code of the task or a Task Scheduler error. Requires the scheduled_task collector, which is not enabled by default.", + "id": 196, + "links": [], + "title": "Tasks with an unknown result code", + "vizConfig": { + "group": "table", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "minWidth": 60 + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Task" + } + ] + } + }, + "version": "" + } + } + }, + "panel-197": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (task) (windows_scheduled_task_missed_runs{job=~\"$job\", instance=\"$instance\"} > 0 and on (task) windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state!=\"disabled\"} == 1)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [ + { + "group": "organize", + "kind": "Transformation", + "spec": { + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Value #A": true + }, + "includeByName": {}, + "indexByName": { + "Value": 1, + "task": 0 + }, + "renameByName": { + "Value": "Missed runs", + "task": "Task" + } + } + } + } + ] + } + }, + "description": "Enabled tasks that missed at least one scheduled run, with the number of missed runs reported by Task Scheduler. Requires the scheduled_task collector, which is not enabled by default.", + "id": 197, + "links": [], + "title": "Tasks with missed runs", + "vizConfig": { + "group": "table", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "minWidth": 60 + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": true, + "displayName": "Missed runs" + } + ] + } + }, + "version": "" + } + } + }, + "panel-198": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (task) (windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state=\"running\"}) and on (task) (max_over_time(windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\", state=\"running\"}[$__range] @ end()) == 1)", + "instant": false, + "legendFormat": "{{task}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Tasks that were running at a scrape in the selected time range. Runs shorter than the scrape interval can be missed. Requires the scheduled_task collector, which is not enabled by default.", + "id": 198, + "links": [], + "title": "Task runs", + "vizConfig": { + "group": "state-timeline", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 90, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineWidth": 0, + "spanNulls": false + }, + "mappings": [ + { + "options": { + "0": { + "color": "transparent", + "index": 0, + "text": "not running" + }, + "1": { + "color": "green", + "index": 1, + "text": "running" + } + }, + "type": "value" + } + ], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + }, + { + "color": "green", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "options": { + "alignValue": "left", + "legend": { + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "mergeValues": false, + "rowHeight": 1, + "showValue": "never", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + } + }, + "version": "" + } + } + }, + "panel-199": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (task, state, status) ((windows_scheduled_task_state{job=~\"$job\", instance=\"$instance\"} == 1) * on (task) group_left (status) (windows_scheduled_task_last_result_status{job=~\"$job\", instance=\"$instance\"} == 1))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (task) (windows_scheduled_task_missed_runs{job=~\"$job\", instance=\"$instance\"})", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [ + { + "group": "joinByField", + "kind": "Transformation", + "spec": { + "options": { + "byField": "task", + "mode": "outer" + } + } + }, + { + "group": "organize", + "kind": "Transformation", + "spec": { + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Value": true, + "Value #A": true + }, + "includeByName": {}, + "indexByName": { + "Value #B": 3, + "state": 1, + "status": 2, + "task": 0 + }, + "renameByName": { + "Value #B": "Missed runs", + "state": "State", + "status": "Last result", + "task": "Task" + } + } + } + } + ] + } + }, + "description": "All tasks with their state, last result and missed runs. Tasks that never ran report no missed runs. Requires the scheduled_task collector, which is not enabled by default.", + "id": 199, + "links": [], + "title": "Tasks", + "vizConfig": { + "group": "table", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": true, + "inspect": false, + "minWidth": 60 + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Last result" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "success": { + "color": "green", + "index": 0 + }, + "terminated": { + "color": "orange", + "index": 1 + }, + "unknown": { + "color": "orange", + "index": 2 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Task" + } + ] + } + }, + "version": "" + } + } + }, "panel-2": { "kind": "Panel", "spec": { @@ -7583,6 +11256,1236 @@ } } }, + "panel-200": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max(1 - clamp_max(rate(windows_physical_disk_idle_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]), 1))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Busy time of the busiest physical disk. Requires the physical_disk collector.", + "id": 200, + "links": [], + "title": "Busiest disk", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "decimals": 1, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.8 + }, + { + "color": "red", + "value": 0.9 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-201": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(label_replace(windows_diskdrive_status{job=~\"$job\", instance=\"$instance\", status!=\"OK\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\") == 1) or (0 * count(label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Drives whose operational status is not OK. Requires the diskdrive collector.", + "id": 201, + "links": [], + "title": "Drives not OK", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-202": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\"))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (disk) (label_replace(windows_diskdrive_size{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\"))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "B" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (disk) (label_replace(windows_diskdrive_partitions{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\"))", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "C" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (disk, status) (label_replace(windows_diskdrive_status{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\") == 1)", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "D" + } + } + ], + "queryOptions": {}, + "transformations": [ + { + "group": "joinByField", + "kind": "Transformation", + "spec": { + "options": { + "byField": "disk", + "mode": "outer" + } + } + }, + { + "group": "organize", + "kind": "Transformation", + "spec": { + "options": { + "excludeByName": { + "Time": true, + "Time 1": true, + "Time 2": true, + "Time 3": true, + "Time 4": true, + "Value #A": true, + "Value #D": true + }, + "includeByName": {}, + "indexByName": { + "Value #B": 2, + "Value #C": 3, + "disk": 0, + "model": 1, + "status": 4 + }, + "renameByName": { + "Value #B": "Size", + "Value #C": "Partitions", + "disk": "Disk", + "model": "Model", + "status": "Status" + } + } + } + } + ] + } + }, + "description": "Model, size, partitions and operational status of each drive. Requires the diskdrive collector.", + "id": 202, + "links": [], + "title": "Drives", + "vizConfig": { + "group": "table", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "minWidth": 60 + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Size" + }, + "properties": [ + { + "id": "unit", + "value": "bytes" + } + ] + }, + { + "matcher": { + "id": "byName", + "options": "Status" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "OK": { + "color": "green", + "index": 0 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Disk" + } + ] + } + }, + "version": "" + } + } + }, + "panel-203": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(1 - clamp_max(rate(windows_physical_disk_idle_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]), 1)) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (1 - clamp_max(rate(windows_physical_disk_idle_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]), 1))", + "instant": false, + "legendFormat": "{{disk}} {{model}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Share of time each physical disk was servicing requests (1 - idle time). Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 203, + "links": [], + "title": "Disk busy time", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-204": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_write_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_write_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "{{disk}} {{model}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_read_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_read_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "{{disk}} {{model}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Bytes read and written per second by each physical disk. Reads are drawn below the axis. Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 204, + "links": [], + "title": "Disk throughput", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-205": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_writes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_writes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "{{disk}} {{model}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_reads_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_reads_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "{{disk}} {{model}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Read and write operations per second by each physical disk. Reads are drawn below the axis. Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 205, + "links": [], + "title": "Disk IOPS", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "iops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-206": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_write_latency_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_physical_disk_writes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0)) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_write_latency_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_physical_disk_writes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0))", + "instant": false, + "legendFormat": "{{disk}} {{model}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_read_latency_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_physical_disk_reads_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0)) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_read_latency_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_physical_disk_reads_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0))", + "instant": false, + "legendFormat": "{{disk}} {{model}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Average time per read and write operation of each physical disk. Reads are drawn below the axis. Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 206, + "links": [], + "title": "Disk latency", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-207": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(windows_physical_disk_requests_queued{job=~\"$job\", instance=\"$instance\"}) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (windows_physical_disk_requests_queued{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "{{disk}} {{model}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Requests outstanding on each physical disk at the time of the scrape. A queue that stays high while latency rises indicates a disk bottleneck. Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 207, + "links": [], + "title": "Disk queue length", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-208": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(rate(windows_physical_disk_split_ios_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) * on (disk) group_left (model) max by (disk, model) (label_replace(windows_diskdrive_info{job=~\"$job\", instance=\"$instance\"}, \"disk\", \"$1\", \"name\", \"PHYSICALDRIVE(\\\\d+)\")) or on (disk) (rate(windows_physical_disk_split_ios_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "{{disk}} {{model}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "I/O requests per second that Windows split into multiple requests, because of a fragmented volume or a request too large for a single I/O. Requires the physical_disk collector; the diskdrive collector adds drive models.", + "id": 208, + "links": [], + "title": "Split I/O", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "iops" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, "panel-21": { "kind": "Panel", "spec": { @@ -7728,6 +12631,848 @@ } } }, + "panel-210": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(windows_update_pending_info{job=~\"$job\", instance=\"$instance\"}) or (0 * windows_update_scrape_timestamp_seconds{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Updates that are available but not installed. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 210, + "links": [], + "title": "Pending", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-211": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(windows_update_pending_info{job=~\"$job\", instance=\"$instance\", severity=\"Critical\"}) or (0 * windows_update_scrape_timestamp_seconds{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Pending updates with the Microsoft security severity Critical. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 211, + "links": [], + "title": "Critical", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-212": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count(windows_update_pending_info{job=~\"$job\", instance=\"$instance\", severity=\"Important\"}) or (0 * windows_update_scrape_timestamp_seconds{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Pending updates with the Microsoft security severity Important. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 212, + "links": [], + "title": "Important", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-214": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "time() - min(windows_update_pending_published_timestamp{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Time since the oldest pending update was published. Orange after 30 days, red after 60 days. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 214, + "links": [], + "title": "Oldest pending", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "noValue": "none", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 2592000 + }, + { + "color": "red", + "value": 5184000 + } + ] + }, + "unit": "dtdurations" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-215": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "time() - windows_update_scrape_timestamp_seconds{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Time since the collector last queried Windows Update. Orange after 1 day, red after 7 days. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 215, + "links": [], + "title": "Last check", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 86400 + }, + { + "color": "red", + "value": 604800 + } + ] + }, + "unit": "dtdurations" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-216": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (title, category, severity) ((windows_update_pending_published_timestamp{job=~\"$job\", instance=\"$instance\"} * on (id, revision) group_right windows_update_pending_info{job=~\"$job\", instance=\"$instance\"}) or on (id, revision) (0 * windows_update_pending_info{job=~\"$job\", instance=\"$instance\"})) * 1000", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [ + { + "group": "organize", + "kind": "Transformation", + "spec": { + "options": { + "excludeByName": { + "Time": true + }, + "includeByName": {}, + "indexByName": { + "Value": 3, + "category": 1, + "severity": 2, + "title": 0 + }, + "renameByName": { + "Value": "Published", + "category": "Category", + "severity": "Severity", + "title": "Update" + } + } + } + } + ] + } + }, + "description": "Pending updates with their category, security severity and publish date. Category names follow the Windows display language. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 216, + "links": [], + "title": "Pending updates", + "vizConfig": { + "group": "table", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "filterable": false, + "inspect": false, + "minWidth": 60 + }, + "mappings": [ + { + "options": { + "0": { + "index": 0, + "text": "unknown" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "dateTimeFromNow" + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "Severity" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "text", + "mode": "fixed" + } + }, + { + "id": "mappings", + "value": [ + { + "options": { + "Critical": { + "color": "red", + "index": 0 + }, + "Important": { + "color": "orange", + "index": 1 + } + }, + "type": "value" + } + ] + }, + { + "id": "custom.cellOptions", + "value": { + "type": "color-text" + } + } + ] + } + ] + }, + "options": { + "cellHeight": "sm", + "enablePagination": false, + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true, + "sortBy": [ + { + "desc": false, + "displayName": "Published" + } + ] + } + }, + "version": "" + } + } + }, + "panel-217": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "count by (category) (windows_update_pending_info{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "{{category}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Number of pending updates per update category. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 217, + "links": [], + "title": "Pending updates by category", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 80, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-218": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_update_scrape_query_duration_seconds{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "query duration", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Duration of the last background query to the Windows Update API. Slow queries can point to a slow or unreachable update server. Requires the update collector, which is not enabled by default. The collector queries Windows Update in the background, every 6 hours by default.", + "id": 218, + "links": [], + "title": "Windows Update query duration", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, "panel-22": { "kind": "Panel", "spec": { @@ -7873,6 +13618,1971 @@ } } }, + "panel-220": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_smb_server_shares_current_open_file_count{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Files open on the shares of this SMB server. Requires the smb collector, which is not enabled by default.", + "id": 220, + "links": [], + "title": "Open files", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-221": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(windows_smb_server_shares_tree_connect_count{job=~\"$job\", instance=\"$instance\"})", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Client connections (tree connects) to the shares of this SMB server. Requires the smb collector, which is not enabled by default.", + "id": 221, + "links": [], + "title": "Connections", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-222": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_smb_server_shares_received_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) + sum(rate(windows_smb_server_shares_sent_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bytes sent and received per second by the shares of this SMB server. Requires the smb collector, which is not enabled by default.", + "id": 222, + "links": [], + "title": "Server traffic", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-223": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_smbclient_data_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Bytes read and written per second by this host on remote SMB shares. Requires the smbclient collector, which is not enabled by default.", + "id": 223, + "links": [], + "title": "Client traffic", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "fixedColor": "text", + "mode": "fixed" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "text", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-224": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "(sum(rate(windows_smbclient_request_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) / (sum(rate(windows_smbclient_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])) > 0)) or (0 * sum(rate(windows_smbclient_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Average time per request of this host on remote SMB shares. 0 when there are no requests. Requires the smbclient collector, which is not enabled by default.", + "id": 224, + "links": [], + "title": "Client latency", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 0.02 + }, + { + "color": "red", + "value": 0.05 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-225": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "sum(rate(windows_smbclient_stalls_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]))", + "instant": false, + "legendFormat": "__auto", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": { + "maxDataPoints": 100 + }, + "transformations": [] + } + }, + "description": "Requests per second delayed because the server granted too few SMB credits. Sustained stalls limit throughput. Requires the smbclient collector, which is not enabled by default.", + "id": 225, + "links": [], + "title": "Credit stalls", + "vizConfig": { + "group": "stat", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "orange", + "value": 1 + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + } + }, + "version": "" + } + } + }, + "panel-226": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_sent_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}} sent", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_received_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}} received", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Bytes sent and received per second per share. Received bytes are drawn below the axis. Requires the smb collector, which is not enabled by default.", + "id": 226, + "links": [], + "title": "Share traffic", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* received$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-227": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_read_requests_count_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}} read", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_write_requests_count_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}} write", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_metadata_requests_count_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}} metadata", + "range": true + }, + "version": "v0" + }, + "refId": "C" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Read, write and metadata requests per second per share. Requires the smb collector, which is not enabled by default.", + "id": 227, + "links": [], + "title": "Share requests", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-228": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_smb_server_shares_current_open_file_count{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Files open per share. Requires the smb collector, which is not enabled by default.", + "id": 228, + "links": [], + "title": "Open files", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-229": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_smb_server_shares_tree_connect_count{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Client connections (tree connects) per share. Requires the smb collector, which is not enabled by default.", + "id": 229, + "links": [], + "title": "Connections", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-230": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smb_server_shares_files_opened_count_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Files opened per second per share. Requires the smb collector, which is not enabled by default.", + "id": 230, + "links": [], + "title": "Files opened", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-231": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_write_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_read_bytes_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Bytes read and written per second per remote share. Reads are drawn below the axis. Requires the smbclient collector, which is not enabled by default.", + "id": 231, + "links": [], + "title": "Client traffic", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "Bps" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-232": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_write_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_read_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Read and write requests per second per remote share. Reads are drawn below the axis. Requires the smbclient collector, which is not enabled by default.", + "id": 232, + "links": [], + "title": "Client requests", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-233": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_write_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_smbclient_write_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0)", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} write", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_read_seconds_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) / (rate(windows_smbclient_read_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval]) > 0)", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}} read", + "range": true + }, + "version": "v0" + }, + "refId": "B" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Average time per read and write request per remote share. Reads are drawn below the axis. Requires the smbclient collector, which is not enabled by default.", + "id": 233, + "links": [], + "title": "Client latency", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "s" + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": ".* read$" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-234": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "windows_smbclient_requests_queued{job=~\"$job\", instance=\"$instance\"}", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Requests outstanding per remote share at the time of the scrape. Requires the smbclient collector, which is not enabled by default.", + "id": 234, + "links": [], + "title": "Client queue length", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "short" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-235": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_stalls_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Requests per second per remote share delayed because the server granted too few SMB credits. Requires the smbclient collector, which is not enabled by default.", + "id": 235, + "links": [], + "title": "Credit stalls", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, + "panel-236": { + "kind": "Panel", + "spec": { + "data": { + "kind": "QueryGroup", + "spec": { + "queries": [ + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "rate(windows_smbclient_metadata_requests_total{job=~\"$job\", instance=\"$instance\"}[$__rate_interval])", + "instant": false, + "legendFormat": "\\\\{{server}}\\{{share}}", + "range": true + }, + "version": "v0" + }, + "refId": "A" + } + } + ], + "queryOptions": {}, + "transformations": [] + } + }, + "description": "Metadata requests per second per remote share, such as opening files and listing directories. Requires the smbclient collector, which is not enabled by default.", + "id": 236, + "links": [], + "title": "Metadata requests", + "vizConfig": { + "group": "timeseries", + "kind": "VizConfig", + "spec": { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 4, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "ops" + }, + "overrides": [] + }, + "options": { + "legend": { + "calcs": [ + "mean", + "max", + "lastNotNull" + ], + "displayMode": "table", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "desc" + } + } + }, + "version": "" + } + } + }, "panel-24": { "kind": "Panel", "spec": { @@ -9656,6 +17366,29 @@ }, "refId": "C" } + }, + { + "kind": "PanelQuery", + "spec": { + "hidden": false, + "query": { + "datasource": { + "name": "${datasource}" + }, + "group": "prometheus", + "kind": "DataQuery", + "spec": { + "editorMode": "code", + "expr": "max by (volume, volume_name, disk, filesystem) (windows_logical_disk_info{job=~\"$job\", instance=\"$instance\", volume=~\"$volume\"})", + "format": "table", + "instant": true, + "legendFormat": "__auto", + "range": false + }, + "version": "v0" + }, + "refId": "D" + } } ], "queryOptions": {}, @@ -9680,6 +17413,8 @@ "Time 1": true, "Time 2": true, "Time 3": true, + "Time 4": true, + "Value #D": true, "__name__": true, "instance": true, "instance 1": true, @@ -9696,16 +17431,22 @@ }, "includeByName": {}, "indexByName": { - "Value #A": 1, - "Value #B": 2, - "Value #C": 3, - "volume": 0 + "Value #A": 4, + "Value #B": 5, + "Value #C": 6, + "disk": 2, + "filesystem": 3, + "volume": 0, + "volume_name": 1 }, "renameByName": { "Value #A": "Size", "Value #B": "Free", "Value #C": "Used", - "volume": "Volume" + "disk": "Disk", + "filesystem": "File system", + "volume": "Volume", + "volume_name": "Label" } } } @@ -9713,7 +17454,7 @@ ] } }, - "description": "Size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.", + "description": "Label, physical disk number, file system, size, available space and used percentage of each selected logical volume. Windows free-space counters can lag by 10 to 15 minutes; use trends rather than treating a single sample as immediate confirmation of reclaimed space.", "id": 37, "links": [], "title": "Volumes", @@ -10264,7 +18005,7 @@ "description": "Reads are drawn below the axis.", "id": 40, "links": [], - "title": "Disk throughput", + "title": "Volume throughput", "vizConfig": { "group": "timeseries", "kind": "VizConfig", @@ -10413,7 +18154,7 @@ "description": "Reads are drawn below the axis.", "id": 41, "links": [], - "title": "Disk IOPS", + "title": "Volume IOPS", "vizConfig": { "group": "timeseries", "kind": "VizConfig", @@ -10562,7 +18303,7 @@ "description": "Average time per read and write operation. Reads are drawn below the axis.", "id": 42, "links": [], - "title": "Disk latency", + "title": "Volume latency", "vizConfig": { "group": "timeseries", "kind": "VizConfig", @@ -10711,7 +18452,7 @@ "description": "Average number of read and write requests queued for the volume. Reads are drawn below the axis. A queue that stays high while latency rises indicates a disk bottleneck.", "id": 43, "links": [], - "title": "Disk queue length", + "title": "Volume queue length", "vizConfig": { "group": "timeseries", "kind": "VizConfig", @@ -11565,9 +19306,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_service_state{job=~\"$job\", instance=\"$instance\", state=\"running\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -11575,7 +19316,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -11590,7 +19333,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "thresholds": { "mode": "absolute", @@ -11601,13 +19345,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -11647,9 +19391,9 @@ "spec": { "editorMode": "code", "expr": "count(windows_service_state{job=~\"$job\", instance=\"$instance\", state=\"running\"} == 0 and on (name) windows_service_start_mode{job=~\"$job\", instance=\"$instance\", start_mode=\"auto\"} == 1) or vector(0)", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -11657,7 +19401,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -11687,13 +19433,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -11733,9 +19479,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_service_state{job=~\"$job\", instance=\"$instance\", state=~\".* pending\"}) or vector(0)", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -11743,7 +19489,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -11773,13 +19521,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -11819,9 +19567,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_service_start_mode{job=~\"$job\", instance=\"$instance\", start_mode=\"disabled\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -11829,7 +19577,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -11844,7 +19594,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "thresholds": { "mode": "absolute", @@ -11855,13 +19606,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -13187,9 +20938,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_hyperv_virtual_machine_health_total_count{job=~\"$job\", instance=\"$instance\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -13197,7 +20948,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -13212,7 +20965,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "thresholds": { "mode": "absolute", @@ -13223,13 +20977,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -13269,9 +21023,9 @@ "spec": { "editorMode": "code", "expr": "sum(windows_hyperv_virtual_machine_health_total_count{job=~\"$job\", instance=\"$instance\", state=\"critical\"})", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -13279,7 +21033,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -13309,13 +21065,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -13456,9 +21212,9 @@ "spec": { "editorMode": "code", "expr": "windows_hyperv_host_logical_processor_count{job=~\"$job\", instance=\"$instance\"}", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -13466,7 +21222,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -13481,7 +21239,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "thresholds": { "mode": "absolute", @@ -13492,13 +21251,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -13538,9 +21297,9 @@ "spec": { "editorMode": "code", "expr": "windows_hyperv_total_vm_processor_count{job=~\"$job\", instance=\"$instance\"}", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -13548,7 +21307,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -13563,7 +21324,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "thresholds": { "mode": "absolute", @@ -13574,13 +21336,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -13620,9 +21382,9 @@ "spec": { "editorMode": "code", "expr": "windows_hyperv_total_vm_processor_count{job=~\"$job\", instance=\"$instance\"} / windows_hyperv_host_logical_processor_count{job=~\"$job\", instance=\"$instance\"}", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -13630,7 +21392,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -13645,7 +21409,8 @@ "fieldConfig": { "defaults": { "color": { - "mode": "thresholds" + "fixedColor": "text", + "mode": "fixed" }, "decimals": 2, "thresholds": { @@ -13657,13 +21422,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -15599,9 +23364,9 @@ "spec": { "editorMode": "code", "expr": "windows_time_ntp_client_time_sources{job=~\"$job\", instance=\"$instance\"}", - "instant": true, + "instant": false, "legendFormat": "__auto", - "range": false + "range": true }, "version": "v0" }, @@ -15609,7 +23374,9 @@ } } ], - "queryOptions": {}, + "queryOptions": { + "maxDataPoints": 100 + }, "transformations": [] } }, @@ -15639,13 +23406,13 @@ } ] }, - "unit": "none" + "unit": "short" }, "overrides": [] }, "options": { "colorMode": "value", - "graphMode": "none", + "graphMode": "area", "justifyMode": "auto", "orientation": "auto", "percentChangeColorMode": "standard", @@ -16992,98 +24759,140 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-2" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-2" + }, + "height": 10, + "width": 24, + "x": 0, + "y": 0 + } + } + ] + } }, - "height": 10, - "width": 24, - "x": 0, - "y": 0 + "title": "Hosts" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-3" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-3" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-4" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-5" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 0, - "y": 10 + "title": "Utilization" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-4" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-6" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-7" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-8" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 8, - "y": 10 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-5" - }, - "height": 8, - "width": 8, - "x": 16, - "y": 10 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-6" - }, - "height": 8, - "width": 8, - "x": 0, - "y": 18 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-7" - }, - "height": 8, - "width": 8, - "x": 8, - "y": 18 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-8" - }, - "height": 8, - "width": 8, - "x": 16, - "y": 18 + "title": "Throughput and errors" } } ] @@ -17096,176 +24905,218 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-10" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-10" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-11" + }, + "height": 4, + "width": 3, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-12" + }, + "height": 4, + "width": 2, + "x": 7, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-13" + }, + "height": 4, + "width": 2, + "x": 9, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-14" + }, + "height": 4, + "width": 3, + "x": 11, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-15" + }, + "height": 4, + "width": 3, + "x": 14, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-16" + }, + "height": 4, + "width": 3, + "x": 17, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-17" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-11" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-18" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-19" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 3, - "x": 4, - "y": 0 + "title": "CPU and memory" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-12" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-20" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-21" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-22" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 2, - "x": 7, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-13" - }, - "height": 4, - "width": 2, - "x": 9, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-14" - }, - "height": 4, - "width": 3, - "x": 11, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-15" - }, - "height": 4, - "width": 3, - "x": 14, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-16" - }, - "height": 4, - "width": 3, - "x": 17, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-17" - }, - "height": 4, - "width": 4, - "x": 20, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-18" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 4 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-19" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 4 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-20" - }, - "height": 8, - "width": 8, - "x": 0, - "y": 12 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-21" - }, - "height": 8, - "width": 8, - "x": 8, - "y": 12 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-22" - }, - "height": 8, - "width": 8, - "x": 16, - "y": 12 + "title": "Storage and network" } } ] @@ -17278,98 +25129,232 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-24" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-160" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-161" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-162" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-163" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-164" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-165" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 10, - "width": 12, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-25" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-24" + }, + "height": 10, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-25" + }, + "height": 10, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 10, - "width": 12, - "x": 12, - "y": 0 + "title": "Utilization" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-26" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-26" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-27" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-28" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 0, - "y": 10 + "title": "Scheduling" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-27" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-29" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-30" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 8, - "y": 10 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-28" - }, - "height": 8, - "width": 8, - "x": 16, - "y": 10 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-29" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 18 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-30" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 18 + "title": "System calls and frequency" } } ] @@ -17382,59 +25367,179 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-32" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-166" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-167" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-168" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-169" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-170" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-171" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-33" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-32" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-33" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 0 + "title": "Physical memory and commit" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-34" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-34" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-35" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 8 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-35" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 8 + "title": "Paging and kernel memory" } } ] @@ -17447,98 +25552,350 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-37" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-172" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-200" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-174" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-175" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-176" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-177" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-38" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-37" + }, + "height": 7, + "width": 24, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-38" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 7 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-39" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 7 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 8, - "y": 0 + "title": "Volumes" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-39" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-40" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-41" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-42" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-43" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 8 + } + } + ] + } }, - "height": 8, - "width": 8, - "x": 16, - "y": 0 + "title": "Volume I/O" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-40" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-201" + }, + "height": 6, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-202" + }, + "height": 6, + "width": 20, + "x": 4, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 8 + "title": "Drives" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-41" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-203" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-204" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-205" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-206" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-207" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 16 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-208" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 16 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 8 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-42" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 16 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-43" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 16 + "title": "Physical disks" } } ] @@ -17554,6 +25911,98 @@ "kind": "RowsLayout", "spec": { "rows": [ + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-178" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-179" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-180" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-181" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-182" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-183" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } + }, + "title": "Summary" + } + }, { "kind": "RowsLayoutRow", "spec": { @@ -17736,189 +26185,521 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-150" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-220" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-221" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-222" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-223" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-224" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-225" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-151" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-226" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-227" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-228" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-229" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-230" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 8 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 4, - "y": 0 + "title": "Server shares" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-152" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-231" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-232" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-233" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-234" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-235" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 16 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-236" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 16 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 8, - "y": 0 + "title": "Client shares" + } + } + ] + } + }, + "title": "SMB" + } + }, + { + "kind": "TabsLayoutTab", + "spec": { + "layout": { + "kind": "RowsLayout", + "spec": { + "rows": [ + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-150" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-151" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-152" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-153" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-154" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-155" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } + }, + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-153" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-112" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-113" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-114" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-119" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 8 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 12, - "y": 0 + "title": "CPU and memory" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-154" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-115" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-118" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 16, - "y": 0 + "title": "I/O" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-155" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-116" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-117" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 4, - "x": 20, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-112" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 4 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-113" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 4 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-114" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 12 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-115" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 12 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-116" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 20 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-117" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 20 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-118" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 28 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-119" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 28 + "title": "Threads and handles" } } ] @@ -17931,85 +26712,113 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-50" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-50" + }, + "height": 4, + "width": 6, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-51" + }, + "height": 4, + "width": 6, + "x": 6, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-52" + }, + "height": 4, + "width": 6, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-53" + }, + "height": 4, + "width": 6, + "x": 18, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 6, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-51" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-54" + }, + "height": 10, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-55" + }, + "height": 10, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 6, - "x": 6, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-52" - }, - "height": 4, - "width": 6, - "x": 12, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-53" - }, - "height": 4, - "width": 6, - "x": 18, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-54" - }, - "height": 10, - "width": 12, - "x": 0, - "y": 4 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-55" - }, - "height": 10, - "width": 12, - "x": 12, - "y": 4 + "title": "State" } } ] @@ -18022,228 +26831,720 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-57" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-190" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-191" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-192" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-193" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-194" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-195" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } }, - "height": 5, - "width": 24, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-58" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-196" + }, + "height": 10, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-197" + }, + "height": 10, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 5 + "title": "Attention" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-59" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-198" + }, + "height": 20, + "width": 24, + "x": 0, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 5 + "title": "Activity" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-60" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-199" + }, + "height": 14, + "width": 24, + "x": 0, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 13 + "title": "All tasks" + } + } + ] + } + }, + "title": "Scheduled tasks" + } + }, + { + "kind": "TabsLayoutTab", + "spec": { + "layout": { + "kind": "RowsLayout", + "spec": { + "rows": [ + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-210" + }, + "height": 4, + "width": 5, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-211" + }, + "height": 4, + "width": 5, + "x": 5, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-212" + }, + "height": 4, + "width": 5, + "x": 10, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-214" + }, + "height": 4, + "width": 5, + "x": 15, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-215" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } + }, + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-61" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-216" + }, + "height": 10, + "width": 24, + "x": 0, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 13 + "title": "Pending updates" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-120" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-217" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-218" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 21 + "title": "History" + } + } + ] + } + }, + "title": "Updates" + } + }, + { + "kind": "TabsLayoutTab", + "spec": { + "layout": { + "kind": "RowsLayout", + "spec": { + "rows": [ + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-184" + }, + "height": 4, + "width": 4, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-185" + }, + "height": 4, + "width": 4, + "x": 4, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-186" + }, + "height": 4, + "width": 4, + "x": 8, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-187" + }, + "height": 4, + "width": 4, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-188" + }, + "height": 4, + "width": 4, + "x": 16, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-189" + }, + "height": 4, + "width": 4, + "x": 20, + "y": 0 + } + } + ] + } + }, + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-121" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-57" + }, + "height": 5, + "width": 24, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-58" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 5 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-59" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 5 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-125" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 13 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-126" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 13 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-127" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 13 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 21 + "title": "Adapters" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-122" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-120" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-121" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-122" + }, + "height": 8, + "width": 8, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-123" + }, + "height": 8, + "width": 8, + "x": 8, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-124" + }, + "height": 8, + "width": 8, + "x": 16, + "y": 8 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 0, - "y": 29 + "title": "Sensors and clocks" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-123" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-60" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-61" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-128" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-129" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 8 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-130" + }, + "height": 8, + "width": 12, + "x": 0, + "y": 16 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-131" + }, + "height": 8, + "width": 12, + "x": 12, + "y": 16 + } + } + ] + } }, - "height": 8, - "width": 12, - "x": 12, - "y": 29 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-124" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 37 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-125" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 37 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-126" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 45 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-127" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 45 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-128" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 53 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-129" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 53 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-130" - }, - "height": 8, - "width": 12, - "x": 0, - "y": 61 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-131" - }, - "height": 8, - "width": 12, - "x": 12, - "y": 61 + "title": "Processes" } } ] @@ -18344,7 +27645,21 @@ "x": 20, "y": 0 } - }, + } + ] + } + }, + "title": "Summary" + } + }, + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ { "kind": "GridLayoutItem", "spec": { @@ -18355,7 +27670,7 @@ "height": 8, "width": 12, "x": 0, - "y": 4 + "y": 0 } }, { @@ -18368,13 +27683,13 @@ "height": 8, "width": 12, "x": 12, - "y": 4 + "y": 0 } } ] } }, - "title": "Host" + "title": "CPU" } }, { @@ -18546,72 +27861,100 @@ "kind": "TabsLayoutTab", "spec": { "layout": { - "kind": "GridLayout", + "kind": "RowsLayout", "spec": { - "items": [ + "rows": [ { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-84" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-84" + }, + "height": 4, + "width": 6, + "x": 0, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-85" + }, + "height": 4, + "width": 6, + "x": 6, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-86" + }, + "height": 4, + "width": 6, + "x": 12, + "y": 0 + } + }, + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-87" + }, + "height": 4, + "width": 6, + "x": 18, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 6, - "x": 0, - "y": 0 + "title": "Summary" } }, { - "kind": "GridLayoutItem", + "kind": "RowsLayoutRow", "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-85" + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ + { + "kind": "GridLayoutItem", + "spec": { + "element": { + "kind": "ElementReference", + "name": "panel-88" + }, + "height": 8, + "width": 24, + "x": 0, + "y": 0 + } + } + ] + } }, - "height": 4, - "width": 6, - "x": 6, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-86" - }, - "height": 4, - "width": 6, - "x": 12, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-87" - }, - "height": 4, - "width": 6, - "x": 18, - "y": 0 - } - }, - { - "kind": "GridLayoutItem", - "spec": { - "element": { - "kind": "ElementReference", - "name": "panel-88" - }, - "height": 8, - "width": 24, - "x": 0, - "y": 4 + "title": "Clock" } } ] @@ -18712,7 +28055,21 @@ "x": 20, "y": 0 } - }, + } + ] + } + }, + "title": "Summary" + } + }, + { + "kind": "RowsLayoutRow", + "spec": { + "collapse": false, + "layout": { + "kind": "GridLayout", + "spec": { + "items": [ { "kind": "GridLayoutItem", "spec": { @@ -18723,7 +28080,7 @@ "height": 8, "width": 12, "x": 0, - "y": 4 + "y": 0 } }, { @@ -18736,7 +28093,7 @@ "height": 8, "width": 12, "x": 12, - "y": 4 + "y": 0 } } ]