Compare commits

..

20 Commits

Author SHA1 Message Date
Jan-Otto Kröpke
a56e1ac71a fix: Support running as Windows Service within containers (#1907)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
(cherry picked from commit 3f2633d0b0)
2025-03-15 10:11:42 +01:00
Jan-Otto Kröpke
0c44a934f4 fix: update dependencies (#1920)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-03-11 10:46:14 +01:00
dependabot[bot]
d1151e91f3 chore(deps): bump github.com/prometheus/client_golang from 1.21.0 to 1.21.1 (#1919)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 15:52:45 +01:00
Jan-Otto Kröpke
cbe94c1ea5 netframework: fix metric names (re-add the collector sub-type to metrics) (#1908)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-03-01 17:22:59 +01:00
Jan-Otto Kröpke
b809f5a8ee docs: added examples for alternative installer dir (#1909)
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
2025-03-01 00:17:48 +01:00
dependabot[bot]
756d9c160d chore(deps): bump github.com/prometheus/client_golang from 1.21.0-rc.0 to 1.21.0 (#1899)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-01 00:09:41 +01:00
Jan-Otto Kröpke
a0e132b30e terminal_services: fix panic in collect (#1906) 2025-02-28 07:53:23 +01:00
Jan-Otto Kröpke
d645e89be9 ci: fix checksum (#1905) 2025-02-28 07:53:10 +01:00
Jan-Otto Kröpke
a73a08d704 fix: log to the Windows temp directory if of service detection failures. (#1890) 2025-02-28 01:35:41 +01:00
Jan-Otto Kröpke
228164765b docs: fix physical_disk docs (#1897) 2025-02-22 08:29:52 +00:00
Jan-Otto Kröpke
4c9c78c599 time: fix panic if counters aren't present (#1898) 2025-02-22 09:29:02 +01:00
Jan-Otto Kröpke
4b3c154049 docs: add disk activity query. (#1889)
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
2025-02-18 13:41:26 +01:00
Jan-Otto Kröpke
be0037eda5 ci: pin wix toolset version to avoid installing incompatible extensions (#1885)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-13 20:56:44 +01:00
Jan-Otto Kröpke
367fae95c4 mscluster: restore support for Windows Server 2016-2019 (#1882)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-12 21:03:24 +01:00
Jan-Otto Kröpke
96ffc3bf3f config: multiple web.listen-address args results into an error, if --config.file is defined. (#1876)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-12 20:30:12 +01:00
Jan-Otto Kröpke
285c4cc5ea feat: windows_exporter uses own event log source to correctly format messages. (#1873)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
2025-02-10 18:57:31 +01:00
Jan-Otto Kröpke
f07aceb0dd cs: fix metric description (#1881)
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-10 18:23:35 +01:00
Jan-Otto Kröpke
dcacce4577 fix: sign binaries (#1878)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-09 22:34:55 +01:00
Jan-Otto Kröpke
fc5b3051fa feat: sign binaries (#1875)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-08 20:04:37 +01:00
Jan-Otto Kröpke
1b2958a7cc fix: slow stop if run as service (#1870)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2025-02-07 22:26:09 +01:00
36 changed files with 450 additions and 285 deletions

View File

@@ -1,3 +1,5 @@
<!--
Please give your PR a title in the form "area: short description". For example "cpu: reduce usage by 95%" or "docs: fix typo in installation.md".

View File

@@ -4,23 +4,11 @@ name: Linting
# have been changed.
on:
push:
paths:
- "go.mod"
- "go.sum"
- "**.go"
- ".github/workflows/lint.yml"
- "tools/e2e-output.txt"
branches:
- master
- next
- main
pull_request:
paths:
- "go.mod"
- "go.sum"
- "**.go"
- ".github/workflows/lint.yml"
- "tools/e2e-output.txt"
branches:
- master
- next
@@ -105,4 +93,4 @@ jobs:
uses: golangci/golangci-lint-action@v6
with:
version: v1.60
args: "--max-same-issues=0"
args: "--max-same-issues=0"

View File

@@ -22,6 +22,7 @@ env:
jobs:
build:
runs-on: windows-2022
environment: build
steps:
- uses: actions/checkout@v4
with:
@@ -32,13 +33,14 @@ jobs:
go-version-file: 'go.mod'
- name: Install WiX
run: dotnet tool install --global wix
run: |
dotnet tool install --global wix --version 5.0.2
- name: Install WiX extensions
run: |
wix extension add -g WixToolset.Util.wixext
wix extension add -g WixToolset.Ui.wixext
wix extension add -g WixToolset.Firewall.wixext
wix extension add -g WixToolset.Util.wixext/5.0.2
wix extension add -g WixToolset.Ui.wixext/5.0.2
wix extension add -g WixToolset.Firewall.wixext/5.0.2
- name: Install Build deps
run: |
@@ -68,6 +70,40 @@ jobs:
Get-ChildItem -Path output
- name: Sign build artifacts
if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }}
run: |
$ErrorActionPreference = "Stop"
$Version = Get-Content VERSION
$b64 = $env:CODE_SIGN_KEY
$filename = 'windows_exporter_CodeSign.pfx'
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filename, $bytes)
$basePath = "C:\Program Files (x86)\Windows Kits\10\bin"
$latestSigntool = Get-ChildItem -Path $basePath -Directory |
Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } |
Sort-Object { [Version]$_.Name } -Descending |
Select-Object -First 1 |
ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" }
if (Test-Path $latestSigntool) {
Write-Output $latestSigntool
} else {
Write-Output "signtool.exe not found"
}
foreach($Arch in "amd64", "arm64") {
& $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.exe"
}
rm windows_exporter_CodeSign.pfx
env:
CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }}
CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }}
- name: Build Release Artifacts
run: |
$ErrorActionPreference = "Stop"
@@ -79,9 +115,46 @@ jobs:
}
Move-Item installer\*.msi output\
Get-ChildItem -Path output\
Get-ChildItem -Path output\ g
promu checksum output\
- name: Sign installer artifacts
if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }}
run: |
$ErrorActionPreference = "Stop"
$Version = Get-Content VERSION
$b64 = $env:CODE_SIGN_KEY
$filename = 'windows_exporter_CodeSign.pfx'
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filename, $bytes)
$basePath = "C:\Program Files (x86)\Windows Kits\10\bin"
$latestSigntool = Get-ChildItem -Path $basePath -Directory |
Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } |
Sort-Object { [Version]$_.Name } -Descending |
Select-Object -First 1 |
ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" }
if (Test-Path $latestSigntool) {
Write-Output $latestSigntool
} else {
Write-Output "signtool.exe not found"
}
foreach($Arch in "amd64", "arm64") {
& $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.msi"
}
rm windows_exporter_CodeSign.pfx
env:
CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }}
CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }}
- name: Generate checksums
run: |
promu checksum output
cat output\sha256sums.txt
- name: Upload Artifacts
uses: actions/upload-artifact@v4
@@ -103,6 +176,9 @@ jobs:
runs-on: ubuntu-latest
needs:
- build
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
steps:
- uses: actions/checkout@v4
with:
@@ -165,3 +241,4 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: windows/amd64
annotations: ${{ steps.meta.outputs.labels }}

View File

@@ -100,6 +100,9 @@ windows_exporter accepts flags to configure certain behaviours. The ones configu
The latest release can be downloaded from the [releases page](https://github.com/prometheus-community/windows_exporter/releases).
All binaries and installation packages are signed with an self-signed certificate. The public key can be found [here](https://github.com/prometheus-community/windows_exporter/blob/master/installer/codesign.cer).
Once import into the trusted root certificate store, the binaries and installation packages will be trusted.
Each release provides a .msi installer. The installer will setup the windows_exporter as a Windows service, as well as create an exception in the Windows Firewall.
If the installer is run without any parameters, the exporter will run with default settings for enabled collectors, ports, etc.
@@ -125,6 +128,8 @@ The following parameters are available:
| `EXTRA_FLAGS` | Allows passing full CLI flags. Defaults to an empty string. For `--collectors.enabled` and `--config.file`, use the specialized properties `ENABLED_COLLECTORS` and `CONFIG_FILE` |
| `ADDLOCAL` | Enables features within the windows_exporter installer. Supported values: `FirewallException` |
| `REMOVE` | Disables features within the windows_exporter installer. Supported values: `FirewallException` |
| `APPLICATIONFOLDER` | Directory to install windows_exporter. Defaults to `C:\Program Files\windows_exporter` |
Parameters are sent to the installer via `msiexec`.
On PowerShell, the `--%` should be passed before defining properties.
@@ -145,6 +150,11 @@ Define a config file.
msiexec /i <path-to-msi-file> --% CONFIG_FILE="D:\config.yaml"
```
Alternative install directory
```powershell
msiexec /i <path-to-msi-file> --% ADDLOCAL=FirewallException APPLICATIONFOLDER="F:\Program Files\windows_exporter"
```
On some older versions of Windows,
you may need to surround parameter values with double quotes to get the installation command parsing properly:
```powershell

View File

@@ -14,8 +14,11 @@
package main
import (
"errors"
"fmt"
"os"
"strings"
"unsafe"
"golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc"
@@ -33,6 +36,9 @@ var (
// stopCh is a channel to send a signal to the service manager that the service is stopping.
stopCh = make(chan struct{})
// serviceManagerFinishedCh is a channel to send a signal to the main function that the service manager has stopped the service.
serviceManagerFinishedCh = make(chan struct{})
)
// IsService variable declaration allows initiating time-sensitive components like registering the Windows service
@@ -49,33 +55,37 @@ var (
//
//nolint:gochecknoglobals
var IsService = func() bool {
defer func() {
go func() {
err := svc.Run(serviceName, &windowsExporterService{})
if err == nil {
return
}
_ = logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("failed to start service: %v", err))
}()
}()
var err error
isService, err := svc.IsWindowsService()
isService, err := isWindowsService()
if err != nil {
_ = logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("failed to detect service: %v", err))
logToFile(fmt.Sprintf("failed to detect service: %v", err))
exitCodeCh <- 1
return false
}
if !isService {
return false
}
defer func() {
go func() {
err := svc.Run(serviceName, &windowsExporterService{})
if err != nil {
// https://github.com/open-telemetry/opentelemetry-collector/pull/9042
if !errors.Is(err, windows.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
if logErr := logToEventToLog(windows.EVENTLOG_ERROR_TYPE, fmt.Sprintf("failed to start service: %v", err)); logErr != nil {
logToFile(fmt.Sprintf("failed to start service: %v", err))
}
}
}
serviceManagerFinishedCh <- struct{}{}
}()
}()
if err := logToEventToLog(windows.EVENTLOG_INFORMATION_TYPE, "attempting to start exporter service"); err != nil {
//nolint:gosec
_ = os.WriteFile("C:\\Program Files\\windows_exporter\\start-service.error.log", []byte(fmt.Sprintf("failed sent log to event log: %v", err)), 0o644)
logToFile(fmt.Sprintf("failed sent log to event log: %v", err))
exitCodeCh <- 2
}
@@ -122,7 +132,7 @@ func (s *windowsExporterService) Execute(_ []string, r <-chan svc.ChangeRequest,
// logToEventToLog logs a message to the Windows event log.
func logToEventToLog(eType uint16, msg string) error {
eventLog, err := eventlog.Open("windows_exporter")
eventLog, err := eventlog.Open(serviceName)
if err != nil {
return fmt.Errorf("failed to open event log: %w", err)
}
@@ -130,18 +140,70 @@ func logToEventToLog(eType uint16, msg string) error {
_ = eventLog.Close()
}(eventLog)
p, err := windows.UTF16PtrFromString(msg)
if err != nil {
return fmt.Errorf("error convert string to UTF-16: %w", err)
switch eType {
case windows.EVENTLOG_ERROR_TYPE:
err = eventLog.Error(102, msg)
case windows.EVENTLOG_WARNING_TYPE:
err = eventLog.Warning(101, msg)
case windows.EVENTLOG_INFORMATION_TYPE:
err = eventLog.Info(100, msg)
}
zero := uint16(0)
ss := []*uint16{p, &zero, &zero, &zero, &zero, &zero, &zero, &zero, &zero}
err = windows.ReportEvent(eventLog.Handle, eType, 0, 3299, 0, 9, 0, &ss[0], nil)
if err != nil {
return fmt.Errorf("error report event: %w", err)
}
return nil
}
func logToFile(msg string) {
if file, err := os.CreateTemp("", "windows_exporter.service.error.log"); err == nil {
_, _ = file.WriteString(msg)
_ = file.Close()
}
}
// isWindowsService is a clone of "golang.org/x/sys/windows/svc:IsWindowsService", but with a fix
// for Windows containers.
// Go cloned the .NET implementation of this function, which has since
// been patched to support Windows containers, which don't use Session ID 0 for services.
// https://github.com/dotnet/runtime/pull/74188
// This function can be replaced with go's once go brings in the fix.
//
// Copyright 2023-present Datadog, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// https://github.com/DataDog/datadog-agent/blob/46740e82ef40a04c4be545ed8c16a4b0d1f046cf/pkg/util/winutil/servicemain/servicemain.go#L128
func isWindowsService() (bool, error) {
var currentProcess windows.PROCESS_BASIC_INFORMATION
infoSize := uint32(unsafe.Sizeof(currentProcess))
err := windows.NtQueryInformationProcess(windows.CurrentProcess(), windows.ProcessBasicInformation, unsafe.Pointer(&currentProcess), infoSize, &infoSize)
if err != nil {
return false, err
}
var parentProcess *windows.SYSTEM_PROCESS_INFORMATION
for infoSize = uint32((unsafe.Sizeof(*parentProcess) + unsafe.Sizeof(uintptr(0))) * 1024); ; {
parentProcess = (*windows.SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(&make([]byte, infoSize)[0]))
err = windows.NtQuerySystemInformation(windows.SystemProcessInformation, unsafe.Pointer(parentProcess), infoSize, &infoSize)
if err == nil {
break
} else if !errors.Is(err, windows.STATUS_INFO_LENGTH_MISMATCH) {
return false, err
}
}
for ; ; parentProcess = (*windows.SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(uintptr(unsafe.Pointer(parentProcess)) + uintptr(parentProcess.NextEntryOffset))) {
if parentProcess.UniqueProcessID == currentProcess.InheritedFromUniqueProcessId {
return strings.EqualFold("services.exe", parentProcess.ImageName.String()), nil
}
if parentProcess.NextEntryOffset == 0 {
break
}
}
return false, nil
}

View File

@@ -57,7 +57,7 @@ func main() {
exitCodeCh <- exitCode
// Wait for the service control manager to signal that we are done.
<-stopCh
<-serviceManagerFinishedCh
}
func run() int {
@@ -163,11 +163,6 @@ func run() int {
return 1
}
// NOTE: This is temporary fix for issue #1092, calling kingpin.Parse
// twice makes slices flags duplicate its value, this clean up
// the first parse before the second call.
*webConfig.WebListenAddresses = (*webConfig.WebListenAddresses)[1:]
// Parse flags once more to include those discovered in configuration file(s).
if _, err = app.Parse(os.Args[1:]); err != nil {
logger.ErrorContext(ctx, "failed to parse CLI args from YAML file",
@@ -177,6 +172,12 @@ func run() int {
return 1
}
// NOTE: This is temporary fix for issue #1092, calling kingpin.Parse
// twice makes slices flags duplicate its value, this clean up
// the first parse before the second call.
slices.Sort(*webConfig.WebListenAddresses)
*webConfig.WebListenAddresses = slices.Clip(slices.Compact(*webConfig.WebListenAddresses))
logger, err = log.New(logConfig)
if err != nil {
//nolint:sloglint // we do not have an logger yet

View File

@@ -69,6 +69,23 @@ Show volume usage (%)
100.0 - 100 * (windows_logical_disk_free_bytes{instance="localhost", volume="C:"} / windows_logical_disk_size_bytes{instance="localhost", volume="C:"})
```
Disk Activity
```promql
(
rate(windows_logical_disk_read_seconds_total[2m])
+
rate(windows_logical_disk_write_seconds_total[2m])
)
/
(
rate(windows_logical_disk_read_seconds_total[2m])
+
rate(windows_logical_disk_write_seconds_total[2m])
+
rate(windows_logical_disk_idle_seconds_total[2m])
)
```
## Alerting examples
**prometheus.rules**
```yaml

View File

@@ -21,19 +21,21 @@ If given, a disk needs to *not* match the exclude regexp in order for the corres
## Metrics
Name | Description | Type | Labels
-----|-------------|------|-------
`requests_queued` | Number of requests outstanding on the disk at the time the performance data is collected | gauge | `disk`
`read_bytes_total` | Rate at which bytes are transferred from the disk during read operations | counter | `disk`
`reads_total` | Rate of read operations on the disk | counter | `disk`
`write_bytes_total` | Rate at which bytes are transferred to the disk during write operations | counter | `disk`
`writes_total` | Rate of write operations on the disk | counter | `disk`
`read_seconds_total` | Seconds the disk was busy servicing read requests | counter | `disk`
`write_seconds_total` | Seconds the disk was busy servicing write requests | counter | `disk`
`free_bytes` | Unused space of the disk in bytes (not real time, updates every 10-15 min) | gauge | `disk`
`size_bytes` | Total size of the disk in bytes (not real time, updates every 10-15 min) | gauge | `disk`
`idle_seconds_total` | Seconds the disk was idle (not servicing read/write requests) | counter | `disk`
`split_ios_total` | Number of I/Os to the disk split into multiple I/Os | counter | `disk`
| Name | Description | Type | Labels |
|--------------------------------------------------------|---------------------------------------------------------------------------------------------------------|---------|--------|
| windows_physical_disk_requests_queued | The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength) | Gauge | disk |
| windows_physical_disk_read_bytes_total | The number of bytes transferred from the disk during read operations (PhysicalDisk.DiskReadBytesPerSec) | Counter | disk |
| windows_physical_disk_reads_total | The number of read operations on the disk (PhysicalDisk.DiskReadsPerSec) | Counter | disk |
| windows_physical_disk_write_bytes_total | The number of bytes transferred to the disk during write operations (PhysicalDisk.DiskWriteBytesPerSec) | Counter | disk |
| windows_physical_disk_writes_total | The number of write operations on the disk (PhysicalDisk.DiskWritesPerSec) | Counter | disk |
| windows_physical_disk_read_seconds_total | Seconds that the disk was busy servicing read requests (PhysicalDisk.PercentDiskReadTime) | Counter | disk |
| windows_physical_disk_write_seconds_total | Seconds that the disk was busy servicing write requests (PhysicalDisk.PercentDiskWriteTime) | Counter | disk |
| windows_physical_disk_idle_seconds_total | Seconds that the disk was idle (PhysicalDisk.PercentIdleTime) | Counter | disk |
| windows_physical_disk_split_ios_total | The number of I/Os to the disk that were split into multiple I/Os (PhysicalDisk.SplitIOPerSec) | Counter | disk |
| windows_physical_disk_read_latency_seconds_total | The average time, in seconds, of a read operation from the disk (PhysicalDisk.AvgDiskSecPerRead) | Counter | disk |
| windows_physical_disk_write_latency_seconds_total | The average time, in seconds, of a write operation to the disk (PhysicalDisk.AvgDiskSecPerWrite) | Counter | disk |
| windows_physical_disk_read_write_latency_seconds_total | The time, in seconds, of the average disk transfer (PhysicalDisk.AvgDiskSecPerTransfer) | Counter | disk |
### Warning about size metrics
The `free_bytes` and `size_bytes` metrics are not updated in real time and might have a delay of 10-15min.
@@ -52,29 +54,4 @@ rate(windows_physical_disk_reads_total{instance="localhost", disk=~"0"}[2m]) + r
```
## Alerting examples
**prometheus.rules**
```yaml
groups:
- name: Windows Disk Alerts
rules:
# Sends an alert when disk space usage is above 95%
- alert: DiskSpaceUsage
expr: 100.0 - 100 * (windows_physical_disk_free_bytes / windows_physical_disk_size_bytes) > 95
for: 10m
labels:
severity: high
annotations:
summary: "Disk Space Usage (instance {{ $labels.instance }})"
description: "Disk Space on Drive is used more than 95%\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
# Alerts on disks with over 85% space usage predicted to fill within the next four days
- alert: DiskFilling
expr: 100 * (windows_physical_disk_free_bytes / windows_physical_disk_size_bytes) < 15 and predict_linear(windows_physical_disk_free_bytes[6h], 4 * 24 * 3600) < 0
for: 10m
labels:
severity: warning
annotations:
summary: "Disk full in four days (instance {{ $labels.instance }})"
description: "{{ $labels.disk }} is expected to fill up within four days. Currently {{ $value | humanize }}% is available.\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
```
_This collector does not yet have alerting examples, we would appreciate your help adding them!_

33
go.mod
View File

@@ -1,6 +1,8 @@
module github.com/prometheus-community/windows_exporter
go 1.23
go 1.23.0
toolchain go1.23.4
require (
github.com/Microsoft/hcsshim v0.12.9
@@ -8,13 +10,12 @@ require (
github.com/bmatcuk/doublestar/v4 v4.8.1
github.com/dimchansky/utfbom v1.1.1
github.com/go-ole/go-ole v1.3.0
github.com/google/uuid v1.6.0
github.com/prometheus/client_golang v1.20.5
github.com/prometheus/client_golang v1.21.1
github.com/prometheus/client_model v0.6.1
github.com/prometheus/common v0.61.0
github.com/prometheus/exporter-toolkit v0.13.2
github.com/prometheus/common v0.62.0
github.com/prometheus/exporter-toolkit v0.14.0
github.com/stretchr/testify v1.10.0
golang.org/x/sys v0.29.0
golang.org/x/sys v0.31.0
gopkg.in/yaml.v3 v3.0.1
)
@@ -23,7 +24,7 @@ require (
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/containerd/cgroups/v3 v3.0.4 // indirect
github.com/containerd/cgroups/v3 v3.0.5 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
@@ -32,7 +33,7 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/mdlayher/socket v0.5.1 // indirect
github.com/mdlayher/vsock v1.2.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -43,13 +44,13 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 // indirect
google.golang.org/grpc v1.68.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/oauth2 v0.28.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/grpc v1.71.0 // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

72
go.sum
View File

@@ -17,8 +17,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/containerd/cgroups/v3 v3.0.4 h1:2fs7l3P0Qxb1nKWuJNFiwhp2CqiKzho71DQkDrHJIo4=
github.com/containerd/cgroups/v3 v3.0.4/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
@@ -66,14 +66,14 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -92,15 +92,15 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.61.0 h1:3gv/GThfX0cV2lpO7gkTUwZru38mxevy90Bj8YFSRQQ=
github.com/prometheus/common v0.61.0/go.mod h1:zr29OCN/2BsJRaFwG8QOBr41D6kkchKbpeNH7pAjb/s=
github.com/prometheus/exporter-toolkit v0.13.2 h1:Z02fYtbqTMy2i/f+xZ+UK5jy/bl1Ex3ndzh06T/Q9DQ=
github.com/prometheus/exporter-toolkit v0.13.2/go.mod h1:tCqnfx21q6qN1KA4U3Bfb8uWzXfijIrJz3/kTIqMV7g=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/exporter-toolkit v0.14.0 h1:NMlswfibpcZZ+H0sZBiTjrA3/aBFHkNZqE+iCj5EmRg=
github.com/prometheus/exporter-toolkit v0.14.0/go.mod h1:Gu5LnVvt7Nr/oqTBUC23WILZepW0nffNo10XdhQcwWA=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@@ -128,8 +128,10 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@@ -145,30 +147,40 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -186,15 +198,19 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697 h1:LWZqQOEjDyONlF1H6afSWpAL/znlREo2tHfLoe+8LMA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20241118233622-e639e219e697/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.68.0 h1:aHQeeJbo8zAkAa3pRzrVjZlbz6uSfeOXlJNQM0RAbz0=
google.golang.org/grpc v1.68.0/go.mod h1:fmSPC5AsjSBCK54MyHRx48kpOti1/jRfOlwEWywNjWA=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -204,8 +220,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

BIN
installer/codesign.cer Normal file

Binary file not shown.

View File

@@ -44,6 +44,12 @@
<ServiceDependency Id="wmiApSrv" />
</ServiceInstall>
<ServiceControl Id="ServiceStateControl" Name="windows_exporter" Remove="uninstall" Start="install" Stop="both"/>
<!-- The "Name" field must match the argument to eventlog.Open() -->
<util:EventSource Log="Application" Name="windows_exporter"
EventMessageFile="%SystemRoot%\System32\EventCreate.exe"
SupportsErrors="yes"
SupportsInformationals="yes"
SupportsWarnings="yes"/>
</Component>
<Component Id="CreateTextfileDirectory" Directory="textfile_inputs" Guid="d03ef58a-9cbf-4165-ad39-d143e9b27e14">
<CreateFolder />

View File

@@ -37,7 +37,7 @@ type Collector struct {
config Config
// physicalMemoryBytes
// Deprecated: Use windows_physical_memory_total_bytes instead
// Deprecated: Use windows_memory_physical_total_bytes instead
physicalMemoryBytes *prometheus.Desc
// logicalProcessors
// Deprecated: Use windows_cpu_logical_processor instead
@@ -85,7 +85,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
)
c.physicalMemoryBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "physical_memory_bytes"),
"Deprecated: Use windows_physical_memory_total_bytes instead",
"Deprecated: Use windows_memory_physical_total_bytes instead",
nil,
nil,
)

View File

@@ -23,11 +23,10 @@ import (
"strings"
"sync"
"github.com/Microsoft/hcsshim/osversion"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/windows"
)
const (
@@ -157,19 +156,17 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
return nil
}
version := windows.RtlGetVersion()
subCollectors := map[string]struct {
build func() error
collect func(ch chan<- prometheus.Metric) error
close func()
minBuildNumber uint32
minBuildNumber uint16
}{
subCollectorDataStore: {
build: c.buildDataStore,
collect: c.collectDataStore,
close: c.perfDataCollectorDataStore.Close,
minBuildNumber: types.BuildNumberWindowsServer2022,
minBuildNumber: osversion.LTSC2022,
},
subCollectorDynamicMemoryBalancer: {
build: c.buildDynamicMemoryBalancer,
@@ -243,6 +240,8 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
},
}
buildNumber := osversion.Build()
// Result must order, to prevent test failures.
sort.Strings(c.config.CollectorsEnabled)
@@ -253,7 +252,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
return fmt.Errorf("unknown collector: %s", name)
}
if version.BuildNumber < subCollectors[name].minBuildNumber {
if buildNumber < subCollectors[name].minBuildNumber {
errs = append(errs, fmt.Errorf("collector %s requires Windows Server 2022 or newer", name))
continue

View File

@@ -18,6 +18,7 @@ package mscluster
import (
"fmt"
"github.com/Microsoft/hcsshim/osversion"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
@@ -192,7 +193,14 @@ type msClusterCluster struct {
}
func (c *Collector) buildCluster() error {
clusterMIQuery, err := mi.NewQuery("SELECT * FROM MSCluster_Cluster")
buildNumber := osversion.Build()
wmiSelect := "AddEvictDelay,AdminAccessPoint,AutoAssignNodeSite,AutoBalancerLevel,AutoBalancerMode,BackupInProgress,BlockCacheSize,ClusSvcHangTimeout,ClusSvcRegroupOpeningTimeout,ClusSvcRegroupPruningTimeout,ClusSvcRegroupStageTimeout,ClusSvcRegroupTickInMilliseconds,ClusterEnforcedAntiAffinity,ClusterFunctionalLevel,ClusterGroupWaitDelay,ClusterLogLevel,ClusterLogSize,ClusterUpgradeVersion,CrossSiteDelay,CrossSiteThreshold,CrossSubnetDelay,CrossSubnetThreshold,CsvBalancer,DatabaseReadWriteMode,DefaultNetworkRole,DisableGroupPreferredOwnerRandomization,DrainOnShutdown,DynamicQuorumEnabled,EnableSharedVolumes,FixQuorum,GracePeriodEnabled,GracePeriodTimeout,GroupDependencyTimeout,HangRecoveryAction,IgnorePersistentStateOnStartup,LogResourceControls,LowerQuorumPriorityNodeId,MessageBufferLength,MinimumNeverPreemptPriority,MinimumPreemptorPriority,NetftIPSecEnabled,PlacementOptions,PlumbAllCrossSubnetRoutes,PreventQuorum,QuarantineDuration,QuarantineThreshold,QuorumArbitrationTimeMax,QuorumArbitrationTimeMin,QuorumLogFileSize,QuorumTypeValue,RequestReplyTimeout,ResiliencyDefaultPeriod,ResiliencyLevel,ResourceDllDeadlockPeriod,RootMemoryReserved,RouteHistoryLength,S2DBusTypes,S2DCacheDesiredState,S2DCacheFlashReservePercent,S2DCachePageSizeKBytes,S2DEnabled,S2DIOLatencyThreshold,S2DOptimizations,SameSubnetDelay,SameSubnetThreshold,SecurityLevel,SharedVolumeVssWriterOperationTimeout,ShutdownTimeoutInMinutes,UseClientAccessNetworksForSharedVolumes,WitnessDatabaseWriteTimeout,WitnessDynamicWeight,WitnessRestartInterval"
if buildNumber >= osversion.LTSC2022 {
wmiSelect += ",DetectManagedEvents,SecurityLevelForStorage,MaxNumberOfNodes,DetectManagedEventsThreshold,DetectedCloudPlatform"
}
clusterMIQuery, err := mi.NewQuery(fmt.Sprintf("SELECT %s FROM MSCluster_Cluster", wmiSelect))
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
@@ -852,27 +860,6 @@ func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error {
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDetectedCloudPlatform,
prometheus.GaugeValue,
float64(v.DetectedCloudPlatform),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDetectManagedEvents,
prometheus.GaugeValue,
float64(v.DetectManagedEvents),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDetectManagedEventsThreshold,
prometheus.GaugeValue,
float64(v.DetectManagedEventsThreshold),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDisableGroupPreferredOwnerRandomization,
prometheus.GaugeValue,
@@ -957,13 +944,6 @@ func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error {
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterMaxNumberOfNodes,
prometheus.GaugeValue,
float64(v.MaxNumberOfNodes),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterMessageBufferLength,
prometheus.GaugeValue,
@@ -1167,13 +1147,6 @@ func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error {
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterSecurityLevelForStorage,
prometheus.GaugeValue,
float64(v.SecurityLevelForStorage),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterSharedVolumeVssWriterOperationTimeout,
prometheus.GaugeValue,
@@ -1215,6 +1188,43 @@ func (c *Collector) collectCluster(ch chan<- prometheus.Metric) error {
float64(v.WitnessRestartInterval),
v.Name,
)
if osversion.Build() >= osversion.LTSC2022 {
ch <- prometheus.MustNewConstMetric(
c.clusterDetectManagedEvents,
prometheus.GaugeValue,
float64(v.DetectManagedEvents),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDetectManagedEventsThreshold,
prometheus.GaugeValue,
float64(v.DetectManagedEventsThreshold),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterSecurityLevelForStorage,
prometheus.GaugeValue,
float64(v.SecurityLevelForStorage),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterMaxNumberOfNodes,
prometheus.GaugeValue,
float64(v.MaxNumberOfNodes),
v.Name,
)
ch <- prometheus.MustNewConstMetric(
c.clusterDetectedCloudPlatform,
prometheus.GaugeValue,
float64(v.DetectedCloudPlatform),
v.Name,
)
}
}
return nil

View File

@@ -48,7 +48,7 @@ type msClusterNetwork struct {
}
func (c *Collector) buildNetwork() error {
networkMIQuery, err := mi.NewQuery("SELECT * FROM MSCluster_Network")
networkMIQuery, err := mi.NewQuery("SELECT Characteristics,Flags,Metric,Role,State FROM MSCluster_Network")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}

View File

@@ -18,6 +18,7 @@ package mscluster
import (
"fmt"
"github.com/Microsoft/hcsshim/osversion"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
@@ -66,7 +67,14 @@ type msClusterNode struct {
}
func (c *Collector) buildNode() error {
nodeMIQuery, err := mi.NewQuery("SELECT * FROM MSCluster_Node")
buildNumber := osversion.Build()
wmiSelect := "BuildNumber,Characteristics,DynamicWeight,Flags,MajorVersion,MinorVersion,NeedsPreventQuorum,NodeDrainStatus,NodeHighestVersion,NodeLowestVersion,NodeWeight,State,StatusInformation"
if buildNumber >= osversion.LTSC2022 {
wmiSelect += ",DetectedCloudPlatform"
}
nodeMIQuery, err := mi.NewQuery(fmt.Sprintf("SELECT %s FROM MSCluster_Node", wmiSelect))
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}

View File

@@ -74,7 +74,7 @@ type msClusterResource struct {
}
func (c *Collector) buildResource() error {
resourceMIQuery, err := mi.NewQuery("SELECT * FROM MSCluster_Resource")
resourceMIQuery, err := mi.NewQuery("SELECT Name,Type,OwnerGroup,OwnerNode,Characteristics,DeadlockTimeout,EmbeddedFailureAction,Flags,IsAlivePollInterval,LooksAlivePollInterval,MonitorProcessId,PendingTimeout,ResourceClass,RestartAction,RestartDelay,RestartPeriod,RestartThreshold,RetryPeriodOnFailure,State,Subclass FROM MSCluster_Resource")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}

View File

@@ -66,7 +66,7 @@ type msClusterResourceGroup struct {
}
func (c *Collector) buildResourceGroup() error {
resourceGroupMIQuery, err := mi.NewQuery("SELECT * FROM MSCluster_ResourceGroup")
resourceGroupMIQuery, err := mi.NewQuery("SELECT AutoFailbackType,Characteristics,ColdStartSetting,DefaultOwner,FailbackWindowEnd,FailbackWindowStart,FailoverPeriod,FailoverThreshold,Flags,GroupType,OwnerNode,Priority,ResiliencyPeriod,State FROM MSCluster_ResourceGroup")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}

View File

@@ -26,25 +26,25 @@ import (
func (c *Collector) buildClrExceptions() {
c.numberOfExceptionsThrown = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "exceptions_thrown_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrExceptions+"_exceptions_thrown_total"),
"Displays the total number of exceptions thrown since the application started. This includes both .NET exceptions and unmanaged exceptions that are converted into .NET exceptions.",
[]string{"process"},
nil,
)
c.numberOfFilters = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "exceptions_filters_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrExceptions+"_exceptions_filters_total"),
"Displays the total number of .NET exception filters executed. An exception filter evaluates regardless of whether an exception is handled.",
[]string{"process"},
nil,
)
c.numberOfFinally = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "exceptions_finallys_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrExceptions+"_exceptions_finallys_total"),
"Displays the total number of finally blocks executed. Only the finally blocks executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.",
[]string{"process"},
nil,
)
c.throwToCatchDepth = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "throw_to_catch_depth_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrExceptions+"_throw_to_catch_depth_total"),
"Displays the total number of stack frames traversed, from the frame that threw the exception to the frame that handled the exception.",
[]string{"process"},
nil,

View File

@@ -26,19 +26,19 @@ import (
func (c *Collector) buildClrInterop() {
c.numberOfCCWs = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "com_callable_wrappers_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrInterop+"_com_callable_wrappers_total"),
"Displays the current number of COM callable wrappers (CCWs). A CCW is a proxy for a managed object being referenced from an unmanaged COM client.",
[]string{"process"},
nil,
)
c.numberOfMarshalling = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "interop_marshalling_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrInterop+"_interop_marshalling_total"),
"Displays the total number of times arguments and return values have been marshaled from managed to unmanaged code, and vice versa, since the application started.",
[]string{"process"},
nil,
)
c.numberOfStubs = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "interop_stubs_created_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrInterop+"_interop_stubs_created_total"),
"Displays the current number of stubs created by the common language runtime. Stubs are responsible for marshaling arguments and return values from managed to unmanaged code, and vice versa, during a COM interop call or a platform invoke call.",
[]string{"process"},
nil,

View File

@@ -26,25 +26,25 @@ import (
func (c *Collector) buildClrJIT() {
c.numberOfMethodsJitted = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "jit_methods_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrJIT+"_jit_methods_total"),
"Displays the total number of methods JIT-compiled since the application started. This counter does not include pre-JIT-compiled methods.",
[]string{"process"},
nil,
)
c.timeInJit = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "jit_time_percent"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrJIT+"_jit_time_percent"),
"Displays the percentage of time spent in JIT compilation. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase occurs when a method and its dependencies are compiled.",
[]string{"process"},
nil,
)
c.standardJitFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "jit_standard_failures_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrJIT+"_jit_standard_failures_total"),
"Displays the peak number of methods the JIT compiler has failed to compile since the application started. This failure can occur if the MSIL cannot be verified or if there is an internal error in the JIT compiler.",
[]string{"process"},
nil,
)
c.totalNumberOfILBytesJitted = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "jit_il_bytes_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrJIT+"_jit_il_bytes_total"),
"Displays the total number of Microsoft intermediate language (MSIL) bytes compiled by the just-in-time (JIT) compiler since the application started",
[]string{"process"},
nil,

View File

@@ -26,55 +26,55 @@ import (
func (c *Collector) buildClrLoading() {
c.bytesInLoaderHeap = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "loader_heap_size_bytes"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_loader_heap_size_bytes"),
"Displays the current size, in bytes, of the memory committed by the class loader across all application domains. Committed memory is the physical space reserved in the disk paging file.",
[]string{"process"},
nil,
)
c.currentAppDomains = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "appdomains_loaded_current"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_appdomains_loaded_current"),
"Displays the current number of application domains loaded in this application.",
[]string{"process"},
nil,
)
c.currentAssemblies = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "assemblies_loaded_current"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_assemblies_loaded_current"),
"Displays the current number of assemblies loaded across all application domains in the currently running application. If the assembly is loaded as domain-neutral from multiple application domains, this counter is incremented only once.",
[]string{"process"},
nil,
)
c.currentClassesLoaded = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "classes_loaded_current"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_classes_loaded_current"),
"Displays the current number of classes loaded in all assemblies.",
[]string{"process"},
nil,
)
c.totalAppDomains = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "appdomains_loaded_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_appdomains_loaded_total"),
"Displays the peak number of application domains loaded since the application started.",
[]string{"process"},
nil,
)
c.totalAppDomainsUnloaded = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "appdomains_unloaded_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_appdomains_unloaded_total"),
"Displays the total number of application domains unloaded since the application started. If an application domain is loaded and unloaded multiple times, this counter increments each time the application domain is unloaded.",
[]string{"process"},
nil,
)
c.totalAssemblies = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "assemblies_loaded_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_assemblies_loaded_total"),
"Displays the total number of assemblies loaded since the application started. If the assembly is loaded as domain-neutral from multiple application domains, this counter is incremented only once.",
[]string{"process"},
nil,
)
c.totalClassesLoaded = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "classes_loaded_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_classes_loaded_total"),
"Displays the cumulative number of classes loaded in all assemblies since the application started.",
[]string{"process"},
nil,
)
c.totalNumberOfLoadFailures = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "class_load_failures_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLoading+"_class_load_failures_total"),
"Displays the peak number of classes that have failed to load since the application started.",
[]string{"process"},
nil,

View File

@@ -26,43 +26,43 @@ import (
func (c *Collector) buildClrLocksAndThreads() {
c.currentQueueLength = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "current_queue_length"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_current_queue_length"),
"Displays the total number of threads that are currently waiting to acquire a managed lock in the application.",
[]string{"process"},
nil,
)
c.numberOfCurrentLogicalThreads = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "current_logical_threads"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_current_logical_threads"),
"Displays the number of current managed thread objects in the application. This counter maintains the count of both running and stopped threads. ",
[]string{"process"},
nil,
)
c.numberOfCurrentPhysicalThreads = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "physical_threads_current"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_physical_threads_current"),
"Displays the number of native operating system threads created and owned by the common language runtime to act as underlying threads for managed thread objects. This counter's value does not include the threads used by the runtime in its internal operations; it is a subset of the threads in the operating system process.",
[]string{"process"},
nil,
)
c.numberOfCurrentRecognizedThreads = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "recognized_threads_current"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_recognized_threads_current"),
"Displays the number of threads that are currently recognized by the runtime. These threads are associated with a corresponding managed thread object. The runtime does not create these threads, but they have run inside the runtime at least once.",
[]string{"process"},
nil,
)
c.numberOfTotalRecognizedThreads = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "recognized_threads_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_recognized_threads_total"),
"Displays the total number of threads that have been recognized by the runtime since the application started. These threads are associated with a corresponding managed thread object. The runtime does not create these threads, but they have run inside the runtime at least once.",
[]string{"process"},
nil,
)
c.queueLengthPeak = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "queue_length_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_queue_length_total"),
"Displays the total number of threads that waited to acquire a managed lock since the application started.",
[]string{"process"},
nil,
)
c.totalNumberOfContentions = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "contentions_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrLocksAndThreads+"_contentions_total"),
"Displays the total number of times that threads in the runtime have attempted to acquire a managed lock unsuccessfully.",
[]string{"process"},
nil,

View File

@@ -26,73 +26,73 @@ import (
func (c *Collector) buildClrMemory() {
c.allocatedBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "allocated_bytes_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_allocated_bytes_total"),
"Displays the total number of bytes allocated on the garbage collection heap.",
[]string{"process"},
nil,
)
c.finalizationSurvivors = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "finalization_survivors"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_finalization_survivors"),
"Displays the number of garbage-collected objects that survive a collection because they are waiting to be finalized.",
[]string{"process"},
nil,
)
c.heapSize = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "heap_size_bytes"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_heap_size_bytes"),
"Displays the maximum bytes that can be allocated; it does not indicate the current number of bytes allocated.",
[]string{"process", "area"},
nil,
)
c.promotedBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "promoted_bytes"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_promoted_bytes"),
"Displays the bytes that were promoted from the generation to the next one during the last GC. Memory is promoted when it survives a garbage collection.",
[]string{"process", "area"},
nil,
)
c.numberGCHandles = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "number_gc_handles"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_number_gc_handles"),
"Displays the current number of garbage collection handles in use. Garbage collection handles are handles to resources external to the common language runtime and the managed environment.",
[]string{"process"},
nil,
)
c.numberCollections = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "collections_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_collections_total"),
"Displays the number of times the generation objects are garbage collected since the application started.",
[]string{"process", "area"},
nil,
)
c.numberInducedGC = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "induced_gc_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_induced_gc_total"),
"Displays the peak number of times garbage collection was performed because of an explicit call to GC.Collect.",
[]string{"process"},
nil,
)
c.numberOfPinnedObjects = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "number_pinned_objects"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_number_pinned_objects"),
"Displays the number of pinned objects encountered in the last garbage collection.",
[]string{"process"},
nil,
)
c.numberOfSinkBlocksInUse = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "number_sink_blocksinuse"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_number_sink_blocksinuse"),
"Displays the current number of synchronization blocks in use. Synchronization blocks are per-object data structures allocated for storing synchronization information. They hold weak references to managed objects and must be scanned by the garbage collector.",
[]string{"process"},
nil,
)
c.numberTotalCommittedBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "committed_bytes"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_committed_bytes"),
"Displays the amount of virtual memory, in bytes, currently committed by the garbage collector. Committed memory is the physical memory for which space has been reserved in the disk paging file.",
[]string{"process"},
nil,
)
c.numberTotalReservedBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "reserved_bytes"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_reserved_bytes"),
"Displays the amount of virtual memory, in bytes, currently reserved by the garbage collector. Reserved memory is the virtual memory space reserved for the application when no disk or main memory pages have been used.",
[]string{"process"},
nil,
)
c.timeInGC = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "gc_time_percent"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrMemory+"_gc_time_percent"),
"Displays the percentage of time that was spent performing a garbage collection in the last sample.",
[]string{"process"},
nil,

View File

@@ -26,37 +26,37 @@ import (
func (c *Collector) buildClrRemoting() {
c.channels = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "channels_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_channels_total"),
"Displays the total number of remoting channels registered across all application domains since application started.",
[]string{"process"},
nil,
)
c.contextBoundClassesLoaded = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "context_bound_classes_loaded"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_context_bound_classes_loaded"),
"Displays the current number of context-bound classes that are loaded.",
[]string{"process"},
nil,
)
c.contextBoundObjects = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "context_bound_objects_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_context_bound_objects_total"),
"Displays the total number of context-bound objects allocated.",
[]string{"process"},
nil,
)
c.contextProxies = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "context_proxies_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_context_proxies_total"),
"Displays the total number of remoting proxy objects in this process since it started.",
[]string{"process"},
nil,
)
c.contexts = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "contexts"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_contexts"),
"Displays the current number of remoting contexts in the application.",
[]string{"process"},
nil,
)
c.totalRemoteCalls = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "remote_calls_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrRemoting+"_remote_calls_total"),
"Displays the total number of remote procedure calls invoked since the application started.",
[]string{"process"},
nil,

View File

@@ -26,25 +26,25 @@ import (
func (c *Collector) buildClrSecurity() {
c.numberLinkTimeChecks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "link_time_checks_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrSecurity+"_link_time_checks_total"),
"Displays the total number of link-time code access security checks since the application started.",
[]string{"process"},
nil,
)
c.timeInRTChecks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "rt_checks_time_percent"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrSecurity+"_rt_checks_time_percent"),
"Displays the percentage of time spent performing runtime code access security checks in the last sample.",
[]string{"process"},
nil,
)
c.stackWalkDepth = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "stack_walk_depth"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrSecurity+"_stack_walk_depth"),
"Displays the depth of the stack during that last runtime code access security check.",
[]string{"process"},
nil,
)
c.totalRuntimeChecks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "runtime_checks_total"),
prometheus.BuildFQName(types.Namespace, Name, collectorClrSecurity+"_runtime_checks_total"),
"Displays the total number of runtime code access security checks performed since the application started.",
[]string{"process"},
nil,

View File

@@ -139,13 +139,6 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
c.logger = logger.With(slog.String("collector", Name))
var err error
c.perfDataCollectorTerminalServicesSession, err = pdh.NewCollector[perfDataCounterValuesTerminalServicesSession](pdh.CounterTypeRaw, "Terminal Services Session", pdh.InstancesAll)
if err != nil {
return fmt.Errorf("failed to create Terminal Services Session collector: %w", err)
}
c.connectionBrokerEnabled = isConnectionBrokerServer(miSession)
if c.connectionBrokerEnabled {
@@ -250,11 +243,18 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
nil,
)
var err error
c.hServer, err = wtsapi32.WTSOpenServer("")
if err != nil {
return fmt.Errorf("failed to open WTS server: %w", err)
}
c.perfDataCollectorTerminalServicesSession, err = pdh.NewCollector[perfDataCounterValuesTerminalServicesSession](pdh.CounterTypeRaw, "Terminal Services Session", pdh.InstancesAll)
if err != nil {
return fmt.Errorf("failed to create Terminal Services Session collector: %w", err)
}
return nil
}

View File

@@ -125,13 +125,6 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
}
}
var err error
c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "Windows Time Service", nil)
if err != nil {
return fmt.Errorf("failed to create Windows Time Service collector: %w", err)
}
c.currentTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"),
"OperatingSystem.LocalDateTime",
@@ -181,6 +174,13 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil,
)
var err error
c.perfDataCollector, err = pdh.NewCollector[perfDataCounterValues](pdh.CounterTypeRaw, "Windows Time Service", nil)
if err != nil {
return fmt.Errorf("failed to create Windows Time Service collector: %w", err)
}
return nil
}

View File

@@ -22,7 +22,6 @@ import (
"strconv"
"time"
"github.com/google/uuid"
"github.com/prometheus-community/windows_exporter/pkg/collector"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/collectors"
@@ -82,8 +81,7 @@ func New(logger *slog.Logger, metricCollectors *collector.Collection, options *O
func (c *MetricsHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger := c.logger.With(
slog.Any("remote", r.RemoteAddr),
slog.Any("correlation_id", uuid.New().String()),
slog.String("remote", r.RemoteAddr),
)
scrapeTimeout := c.getScrapeTimeout(logger, r)

View File

@@ -17,53 +17,41 @@
package eventlog
import (
"bytes"
"fmt"
"io"
"regexp"
"strings"
"golang.org/x/sys/windows"
)
const (
// NeLogOemCode is a generic error log entry for OEMs to use to
// elog errors from OEM value added services.
// See: https://github.com/microsoft/win32metadata/blob/2f3c5282ce1024a712aeccd90d3aa50bf7a49e27/generation/WinSDK/RecompiledIdlHeaders/um/LMErrlog.h#L824-L845
NeLogOemCode = uint32(3299)
"golang.org/x/sys/windows/svc/eventlog"
)
// Interface guard.
var _ io.Writer = (*Writer)(nil)
//nolint:gochecknoglobals
var EmptyStringUTF16 uint16
var reStripTimeAndLevel = regexp.MustCompile(`^time=\S+ level=\S+ `)
type Writer struct {
handle windows.Handle
handle *eventlog.Log
}
// NewEventLogWriter returns a new Writer which writes to Windows EventLog.
func NewEventLogWriter(handle windows.Handle) *Writer {
// NewEventLogWriter returns a new Writer, which writes to Windows EventLog.
func NewEventLogWriter(handle *eventlog.Log) *Writer {
return &Writer{handle: handle}
}
func (w *Writer) Write(p []byte) (int, error) {
var eType uint16
var err error
msg := strings.TrimSpace(string(p))
eventLogMsg := reStripTimeAndLevel.ReplaceAllString(msg, "")
switch {
case bytes.Contains(p, []byte(" level=error")) || bytes.Contains(p, []byte(`"level":"error"`)):
eType = windows.EVENTLOG_ERROR_TYPE
case bytes.Contains(p, []byte(" level=warn")) || bytes.Contains(p, []byte(`"level":"warn"`)):
eType = windows.EVENTLOG_WARNING_TYPE
case strings.Contains(msg, " level=ERROR") || strings.Contains(msg, `"level":"error"`):
err = w.handle.Error(102, eventLogMsg)
case strings.Contains(msg, " level=WARN") || strings.Contains(msg, `"level":"warn"`):
err = w.handle.Warning(101, eventLogMsg)
default:
eType = windows.EVENTLOG_INFORMATION_TYPE
err = w.handle.Info(100, eventLogMsg)
}
msg, err := windows.UTF16PtrFromString(string(p))
if err != nil {
return 0, fmt.Errorf("error convert string to UTF-16: %w", err)
}
ss := []*uint16{msg, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16, &EmptyStringUTF16}
return len(p), windows.ReportEvent(w.handle, eType, 0, NeLogOemCode, 0, 9, 0, &ss[0], nil)
return len(p), err
}

View File

@@ -24,7 +24,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/log/eventlog"
"github.com/prometheus/common/promslog"
"golang.org/x/sys/windows"
wineventlog "golang.org/x/sys/windows/svc/eventlog"
)
// AllowedFile is a settable identifier for the output file that the logger can have.
@@ -51,12 +51,12 @@ func (f *AllowedFile) Set(s string) error {
case "stderr":
f.w = os.Stderr
case "eventlog":
handle, err := windows.RegisterEventSource(nil, windows.StringToUTF16Ptr("windows_exporter"))
eventLog, err := wineventlog.Open("windows_exporter")
if err != nil {
return fmt.Errorf("failed to open event log: %w", err)
}
f.w = eventlog.NewEventLogWriter(handle)
f.w = eventlog.NewEventLogWriter(eventLog)
default:
file, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o200)
if err != nil {

View File

@@ -138,6 +138,10 @@ func (o *OperationUnmarshalCallbacks) InstanceResult(
element, err := instance.GetElement(miTag)
if err != nil {
if errors.Is(err, MI_RESULT_NO_SUCH_PROPERTY) {
continue
}
o.errCh <- fmt.Errorf("failed to get element %s: %w", miTag, err)
return 0

View File

@@ -172,6 +172,12 @@ func NewCollectorWithReflection(resultType CounterType, object string, instances
continue
}
if bufLen == 0 {
errs = append(errs, errors.New("GetCounterInfo: buffer length is zero"))
continue
}
buf := make([]byte, bufLen)
if ret := GetCounterInfo(counterHandle, 0, &bufLen, &buf[0]); ret != ErrorSuccess {
errs = append(errs, fmt.Errorf("GetCounterInfo: %w", NewPdhError(ret)))

View File

@@ -16,10 +16,5 @@
package types
const (
BuildNumberWindowsServer2025 uint32 = 26100
BuildNumberWindowsServer2022 uint32 = 20348
BuildNumberWindowsServer2019 uint32 = 17763
BuildNumberWindowsServer2016 uint32 = 14393
Namespace = "windows"
)

View File

@@ -105,7 +105,7 @@ test_alpha_total 42
# TYPE windows_cs_hostname gauge
# HELP windows_cs_logical_processors Deprecated: Use windows_cpu_logical_processor instead
# TYPE windows_cs_logical_processors gauge
# HELP windows_cs_physical_memory_bytes Deprecated: Use windows_physical_memory_total_bytes instead
# HELP windows_cs_physical_memory_bytes Deprecated: Use windows_memory_physical_total_bytes instead
# TYPE windows_cs_physical_memory_bytes gauge
# HELP windows_exporter_build_info A metric with a constant '1' value labeled by version, revision, branch, goversion from which windows_exporter was built, and the goos and goarch for the build.
# TYPE windows_exporter_build_info gauge