mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-21 03:59:04 +02:00
contrib: expand Windows mixin rules and publish runbooks (#2575)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
@@ -21,4 +21,10 @@ rule {
|
||||
value = ".+"
|
||||
severity = "bug"
|
||||
}
|
||||
|
||||
annotation "runbook_url" {
|
||||
required = true
|
||||
value = "https?://.+"
|
||||
severity = "bug"
|
||||
}
|
||||
}
|
||||
|
||||
+13
-6
@@ -2,24 +2,27 @@ JSONNET ?= jsonnet
|
||||
JSONNETFMT ?= jsonnetfmt
|
||||
PROMTOOL ?= promtool
|
||||
PINT ?= pint
|
||||
PYTHON ?= python3
|
||||
|
||||
# renovate: go=github.com/google/go-jsonnet
|
||||
JSONNET_VERSION := v0.22.0
|
||||
# renovate: go=github.com/cloudflare/pint
|
||||
PINT_VERSION := v0.89.2
|
||||
SOURCES := $(wildcard *.libsonnet *.jsonnet lib/*.libsonnet rules/*.libsonnet alerts/*.libsonnet tests/*.libsonnet)
|
||||
SOURCES := $(wildcard *.libsonnet *.jsonnet lib/*.libsonnet rules/*.libsonnet alerts/*.libsonnet tests/*.libsonnet tests/*.jsonnet)
|
||||
FMT_FLAGS := -n 2 --max-blank-lines 2 --string-style s --comment-style s
|
||||
|
||||
.DEFAULT_GOAL := generate
|
||||
.DELETE_ON_ERROR:
|
||||
.PHONY: generate tools fmt lint test clean
|
||||
.PHONY: generate tools jsonnet-tools fmt lint test check-runbooks clean
|
||||
|
||||
generate: windows_rules.yaml windows_alerts.yaml
|
||||
|
||||
tools:
|
||||
tools: jsonnet-tools
|
||||
go install github.com/cloudflare/pint/cmd/pint@$(PINT_VERSION)
|
||||
|
||||
jsonnet-tools:
|
||||
go install github.com/google/go-jsonnet/cmd/jsonnet@$(JSONNET_VERSION)
|
||||
go install github.com/google/go-jsonnet/cmd/jsonnetfmt@$(JSONNET_VERSION)
|
||||
go install github.com/cloudflare/pint/cmd/pint@$(PINT_VERSION)
|
||||
|
||||
windows_rules.yaml: $(SOURCES)
|
||||
$(JSONNET) -S rules.jsonnet > $@
|
||||
@@ -44,8 +47,12 @@ lint: generate tests/custom_rules.yaml tests/custom_alerts.yaml
|
||||
$(PINT) --offline lint windows_rules.yaml windows_alerts.yaml
|
||||
$(PINT) --offline lint tests/custom_rules.yaml tests/custom_alerts.yaml
|
||||
|
||||
test: lint
|
||||
$(PROMTOOL) test rules tests/rules.test.yaml tests/alerts.test.yaml tests/custom.test.yaml
|
||||
check-runbooks:
|
||||
$(JSONNET) -e '(import "mixin.libsonnet") { _config+:: { enableActiveDirectory: true, enableTime: true } }.prometheusAlerts' | $(PYTHON) tests/check_runbooks.py ../../docs/runbooks
|
||||
|
||||
test: lint check-runbooks
|
||||
$(JSONNET) tests/runbooks.test.jsonnet
|
||||
$(PROMTOOL) test rules tests/*.test.yaml
|
||||
|
||||
clean:
|
||||
rm -f windows_rules.yaml windows_alerts.yaml tests/custom_rules.yaml tests/custom_alerts.yaml
|
||||
|
||||
+90
-11
@@ -24,7 +24,8 @@ to generate rules. Generated files are ignored by Git:
|
||||
The default selector is `job="windows_exporter"`. Change it to match your scrape
|
||||
job before generating rules. Resource rules use the default `cpu`, `memory`,
|
||||
`logical_disk`, and `net` collectors. Enable `ad` on domain controllers when
|
||||
opting into Active Directory alerts.
|
||||
opting into Active Directory alerts. Clock alerts require the `time` collector
|
||||
with its `ntp` subcollector and are intended for hosts using NTP synchronization.
|
||||
|
||||
Copy both generated files into your Prometheus rule directory and reference
|
||||
them in `prometheus.yml`:
|
||||
@@ -53,6 +54,8 @@ modifying its source. For example, create `custom.libsonnet` in this directory:
|
||||
rateInterval: '5m',
|
||||
cpuHighUsageThreshold: 95,
|
||||
enableActiveDirectory: true,
|
||||
enableTime: true,
|
||||
runbookURLPattern: 'https://runbooks.example.com/windows/%s/',
|
||||
},
|
||||
}
|
||||
```
|
||||
@@ -68,7 +71,8 @@ Selectors are comma-separated Prometheus label matchers without braces. They
|
||||
apply to both recording rules and alerts. All target labels, including `job`,
|
||||
`instance`, `cluster`, and custom selector labels, are preserved. CPU usage
|
||||
averages idle rates across cores and removes only `core` and `mode`. Disk and
|
||||
network recordings also retain `volume` and `nic` respectively.
|
||||
network recordings also retain `volume` and `nic` respectively. The CPU mode
|
||||
recording retains `mode` and removes only `core`.
|
||||
|
||||
`rateInterval` is the fixed window for recording rules and Active Directory
|
||||
failure rates; keep it at least four times your scrape interval. Grafana's
|
||||
@@ -80,18 +84,47 @@ rules.
|
||||
| Metric | Meaning | Unit |
|
||||
| --- | --- | --- |
|
||||
| `windows:cpu_usage:ratio` | Non-idle CPU time averaged across cores | Ratio, 0–1 |
|
||||
| `windows:cpu_cores:count` | Logical processors observed in idle CPU metrics | Count |
|
||||
| `windows:cpu_time:ratio_rate` | CPU time averaged across cores, retaining `mode` | Seconds/second |
|
||||
| `windows:memory_usage:ratio` | Physical memory in use, based on available bytes | Ratio, 0–1 |
|
||||
| `windows:memory_used:bytes` | Total physical memory minus available memory | Bytes |
|
||||
| `windows:memory_cached:bytes` | Cache, modified pages, and three standby lists | Bytes |
|
||||
| `windows:memory_committed:ratio` | Committed bytes divided by the system commit limit | Ratio |
|
||||
| `windows:memory_swap_page_operations:rate` | Paging operations | Operations/second |
|
||||
| `windows:logical_disk_free:ratio` | Free disk space per volume | Ratio, 0–1 |
|
||||
| `windows:logical_disk_used:bytes` | Used disk space per volume | Bytes |
|
||||
| `windows:logical_disk_busy:ratio` | Non-idle time per volume, clamped to 0–1 | Ratio, 0–1 |
|
||||
| `windows:logical_disk_read_bytes:rate` | Disk read throughput per volume | Bytes/second |
|
||||
| `windows:logical_disk_write_bytes:rate` | Disk write throughput per volume | Bytes/second |
|
||||
| `windows:logical_disk_read_operations:rate` | Disk reads per volume | Operations/second |
|
||||
| `windows:logical_disk_write_operations:rate` | Disk writes per volume | Operations/second |
|
||||
| `windows:logical_disk_read_latency:seconds` | Read-time rate divided by read-operation rate | Seconds/operation |
|
||||
| `windows:logical_disk_write_latency:seconds` | Write-time rate divided by write-operation rate | Seconds/operation |
|
||||
| `windows:net_received_bytes:rate` | Received network traffic per interface | Bytes/second |
|
||||
| `windows:net_sent_bytes:rate` | Sent network traffic per interface | Bytes/second |
|
||||
| `windows:net_received_utilization:ratio` | Received throughput divided by interface bandwidth | Ratio |
|
||||
| `windows:net_sent_utilization:ratio` | Sent throughput divided by interface bandwidth | Ratio |
|
||||
| `windows:net_received_errors:rate` | Inbound packet errors | Packets/second |
|
||||
| `windows:net_outbound_errors:rate` | Outbound packet errors | Packets/second |
|
||||
| `windows:net_received_discarded:rate` | Inbound discarded packets | Packets/second |
|
||||
| `windows:net_outbound_discarded:rate` | Outbound discarded packets | Packets/second |
|
||||
|
||||
The names remain stable when `rateInterval` changes. Dashboard authors can use
|
||||
these recordings or query raw exporter metrics directly. CPU usage measures
|
||||
non-idle time; it is not the frequency-adjusted processor utility shown in
|
||||
Windows Task Manager.
|
||||
|
||||
CPU DPC and interrupt modes overlap privileged time; do not sum all modes.
|
||||
Disk busy time uses the idle counter rather than summing read and write time,
|
||||
which can exceed wall time for concurrent I/O. Latency is an average and is
|
||||
omitted when there are no operations. Memory, disk space, commit, and network
|
||||
utilization ratios are omitted when their capacity is zero or missing. Network
|
||||
bandwidth is already in bytes/second; receive and send utilization are separate
|
||||
for full-duplex links.
|
||||
The cache recording includes modified pages and is not a measure of immediately
|
||||
reclaimable memory. Paging operations can include file-backed pages as well as
|
||||
pagefile traffic.
|
||||
|
||||
## Alerts
|
||||
|
||||
Threshold configuration values below are percentages except where noted.
|
||||
@@ -102,11 +135,18 @@ Threshold configuration values below are percentages except where noted.
|
||||
| `WindowsCollectorFailed` | `windows_exporter_collector_success == 0` | 5m | Warning |
|
||||
| `WindowsCPUHighUsage` | CPU usage above `cpuHighUsageThreshold` (90%) | 15m | Warning |
|
||||
| `WindowsMemoryHighUsage` | Memory usage above `memoryHighUsageThreshold` (90%) | 15m | Warning |
|
||||
| `WindowsMemoryCommitHighUsage` | Commit usage above `memoryCommitHighUsageThreshold` (90%) | 15m | Warning |
|
||||
| `WindowsDiskReadLatencyHigh` | Average read latency above `diskLatencyThresholdSeconds` (0.05 seconds) | 15m | Warning |
|
||||
| `WindowsDiskWriteLatencyHigh` | Average write latency above `diskLatencyThresholdSeconds` (0.05 seconds) | 15m | Warning |
|
||||
| `WindowsNetworkErrors` | Combined receive/outbound errors above `networkErrorRateThreshold` (1 packet/second) | 15m | Warning |
|
||||
| `WindowsNetworkDiscards` | Combined receive/outbound discards above `networkDiscardRateThreshold` (1 packet/second) | 15m | Warning |
|
||||
| `WindowsDiskAlmostFull` | Free space below `diskFreeWarningThreshold` (10%) | 15m | Warning |
|
||||
| `WindowsDiskAlmostFull` | Free space below `diskFreeCriticalThreshold` (5%) | 15m | Critical |
|
||||
| `WindowsDiskFillingUp` | Below the warning threshold and predicted to fill within `diskPredictionHours` (24h), using `diskPredictionWindow` (6h) | 1h | Warning |
|
||||
| `WindowsADPendingReplication` | Pending operations above `adPendingReplicationThreshold` (50) | 15m | Warning |
|
||||
| `WindowsADReplicationFailures` | Failed synchronization requests above `adReplicationFailureRateThreshold` (0 requests/second) | 15m | Warning |
|
||||
| `WindowsClockNotSynchronising` | No active NTP time sources | 10m | Warning |
|
||||
| `WindowsClockSkewDetected` | Absolute reported time offset above `clockOffsetThresholdSeconds` (0.05 seconds) | 10m | Warning |
|
||||
|
||||
Active Directory alerts are generated only when `enableActiveDirectory` is
|
||||
`true`. `criticalSeverity` defaults to `critical` and can be overridden to match
|
||||
@@ -114,6 +154,12 @@ your routing labels. Below the critical disk threshold, both disk severity
|
||||
levels fire; configure Alertmanager inhibition if only the critical
|
||||
notification should be sent.
|
||||
|
||||
Clock alerts are generated only when `enableTime` is `true`. A zero NTP source
|
||||
count may be expected on hosts using another time provider. The offset compares
|
||||
the host to its chosen source and does not independently verify that source.
|
||||
Disk latency and network error/discard thresholds should be tuned for the
|
||||
storage tier, traffic volume, and application requirements.
|
||||
|
||||
Windows disk size/free-space counters may lag by 10–15 minutes. Predictions
|
||||
depend on a sustained trend and are intentionally delayed for an hour. A target
|
||||
removed from service discovery has no `up` series and will not trigger
|
||||
@@ -121,9 +167,35 @@ removed from service discovery has no `up` series and will not trigger
|
||||
scrape and collector-failure alerts cover explicit failures, not disabled
|
||||
collectors.
|
||||
|
||||
## Runbooks and GitHub Pages
|
||||
|
||||
Every alert receives a `runbook_url` annotation pointing to a dedicated page in
|
||||
[docs/runbooks](../../docs/runbooks). Each page describes the meaning, impact,
|
||||
diagnosis, and mitigation, including Windows commands and related metrics.
|
||||
The default URL is
|
||||
`https://prometheus-community.github.io/windows_exporter/runbooks/<lowercase-alert-name>/`.
|
||||
Override `runbookURLPattern` for a fork, custom domain, or internal runbook site;
|
||||
it takes one `%s` placeholder for the lowercase alert name. Explicit
|
||||
`runbook_url` annotations supplied by downstream alerts are preserved.
|
||||
|
||||
The theme-free Hugo site uses `docs/hugo.toml`. With Hugo 0.167.0 installed,
|
||||
preview it from the repository root:
|
||||
|
||||
```sh
|
||||
hugo server --source docs
|
||||
```
|
||||
|
||||
Build it with `hugo --source docs --minify`. The `Runbooks` workflow builds site
|
||||
changes on pull requests, checks alert coverage and internal links, and publishes
|
||||
default-branch changes with `configure-pages`, `upload-pages-artifact`, and
|
||||
`deploy-pages`. This uses the
|
||||
repository's GitHub Pages **Source: GitHub Actions** setting. The workflow reads
|
||||
the configured Pages URL, including custom domains and repository subpaths.
|
||||
Fork users should override `runbookURLPattern` to match their published URL.
|
||||
|
||||
## Validate
|
||||
|
||||
Install `promtool` from a [Prometheus release](https://github.com/prometheus/prometheus/releases),
|
||||
Install Python 3 and `promtool` from a [Prometheus release](https://github.com/prometheus/prometheus/releases),
|
||||
then run:
|
||||
|
||||
```sh
|
||||
@@ -132,10 +204,12 @@ make test
|
||||
|
||||
This checks Jsonnet formatting, validates generated rules with `promtool`, runs
|
||||
`pint --offline lint`, and evaluates the rules against synthetic time series.
|
||||
Tests cover all seven recordings, alert timing and recovery, threshold
|
||||
boundaries, counter resets, disk forecasts, target-label preservation, and
|
||||
custom selectors/thresholds with Active Directory enabled. CI uses Prometheus
|
||||
3.15.0 and the same pinned tool versions as `make tools`.
|
||||
Tests cover all 25 recordings, alert timing and recovery, threshold
|
||||
boundaries, counter resets, zero denominators, disk forecasts, target-label
|
||||
preservation, and custom selectors/thresholds with Active Directory and clock
|
||||
alerts enabled. Runbook checks include opt-in alerts and verify that their pages
|
||||
and URLs exist. CI uses Prometheus 3.15.0 and the same pinned tool versions as
|
||||
`make tools`.
|
||||
|
||||
If you prefer to run `promtool` through Docker:
|
||||
|
||||
@@ -143,10 +217,15 @@ If you prefer to run `promtool` through Docker:
|
||||
make test PROMTOOL="docker run --rm --entrypoint promtool -v \"$PWD:/mixin:ro\" -w /mixin prom/prometheus:v3.15.0"
|
||||
```
|
||||
|
||||
`.pint.hcl` requires a non-empty severity label and summary/description
|
||||
annotations on alerts, in addition to pint's built-in checks. CI uses offline
|
||||
mode without a Prometheus endpoint. To validate metric availability and labels
|
||||
against your own server, copy `.pint.hcl` to a local configuration, add:
|
||||
The dedicated `Mixin` workflow runs on changes to `contrib/mixin/**` or its own
|
||||
workflow file, and can also be started manually. It caches pinned tool binaries
|
||||
and runs the same `make test` checks used locally.
|
||||
|
||||
`.pint.hcl` requires a non-empty severity label, summary/description annotations,
|
||||
and an HTTP(S) runbook URL on alerts, in addition to pint's built-in checks.
|
||||
CI uses offline mode without a Prometheus endpoint. To validate metric
|
||||
availability and labels against your own server, copy `.pint.hcl` to a local
|
||||
configuration, add:
|
||||
|
||||
```hcl
|
||||
prometheus "local" {
|
||||
|
||||
@@ -45,6 +45,41 @@
|
||||
'Windows memory usage is high',
|
||||
'Physical memory usage on {{ $labels.instance }} has exceeded %s%% for 15 minutes.' % c.memoryHighUsageThreshold
|
||||
),
|
||||
alert(
|
||||
'WindowsMemoryCommitHighUsage',
|
||||
q.metric('windows:memory_committed:ratio') + ' * 100 > %s' % c.memoryCommitHighUsageThreshold,
|
||||
'15m',
|
||||
'warning',
|
||||
'Windows memory commit usage is high',
|
||||
'Committed memory on {{ $labels.instance }} has exceeded %s%% of the commit limit for 15 minutes.' % c.memoryCommitHighUsageThreshold
|
||||
),
|
||||
] + [
|
||||
alert(
|
||||
'WindowsDisk%sLatencyHigh' % direction[0],
|
||||
q.metric('windows:logical_disk_%s_latency:seconds' % direction[1], [c.volumeSelector]) + ' > %g' % c.diskLatencyThresholdSeconds,
|
||||
'15m',
|
||||
'warning',
|
||||
'Windows disk %s latency is high' % direction[1],
|
||||
'Volume {{ $labels.volume }} on {{ $labels.instance }} has averaged more than %g seconds per %s operation for 15 minutes.' % [c.diskLatencyThresholdSeconds, direction[1]]
|
||||
)
|
||||
for direction in [['Read', 'read'], ['Write', 'write']]
|
||||
] + [
|
||||
alert(
|
||||
'WindowsNetwork%s' % outcome[0],
|
||||
'(%s + %s) > %g' % [
|
||||
q.metric('windows:net_received_%s:rate' % outcome[1], [c.nicSelector]),
|
||||
q.metric('windows:net_outbound_%s:rate' % outcome[1], [c.nicSelector]),
|
||||
outcome[2],
|
||||
],
|
||||
'15m',
|
||||
'warning',
|
||||
'Windows network packet %s are high' % outcome[3],
|
||||
'Packet %s on interface {{ $labels.nic }} on {{ $labels.instance }} have exceeded %g per second for 15 minutes.' % [outcome[3], outcome[2]]
|
||||
)
|
||||
for outcome in [
|
||||
['Errors', 'errors', c.networkErrorRateThreshold, 'errors'],
|
||||
['Discards', 'discarded', c.networkDiscardRateThreshold, 'discards'],
|
||||
]
|
||||
] + [
|
||||
alert(
|
||||
'WindowsDiskAlmostFull',
|
||||
@@ -74,25 +109,47 @@
|
||||
),
|
||||
],
|
||||
},
|
||||
] + if c.enableActiveDirectory then [
|
||||
] + (if c.enableActiveDirectory then [
|
||||
{
|
||||
name: 'windows-active-directory',
|
||||
rules: [
|
||||
alert(
|
||||
'WindowsADPendingReplication',
|
||||
q.metric('windows_ad_replication_pending_operations') + ' > %s' % c.adPendingReplicationThreshold,
|
||||
'15m',
|
||||
'warning',
|
||||
'Active Directory replication queue is high',
|
||||
'Pending replication operations on {{ $labels.instance }} have exceeded %s for 15 minutes.' % c.adPendingReplicationThreshold
|
||||
),
|
||||
alert(
|
||||
'WindowsADReplicationFailures',
|
||||
'(' + q.rate('windows_ad_replication_sync_requests_total') + ' - ' + q.rate('windows_ad_replication_sync_requests_success_total') + ') > %s' % c.adReplicationFailureRateThreshold,
|
||||
'15m',
|
||||
'warning',
|
||||
'Active Directory replication requests are failing',
|
||||
'Replication synchronization requests on {{ $labels.instance }} have been failing for 15 minutes.'
|
||||
),
|
||||
],
|
||||
},
|
||||
] else []) + if c.enableTime then [
|
||||
{
|
||||
name: 'windows-active-directory',
|
||||
name: 'windows-time',
|
||||
rules: [
|
||||
alert(
|
||||
'WindowsADPendingReplication',
|
||||
q.metric('windows_ad_replication_pending_operations') + ' > %s' % c.adPendingReplicationThreshold,
|
||||
'15m',
|
||||
'WindowsClockNotSynchronising',
|
||||
q.metric('windows_time_ntp_client_time_sources') + ' == 0',
|
||||
'10m',
|
||||
'warning',
|
||||
'Active Directory replication queue is high',
|
||||
'Pending replication operations on {{ $labels.instance }} have exceeded %s for 15 minutes.' % c.adPendingReplicationThreshold
|
||||
'Windows clock has no NTP time source',
|
||||
'Windows Time on {{ $labels.instance }} has had no active NTP time source for 10 minutes.'
|
||||
),
|
||||
alert(
|
||||
'WindowsADReplicationFailures',
|
||||
'(' + q.rate('windows_ad_replication_sync_requests_total') + ' - ' + q.rate('windows_ad_replication_sync_requests_success_total') + ') > %s' % c.adReplicationFailureRateThreshold,
|
||||
'15m',
|
||||
'WindowsClockSkewDetected',
|
||||
'abs(%s) > %g' % [q.metric('windows_time_computed_time_offset_seconds'), c.clockOffsetThresholdSeconds],
|
||||
'10m',
|
||||
'warning',
|
||||
'Active Directory replication requests are failing',
|
||||
'Replication synchronization requests on {{ $labels.instance }} have been failing for 15 minutes.'
|
||||
'Windows clock offset is high',
|
||||
'Windows Time on {{ $labels.instance }} reports a clock offset above %g seconds for 10 minutes.' % c.clockOffsetThresholdSeconds
|
||||
),
|
||||
],
|
||||
},
|
||||
|
||||
@@ -8,9 +8,18 @@
|
||||
|
||||
// Opt in only for targets with the ad collector enabled.
|
||||
enableActiveDirectory: false,
|
||||
// Requires the time collector with its ntp subcollector enabled.
|
||||
enableTime: false,
|
||||
|
||||
runbookURLPattern: 'https://prometheus-community.github.io/windows_exporter/runbooks/%s/',
|
||||
|
||||
cpuHighUsageThreshold: 90,
|
||||
memoryHighUsageThreshold: 90,
|
||||
memoryCommitHighUsageThreshold: 90,
|
||||
diskLatencyThresholdSeconds: 0.05,
|
||||
networkErrorRateThreshold: 1,
|
||||
networkDiscardRateThreshold: 1,
|
||||
clockOffsetThresholdSeconds: 0.05,
|
||||
diskFreeWarningThreshold: 10,
|
||||
diskFreeCriticalThreshold: 5,
|
||||
diskPredictionWindow: '6h',
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
prometheusAlerts+:: {
|
||||
groups: [
|
||||
group {
|
||||
rules: [
|
||||
if std.objectHas(rule, 'alert') && !(std.objectHas(rule, 'annotations') && std.objectHas(rule.annotations, 'runbook_url')) then
|
||||
rule {
|
||||
annotations+: {
|
||||
runbook_url: $._config.runbookURLPattern % std.asciiLower(rule.alert),
|
||||
},
|
||||
}
|
||||
else rule
|
||||
for rule in group.rules
|
||||
],
|
||||
}
|
||||
for group in super.groups
|
||||
],
|
||||
},
|
||||
}
|
||||
@@ -3,16 +3,30 @@ function(c)
|
||||
selector(extra=[]): std.join(', ', [s for s in [c.windowsExporterSelector] + extra if s != '']),
|
||||
metric(name, extra=[]): '%s{%s}' % [name, self.selector(extra)],
|
||||
rate(name, extra=[]): 'rate(%s[%s])' % [self.metric(name, extra), c.rateInterval],
|
||||
// Drop undefined ratios instead of recording NaN or +Inf for idle devices.
|
||||
ratio(numerator, denominator): '(%s / (%s > 0))' % [numerator, denominator],
|
||||
cpuUsage:
|
||||
'1 - avg without (core, mode) (%s)' % self.rate('windows_cpu_time_total', ['mode="idle"']),
|
||||
memoryUsage:
|
||||
'1 - %s / %s' % [
|
||||
'1 - %s' % self.ratio(
|
||||
self.metric('windows_memory_available_bytes'),
|
||||
self.metric('windows_memory_physical_total_bytes'),
|
||||
],
|
||||
self.metric('windows_memory_physical_total_bytes')
|
||||
),
|
||||
diskFree:
|
||||
'%s / %s' % [
|
||||
self.ratio(
|
||||
self.metric('windows_logical_disk_free_bytes', [c.volumeSelector]),
|
||||
self.metric('windows_logical_disk_size_bytes', [c.volumeSelector]),
|
||||
],
|
||||
self.metric('windows_logical_disk_size_bytes', [c.volumeSelector])
|
||||
),
|
||||
memoryCommitted:
|
||||
self.ratio(self.metric('windows_memory_committed_bytes'), self.metric('windows_memory_commit_limit')),
|
||||
diskLatency(direction):
|
||||
self.ratio(
|
||||
self.rate('windows_logical_disk_%s_seconds_total' % direction, [c.volumeSelector]),
|
||||
self.rate('windows_logical_disk_%ss_total' % direction, [c.volumeSelector])
|
||||
),
|
||||
networkUtilization(direction):
|
||||
self.ratio(
|
||||
self.rate('windows_net_bytes_%s_total' % direction, [c.nicSelector]),
|
||||
self.metric('windows_net_current_bandwidth_bytes', [c.nicSelector])
|
||||
),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
(import 'config.libsonnet') +
|
||||
(import 'rules/rules.libsonnet') +
|
||||
(import 'alerts/alerts.libsonnet')
|
||||
(import 'alerts/alerts.libsonnet') +
|
||||
(import 'lib/add-runbook-links.libsonnet')
|
||||
|
||||
@@ -7,20 +7,65 @@
|
||||
name: 'windows-exporter-recording',
|
||||
rules: [
|
||||
{ record: 'windows:cpu_usage:ratio', expr: q.cpuUsage },
|
||||
{ record: 'windows:cpu_cores:count', expr: 'count without (core, mode) (%s)' % q.metric('windows_cpu_time_total', ['mode="idle"']) },
|
||||
{ record: 'windows:cpu_time:ratio_rate', expr: 'avg without (core) (%s)' % q.rate('windows_cpu_time_total') },
|
||||
{ record: 'windows:memory_usage:ratio', expr: q.memoryUsage },
|
||||
{
|
||||
record: 'windows:memory_used:bytes',
|
||||
expr: '%s - %s' % [q.metric('windows_memory_physical_total_bytes'), q.metric('windows_memory_available_bytes')],
|
||||
},
|
||||
{
|
||||
record: 'windows:memory_cached:bytes',
|
||||
expr: std.join(' + ', [
|
||||
q.metric('windows_memory_%s_bytes' % component)
|
||||
for component in ['cache', 'modified_page_list', 'standby_cache_core', 'standby_cache_normal_priority', 'standby_cache_reserve']
|
||||
]),
|
||||
},
|
||||
{ record: 'windows:memory_committed:ratio', expr: q.memoryCommitted },
|
||||
{ record: 'windows:memory_swap_page_operations:rate', expr: q.rate('windows_memory_swap_page_operations_total') },
|
||||
{ record: 'windows:logical_disk_free:ratio', expr: q.diskFree },
|
||||
{
|
||||
record: 'windows:logical_disk_used:bytes',
|
||||
expr: '%s - %s' % [
|
||||
q.metric('windows_logical_disk_size_bytes', [c.volumeSelector]),
|
||||
q.metric('windows_logical_disk_free_bytes', [c.volumeSelector]),
|
||||
],
|
||||
},
|
||||
{
|
||||
record: 'windows:logical_disk_busy:ratio',
|
||||
expr: 'clamp(1 - %s, 0, 1)' % q.rate('windows_logical_disk_idle_seconds_total', [c.volumeSelector]),
|
||||
},
|
||||
] + [
|
||||
{
|
||||
record: 'windows:logical_disk_%s_bytes:rate' % direction,
|
||||
expr: q.rate('windows_logical_disk_%s_bytes_total' % direction, [c.volumeSelector]),
|
||||
}
|
||||
for direction in ['read', 'write']
|
||||
] + [
|
||||
{
|
||||
record: 'windows:logical_disk_%s_operations:rate' % direction,
|
||||
expr: q.rate('windows_logical_disk_%ss_total' % direction, [c.volumeSelector]),
|
||||
}
|
||||
for direction in ['read', 'write']
|
||||
] + [
|
||||
{ record: 'windows:logical_disk_%s_latency:seconds' % direction, expr: q.diskLatency(direction) }
|
||||
for direction in ['read', 'write']
|
||||
] + [
|
||||
{
|
||||
record: 'windows:net_%s_bytes:rate' % direction,
|
||||
expr: q.rate('windows_net_bytes_%s_total' % direction, [c.nicSelector]),
|
||||
}
|
||||
for direction in ['received', 'sent']
|
||||
] + [
|
||||
{ record: 'windows:net_%s_utilization:ratio' % direction, expr: q.networkUtilization(direction) }
|
||||
for direction in ['received', 'sent']
|
||||
] + [
|
||||
{
|
||||
record: 'windows:net_%s_%s:rate' % [direction, outcome],
|
||||
expr: q.rate('windows_net_packets_%s_%s_total' % [direction, outcome], [c.nicSelector]),
|
||||
}
|
||||
for direction in ['received', 'outbound']
|
||||
for outcome in ['errors', 'discarded']
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -7,6 +7,116 @@ group_eval_order:
|
||||
- windows-exporter-alerts
|
||||
|
||||
tests:
|
||||
- name: Commit pressure, disk latency and network failures wait and recover
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_memory_committed_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '95x20 50x10'
|
||||
- series: 'windows_memory_commit_limit{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '100x31'
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+12x20 252x10'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+120x31'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+24x20 504x10'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+240x31'
|
||||
- series: 'windows_net_packets_received_errors_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+120x20 2520x10'
|
||||
- series: 'windows_net_packets_outbound_errors_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0x31'
|
||||
- series: 'windows_net_packets_received_discarded_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0x31'
|
||||
- series: 'windows_net_packets_outbound_discarded_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+120x20 2520x10'
|
||||
alert_rule_test:
|
||||
- {alertname: WindowsMemoryCommitHighUsage, eval_time: 14m, exp_alerts: []}
|
||||
- alertname: WindowsMemoryCommitHighUsage
|
||||
eval_time: 15m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsmemorycommithighusage/
|
||||
summary: Windows memory commit usage is high
|
||||
description: 'Committed memory on host:9182 has exceeded 90% of the commit limit for 15 minutes.'
|
||||
- {alertname: WindowsMemoryCommitHighUsage, eval_time: 21m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskReadLatencyHigh, eval_time: 15m, exp_alerts: []}
|
||||
- alertname: WindowsDiskReadLatencyHigh
|
||||
eval_time: 16m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskreadlatencyhigh/
|
||||
summary: Windows disk read latency is high
|
||||
description: 'Volume C: on host:9182 has averaged more than 0.05 seconds per read operation for 15 minutes.'
|
||||
- {alertname: WindowsDiskReadLatencyHigh, eval_time: 25m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskWriteLatencyHigh, eval_time: 15m, exp_alerts: []}
|
||||
- alertname: WindowsDiskWriteLatencyHigh
|
||||
eval_time: 16m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskwritelatencyhigh/
|
||||
summary: Windows disk write latency is high
|
||||
description: 'Volume C: on host:9182 has averaged more than 0.05 seconds per write operation for 15 minutes.'
|
||||
- {alertname: WindowsDiskWriteLatencyHigh, eval_time: 25m, exp_alerts: []}
|
||||
- {alertname: WindowsNetworkErrors, eval_time: 17m, exp_alerts: []}
|
||||
- alertname: WindowsNetworkErrors
|
||||
eval_time: 18m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, nic: Ethernet, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsnetworkerrors/
|
||||
summary: Windows network packet errors are high
|
||||
description: 'Packet errors on interface Ethernet on host:9182 have exceeded 1 per second for 15 minutes.'
|
||||
- {alertname: WindowsNetworkErrors, eval_time: 25m, exp_alerts: []}
|
||||
- {alertname: WindowsNetworkDiscards, eval_time: 17m, exp_alerts: []}
|
||||
- alertname: WindowsNetworkDiscards
|
||||
eval_time: 18m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, nic: Ethernet, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsnetworkdiscards/
|
||||
summary: Windows network packet discards are high
|
||||
description: 'Packet discards on interface Ethernet on host:9182 have exceeded 1 per second for 15 minutes.'
|
||||
- {alertname: WindowsNetworkDiscards, eval_time: 25m, exp_alerts: []}
|
||||
|
||||
- name: New resource alerts stay quiet at exact thresholds and clock alerts are disabled
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_memory_committed_bytes{job="windows_exporter", instance="host:9182"}'
|
||||
values: '90x20'
|
||||
- series: 'windows_memory_commit_limit{job="windows_exporter", instance="host:9182"}'
|
||||
values: '100x20'
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0+6x20'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0+6x20'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_net_packets_received_errors_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+30x20'
|
||||
- series: 'windows_net_packets_outbound_errors_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+30x20'
|
||||
- series: 'windows_net_packets_received_discarded_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+30x20'
|
||||
- series: 'windows_net_packets_outbound_discarded_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+30x20'
|
||||
- series: 'windows_time_ntp_client_time_sources{job="windows_exporter", instance="host:9182"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_time_computed_time_offset_seconds{job="windows_exporter", instance="host:9182"}'
|
||||
values: '1x20'
|
||||
alert_rule_test:
|
||||
- {alertname: WindowsMemoryCommitHighUsage, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskReadLatencyHigh, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskWriteLatencyHigh, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsNetworkErrors, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsNetworkDiscards, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsClockNotSynchronising, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsClockSkewDetected, eval_time: 20m, exp_alerts: []}
|
||||
- name: Exporter and collector failures wait five minutes and recover
|
||||
interval: 1m
|
||||
input_series:
|
||||
@@ -25,6 +135,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', severity: critical}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsexporterdown/
|
||||
summary: Windows exporter is unreachable
|
||||
description: 'Prometheus cannot scrape Windows exporter on host:9182 (job windows_exporter).'
|
||||
- alertname: WindowsExporterDown
|
||||
@@ -38,6 +149,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', collector: cpu, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowscollectorfailed/
|
||||
summary: Windows collector failed
|
||||
description: 'Collector cpu on host:9182 has failed for at least 5 minutes.'
|
||||
- alertname: WindowsCollectorFailed
|
||||
@@ -62,6 +174,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowscpuhighusage/
|
||||
summary: Windows CPU usage is high
|
||||
description: 'CPU usage on host:9182 has exceeded 90% for 15 minutes.'
|
||||
- alertname: WindowsCPUHighUsage
|
||||
@@ -75,6 +188,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsmemoryhighusage/
|
||||
summary: Windows memory usage is high
|
||||
description: 'Physical memory usage on host:9182 has exceeded 90% for 15 minutes.'
|
||||
- alertname: WindowsMemoryHighUsage
|
||||
@@ -97,10 +211,12 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskalmostfull/
|
||||
summary: Windows disk space is low
|
||||
description: 'Volume C: on host:9182 has less than 10% free space. Windows may delay space metrics by 10–15 minutes.'
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', volume: 'C:', severity: critical}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskalmostfull/
|
||||
summary: Windows disk space is low
|
||||
description: 'Volume C: on host:9182 has less than 5% free space. Windows may delay space metrics by 10–15 minutes.'
|
||||
- alertname: WindowsDiskAlmostFull
|
||||
@@ -153,6 +269,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskfillingup/
|
||||
summary: Windows disk is predicted to fill up
|
||||
description: 'Volume C: on host:9182 is predicted to fill within 24 hours.'
|
||||
- alertname: WindowsDiskFillingUp
|
||||
@@ -160,6 +277,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows_exporter, instance: 'host:9182', cluster: a, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://prometheus-community.github.io/windows_exporter/runbooks/windowsdiskfillingup/
|
||||
summary: Windows disk is predicted to fill up
|
||||
description: 'Volume C: on host:9182 is predicted to fill within 24 hours.'
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"""Check every mixin alert has a complete runbook at its default URL."""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
runbooks = Path(sys.argv[1])
|
||||
alerts = json.load(sys.stdin)
|
||||
errors = []
|
||||
names = set()
|
||||
for group in alerts["groups"]:
|
||||
for rule in group["rules"]:
|
||||
if "alert" not in rule:
|
||||
continue
|
||||
name = rule["alert"]
|
||||
names.add(name)
|
||||
slug = name.lower()
|
||||
expected_path = f"/windows_exporter/runbooks/{slug}/"
|
||||
if urlparse(rule["annotations"].get("runbook_url", "")).path != expected_path:
|
||||
errors.append(f"{name}: runbook URL must end in {expected_path}")
|
||||
path = runbooks / f"{slug}.md"
|
||||
if not path.is_file():
|
||||
errors.append(f"{name}: missing {path}")
|
||||
continue
|
||||
content = path.read_text(encoding="utf-8")
|
||||
for section in ("Meaning", "Impact", "Diagnosis", "Mitigation"):
|
||||
if f"## {section}\n" not in content:
|
||||
errors.append(f"{name}: missing {section} section in {path}")
|
||||
if "TODO" in content:
|
||||
errors.append(f"{name}: unfinished runbook {path}")
|
||||
|
||||
if errors:
|
||||
sys.exit("\n".join(errors))
|
||||
print(f"Checked runbooks and URLs for {len(names)} alerts")
|
||||
@@ -10,6 +10,13 @@
|
||||
diskFreeCriticalThreshold: 10,
|
||||
criticalSeverity: 'page',
|
||||
enableActiveDirectory: true,
|
||||
enableTime: true,
|
||||
runbookURLPattern: 'https://runbooks.example.com/windows/%s/',
|
||||
memoryCommitHighUsageThreshold: 80,
|
||||
diskLatencyThresholdSeconds: 0.02,
|
||||
networkErrorRateThreshold: 0.5,
|
||||
networkDiscardRateThreshold: 0.5,
|
||||
clockOffsetThresholdSeconds: 0.1,
|
||||
adPendingReplicationThreshold: 10,
|
||||
adReplicationFailureRateThreshold: 0.5,
|
||||
},
|
||||
|
||||
@@ -6,8 +6,130 @@ group_eval_order:
|
||||
- windows-exporter-recording
|
||||
- windows-exporter-alerts
|
||||
- windows-active-directory
|
||||
- windows-time
|
||||
|
||||
tests:
|
||||
- name: Custom commit, latency and network thresholds preserve selectors and device filters
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_memory_committed_bytes{job="windows-custom", instance="host:9182", cluster="test"}'
|
||||
values: '85x20'
|
||||
- series: 'windows_memory_commit_limit{job="windows-custom", instance="host:9182", cluster="test"}'
|
||||
values: '100x20'
|
||||
- series: 'windows_memory_committed_bytes{job="windows-custom", instance="host:9182", cluster="prod"}'
|
||||
values: '99x20'
|
||||
- series: 'windows_memory_commit_limit{job="windows-custom", instance="host:9182", cluster="prod"}'
|
||||
values: '100x20'
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows-custom", instance="host:9182", cluster="test", volume="C:"}'
|
||||
values: '0+3.6x20'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows-custom", instance="host:9182", cluster="test", volume="C:"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows-custom", instance="host:9182", cluster="test", volume="C:"}'
|
||||
values: '0+3.6x20'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows-custom", instance="host:9182", cluster="test", volume="C:"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows-custom", instance="host:9182", cluster="test", volume="HarddiskVolume1"}'
|
||||
values: '0+12x20'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows-custom", instance="host:9182", cluster="test", volume="HarddiskVolume1"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows-custom", instance="host:9182", cluster="test", volume="HarddiskVolume1"}'
|
||||
values: '0+12x20'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows-custom", instance="host:9182", cluster="test", volume="HarddiskVolume1"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_net_packets_received_errors_total{job="windows-custom", instance="host:9182", cluster="test", nic="Ethernet"}'
|
||||
values: '0+36x20'
|
||||
- series: 'windows_net_packets_outbound_errors_total{job="windows-custom", instance="host:9182", cluster="test", nic="Ethernet"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_net_packets_received_discarded_total{job="windows-custom", instance="host:9182", cluster="test", nic="Ethernet"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_net_packets_outbound_discarded_total{job="windows-custom", instance="host:9182", cluster="test", nic="Ethernet"}'
|
||||
values: '0+36x20'
|
||||
- series: 'windows_net_packets_received_errors_total{job="windows-custom", instance="host:9182", cluster="test", nic="Loopback"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_net_packets_outbound_errors_total{job="windows-custom", instance="host:9182", cluster="test", nic="Loopback"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_net_packets_received_discarded_total{job="windows-custom", instance="host:9182", cluster="test", nic="Loopback"}'
|
||||
values: '0+120x20'
|
||||
- series: 'windows_net_packets_outbound_discarded_total{job="windows-custom", instance="host:9182", cluster="test", nic="Loopback"}'
|
||||
values: '0+120x20'
|
||||
alert_rule_test:
|
||||
- alertname: WindowsMemoryCommitHighUsage
|
||||
eval_time: 20m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsmemorycommithighusage/
|
||||
summary: Windows memory commit usage is high
|
||||
description: 'Committed memory on host:9182 has exceeded 80% of the commit limit for 15 minutes.'
|
||||
- alertname: WindowsDiskReadLatencyHigh
|
||||
eval_time: 20m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsdiskreadlatencyhigh/
|
||||
summary: Windows disk read latency is high
|
||||
description: 'Volume C: on host:9182 has averaged more than 0.02 seconds per read operation for 15 minutes.'
|
||||
- alertname: WindowsDiskWriteLatencyHigh
|
||||
eval_time: 20m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsdiskwritelatencyhigh/
|
||||
summary: Windows disk write latency is high
|
||||
description: 'Volume C: on host:9182 has averaged more than 0.02 seconds per write operation for 15 minutes.'
|
||||
- alertname: WindowsNetworkErrors
|
||||
eval_time: 20m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, nic: Ethernet, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsnetworkerrors/
|
||||
summary: Windows network packet errors are high
|
||||
description: 'Packet errors on interface Ethernet on host:9182 have exceeded 0.5 per second for 15 minutes.'
|
||||
- alertname: WindowsNetworkDiscards
|
||||
eval_time: 20m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, nic: Ethernet, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsnetworkdiscards/
|
||||
summary: Windows network packet discards are high
|
||||
description: 'Packet discards on interface Ethernet on host:9182 have exceeded 0.5 per second for 15 minutes.'
|
||||
|
||||
- name: Clock alerts opt in, use absolute offset, custom URLs and recover
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_time_ntp_client_time_sources{job="windows-custom", instance="host:9182", cluster="test"}'
|
||||
values: '0x10 1x10'
|
||||
- series: 'windows_time_computed_time_offset_seconds{job="windows-custom", instance="host:9182", cluster="test"}'
|
||||
values: '-0.2x10 0x10'
|
||||
- series: 'windows_time_ntp_client_time_sources{job="windows-custom", instance="healthy:9182", cluster="test"}'
|
||||
values: '1x21'
|
||||
- series: 'windows_time_computed_time_offset_seconds{job="windows-custom", instance="healthy:9182", cluster="test"}'
|
||||
values: '0.1x21'
|
||||
- series: 'windows_time_ntp_client_time_sources{job="windows-custom", instance="host:9182", cluster="prod"}'
|
||||
values: '0x21'
|
||||
- series: 'windows_time_computed_time_offset_seconds{job="windows-custom", instance="host:9182", cluster="prod"}'
|
||||
values: '-1x21'
|
||||
alert_rule_test:
|
||||
- {alertname: WindowsClockNotSynchronising, eval_time: 9m, exp_alerts: []}
|
||||
- alertname: WindowsClockNotSynchronising
|
||||
eval_time: 10m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsclocknotsynchronising/
|
||||
summary: Windows clock has no NTP time source
|
||||
description: 'Windows Time on host:9182 has had no active NTP time source for 10 minutes.'
|
||||
- {alertname: WindowsClockNotSynchronising, eval_time: 11m, exp_alerts: []}
|
||||
- {alertname: WindowsClockSkewDetected, eval_time: 9m, exp_alerts: []}
|
||||
- alertname: WindowsClockSkewDetected
|
||||
eval_time: 10m
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsclockskewdetected/
|
||||
summary: Windows clock offset is high
|
||||
description: 'Windows Time on host:9182 reports a clock offset above 0.1 seconds for 10 minutes.'
|
||||
- {alertname: WindowsClockSkewDetected, eval_time: 11m, exp_alerts: []}
|
||||
- name: Custom selectors, thresholds and critical severity propagate to alerts
|
||||
interval: 1m
|
||||
input_series:
|
||||
@@ -50,6 +172,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: page}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsexporterdown/
|
||||
summary: Windows exporter is unreachable
|
||||
description: 'Prometheus cannot scrape Windows exporter on host:9182 (job windows-custom).'
|
||||
- alertname: WindowsCPUHighUsage
|
||||
@@ -57,6 +180,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowscpuhighusage/
|
||||
summary: Windows CPU usage is high
|
||||
description: 'CPU usage on host:9182 has exceeded 80% for 15 minutes.'
|
||||
- alertname: WindowsMemoryHighUsage
|
||||
@@ -64,6 +188,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsmemoryhighusage/
|
||||
summary: Windows memory usage is high
|
||||
description: 'Physical memory usage on host:9182 has exceeded 85% for 15 minutes.'
|
||||
- alertname: WindowsDiskAlmostFull
|
||||
@@ -71,10 +196,12 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, volume: 'C:', severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsdiskalmostfull/
|
||||
summary: Windows disk space is low
|
||||
description: 'Volume C: on host:9182 has less than 20% free space. Windows may delay space metrics by 10–15 minutes.'
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, volume: 'C:', severity: page}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsdiskalmostfull/
|
||||
summary: Windows disk space is low
|
||||
description: 'Volume C: on host:9182 has less than 10% free space. Windows may delay space metrics by 10–15 minutes.'
|
||||
|
||||
@@ -108,6 +235,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsadpendingreplication/
|
||||
summary: Active Directory replication queue is high
|
||||
description: 'Pending replication operations on host:9182 have exceeded 10 for 15 minutes.'
|
||||
- alertname: WindowsADPendingReplication
|
||||
@@ -121,6 +249,7 @@ tests:
|
||||
exp_alerts:
|
||||
- exp_labels: {job: windows-custom, instance: 'host:9182', cluster: test, severity: warning}
|
||||
exp_annotations:
|
||||
runbook_url: https://runbooks.example.com/windows/windowsadreplicationfailures/
|
||||
summary: Active Directory replication requests are failing
|
||||
description: 'Replication synchronization requests on host:9182 have been failing for 15 minutes.'
|
||||
- alertname: WindowsADReplicationFailures
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
rule_files:
|
||||
- ../windows_rules.yaml
|
||||
- ../windows_alerts.yaml
|
||||
evaluation_interval: 1m
|
||||
group_eval_order:
|
||||
- windows-exporter-recording
|
||||
- windows-exporter-alerts
|
||||
|
||||
tests:
|
||||
- name: Memory cache includes all lists, commit is a ratio and paging is a rate
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_memory_cache_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '10x10'
|
||||
- series: 'windows_memory_modified_page_list_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '20x10'
|
||||
- series: 'windows_memory_standby_cache_core_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '30x10'
|
||||
- series: 'windows_memory_standby_cache_normal_priority_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '40x10'
|
||||
- series: 'windows_memory_standby_cache_reserve_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '50x10'
|
||||
- series: 'windows_memory_committed_bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '80x10'
|
||||
- series: 'windows_memory_commit_limit{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '100x10'
|
||||
- series: 'windows_memory_swap_page_operations_total{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
values: '0+120x10'
|
||||
- series: 'windows_memory_committed_bytes{job="other", instance="host:9182"}'
|
||||
values: '95x10'
|
||||
- series: 'windows_memory_commit_limit{job="other", instance="host:9182"}'
|
||||
values: '100x10'
|
||||
promql_expr_test:
|
||||
- expr: windows:memory_cached:bytes
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:memory_cached:bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
value: 150
|
||||
- expr: windows:memory_committed:ratio
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:memory_committed:ratio{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
value: 0.8
|
||||
- expr: windows:memory_swap_page_operations:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:memory_swap_page_operations:rate{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
value: 2
|
||||
|
||||
- name: Disk latency uses operations, handles resets and busy time stays bounded
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+12x5 12+12x4'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+120x5 120+120x4'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+24x10'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+240x10'
|
||||
- series: 'windows_logical_disk_idle_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
values: '0+30x10'
|
||||
- series: 'windows_logical_disk_idle_seconds_total{job="windows_exporter", instance="host:9182", cluster="a", volume="D:"}'
|
||||
values: '0+90x10'
|
||||
promql_expr_test:
|
||||
- expr: windows:logical_disk_read_operations:rate
|
||||
eval_time: 8m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_read_operations:rate{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 2
|
||||
- expr: windows:logical_disk_write_operations:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_write_operations:rate{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 4
|
||||
- expr: windows:logical_disk_read_latency:seconds
|
||||
eval_time: 8m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_read_latency:seconds{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 0.1
|
||||
- expr: windows:logical_disk_write_latency:seconds
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_write_latency:seconds{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 0.1
|
||||
- expr: windows:logical_disk_busy:ratio
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_busy:ratio{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 0.5
|
||||
- labels: 'windows:logical_disk_busy:ratio{job="windows_exporter", instance="host:9182", cluster="a", volume="D:"}'
|
||||
value: 0
|
||||
|
||||
- name: Full duplex network utilization uses bytes and keeps directions separate
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_net_bytes_received_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+600x10'
|
||||
- series: 'windows_net_bytes_sent_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+1200x10'
|
||||
- series: 'windows_net_current_bandwidth_bytes{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '100x10'
|
||||
- series: 'windows_net_packets_received_errors_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+60x10'
|
||||
- series: 'windows_net_packets_outbound_errors_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+120x10'
|
||||
- series: 'windows_net_packets_received_discarded_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+180x10'
|
||||
- series: 'windows_net_packets_outbound_discarded_total{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
values: '0+240x10'
|
||||
promql_expr_test:
|
||||
- expr: windows:net_received_utilization:ratio
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_received_utilization:ratio{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 0.1
|
||||
- expr: windows:net_sent_utilization:ratio
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_sent_utilization:ratio{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 0.2
|
||||
- expr: windows:net_received_errors:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_received_errors:rate{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 1
|
||||
- expr: windows:net_outbound_errors:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_outbound_errors:rate{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 2
|
||||
- expr: windows:net_received_discarded:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_received_discarded:rate{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 3
|
||||
- expr: windows:net_outbound_discarded:rate
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:net_outbound_discarded:rate{job="windows_exporter", instance="host:9182", cluster="a", nic="Ethernet"}'
|
||||
value: 4
|
||||
|
||||
- name: Zero capacity and idle devices produce no undefined ratios or latency alerts
|
||||
interval: 1m
|
||||
input_series:
|
||||
- series: 'windows_memory_available_bytes{job="windows_exporter", instance="host:9182"}'
|
||||
values: '1x20'
|
||||
- series: 'windows_memory_physical_total_bytes{job="windows_exporter", instance="host:9182"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_logical_disk_free_bytes{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '1x20'
|
||||
- series: 'windows_logical_disk_size_bytes{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_memory_committed_bytes{job="windows_exporter", instance="host:9182"}'
|
||||
values: '1x20'
|
||||
- series: 'windows_memory_commit_limit{job="windows_exporter", instance="host:9182"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_logical_disk_read_seconds_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_logical_disk_reads_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_logical_disk_write_seconds_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_logical_disk_writes_total{job="windows_exporter", instance="host:9182", volume="C:"}'
|
||||
values: '0x20'
|
||||
- series: 'windows_net_bytes_received_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+600x20'
|
||||
- series: 'windows_net_bytes_sent_total{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0+600x20'
|
||||
- series: 'windows_net_current_bandwidth_bytes{job="windows_exporter", instance="host:9182", nic="Ethernet"}'
|
||||
values: '0x20'
|
||||
promql_expr_test:
|
||||
- {expr: 'windows:memory_usage:ratio', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:logical_disk_free:ratio', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:memory_committed:ratio', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:logical_disk_read_latency:seconds', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:logical_disk_write_latency:seconds', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:net_received_utilization:ratio', eval_time: 20m, exp_samples: []}
|
||||
- {expr: 'windows:net_sent_utilization:ratio', eval_time: 20m, exp_samples: []}
|
||||
alert_rule_test:
|
||||
- {alertname: WindowsMemoryCommitHighUsage, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskReadLatencyHigh, eval_time: 20m, exp_alerts: []}
|
||||
- {alertname: WindowsDiskWriteLatencyHigh, eval_time: 20m, exp_alerts: []}
|
||||
@@ -18,6 +18,20 @@ tests:
|
||||
- series: 'windows_cpu_time_total{job="other", instance="host:9182", core="0", mode="idle"}'
|
||||
values: '0+6x10'
|
||||
promql_expr_test:
|
||||
- expr: windows:cpu_cores:count
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:cpu_cores:count{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
value: 2
|
||||
- labels: 'windows:cpu_cores:count{job="windows_exporter", instance="host:9182", cluster="b"}'
|
||||
value: 1
|
||||
- expr: 'windows:cpu_time:ratio_rate{mode="idle"}'
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
- labels: 'windows:cpu_time:ratio_rate{job="windows_exporter", instance="host:9182", cluster="a", mode="idle"}'
|
||||
value: 0.4
|
||||
- labels: 'windows:cpu_time:ratio_rate{job="windows_exporter", instance="host:9182", cluster="b", mode="idle"}'
|
||||
value: 0.5
|
||||
- expr: windows:cpu_usage:ratio
|
||||
eval_time: 10m
|
||||
exp_samples:
|
||||
@@ -42,6 +56,16 @@ tests:
|
||||
- series: 'windows_logical_disk_size_bytes{job="windows_exporter", instance="host:9182", volume=""}'
|
||||
values: '100x5'
|
||||
promql_expr_test:
|
||||
- expr: windows:memory_used:bytes
|
||||
eval_time: 5m
|
||||
exp_samples:
|
||||
- labels: 'windows:memory_used:bytes{job="windows_exporter", instance="host:9182", cluster="a"}'
|
||||
value: 75
|
||||
- expr: windows:logical_disk_used:bytes
|
||||
eval_time: 5m
|
||||
exp_samples:
|
||||
- labels: 'windows:logical_disk_used:bytes{job="windows_exporter", instance="host:9182", cluster="a", volume="C:"}'
|
||||
value: 80
|
||||
- expr: windows:memory_usage:ratio
|
||||
eval_time: 5m
|
||||
exp_samples:
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
local linked = {
|
||||
_config:: { runbookURLPattern: 'https://example.com/runbooks/%s/' },
|
||||
prometheusAlerts:: {
|
||||
groups: [
|
||||
{
|
||||
name: 'custom',
|
||||
rules: [
|
||||
{ alert: 'WindowsCustomAlert', expr: 'up == 0', annotations: { summary: 'Existing summary' } },
|
||||
{ alert: 'WindowsOverride', expr: 'up == 0', annotations: { runbook_url: 'https://example.com/override' } },
|
||||
{ record: 'windows:custom:sum', expr: 'sum(up)' },
|
||||
{ alert: 'WindowsNoAnnotations', expr: 'up == 0' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
} + (import '../lib/add-runbook-links.libsonnet');
|
||||
local rules = linked.prometheusAlerts.groups[0].rules;
|
||||
assert rules[0].annotations == { summary: 'Existing summary', runbook_url: 'https://example.com/runbooks/windowscustomalert/' };
|
||||
assert rules[1].annotations.runbook_url == 'https://example.com/override';
|
||||
assert !std.objectHas(rules[2], 'annotations');
|
||||
assert rules[3].annotations.runbook_url == 'https://example.com/runbooks/windowsnoannotations/';
|
||||
assert rules[0].expr == 'up == 0' && linked.prometheusAlerts.groups[0].name == 'custom';
|
||||
{ result: 'Runbook link composition passed' }
|
||||
Reference in New Issue
Block a user