Compare commits

...

12 Commits

Author SHA1 Message Date
Jan-Otto Kröpke
7a9a4e5831 pagefile: BREAKING: move paging metrics from os to dedicated collector (click PR for more information) (#1735)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-11-14 22:39:59 +01:00
Jan-Otto Kröpke
df8513ab8e Update README.md
Signed-off-by: Jan-Otto Kröpke <github@jkroepke.de>
2024-11-14 22:32:25 +01:00
Jan-Otto Kröpke
1956330ac4 physical_disk: refactor collector (#1734)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-11-14 22:28:28 +01:00
Jan-Otto Kröpke
baa4dc16ae chore: disable quay.io push, since no credentials are available. (#1733)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-11-14 20:14:30 +01:00
Jan-Otto Kröpke
d13d726453 chore: Switch to hostprocess base image and add support for Windows Server 2025 on Kubernetes (click PR number for more information) (#1731)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-11-14 20:01:15 +01:00
Jan-Otto Kröpke
31bcf42473 system: refactor collector (#1730)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
2024-11-14 00:06:22 +01:00
Jan-Otto Kröpke
f332361723 terminal_services: refactor collector (#1729) 2024-11-13 21:38:31 +01:00
Jan-Otto Kröpke
b4f50c542c time: refactor collector (#1728) 2024-11-13 19:26:47 +01:00
Jan-Otto Kröpke
b53f18bcc6 vmware: refactor collector (#1727) 2024-11-12 23:16:22 +01:00
Jan-Otto Kröpke
eeb7955f5e udp: Added UDP collector (#1725) 2024-11-11 17:17:19 +01:00
dependabot[bot]
55181f5bac chore(deps): bump golang.org/x/sys from 0.26.0 to 0.27.0 (#1724)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-11 13:01:20 +01:00
Jan-Otto Kröpke
e6c9253f15 feat: add perfcounter.engine CLI option as alternative to WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE env (#1723) 2024-11-09 23:41:59 +01:00
67 changed files with 1413 additions and 746 deletions

View File

@@ -37,7 +37,7 @@ jobs:
- name: check - name: check
run: | run: |
PR_TITLE_PREFIX=$(echo "$PR_TITLE" | cut -d':' -f1) PR_TITLE_PREFIX=$(echo "$PR_TITLE" | cut -d':' -f1)
if [[ -d "internal/collector/$PR_TITLE_PREFIX" ]] || [[ -d "internal/$PR_TITLE_PREFIX" ]] || [[ -d "pkg/$PR_TITLE_PREFIX" ]] || [[ -d "$PR_TITLE_PREFIX" ]] || [[ "$PR_TITLE_PREFIX" == "docs" ]] || [[ "$PR_TITLE_PREFIX" == "ci" ]] || [[ "$PR_TITLE_PREFIX" == "revert" ]] || [[ "$PR_TITLE_PREFIX" == "fix" ]] || [[ "$PR_TITLE_PREFIX" == "chore" ]] || [[ "$PR_TITLE_PREFIX" == "chore(docs)" ]] || [[ "$PR_TITLE_PREFIX" == "chore(deps)" ]] || [[ "$PR_TITLE_PREFIX" == "*" ]] || [[ "$PR_TITLE_PREFIX" == "Synchronize common files from prometheus/prometheus" ]]; then if [[ -d "internal/collector/$PR_TITLE_PREFIX" ]] || [[ -d "internal/$PR_TITLE_PREFIX" ]] || [[ -d "pkg/$PR_TITLE_PREFIX" ]] || [[ -d "$PR_TITLE_PREFIX" ]] || [[ "$PR_TITLE_PREFIX" == "docs" ]] || [[ "$PR_TITLE_PREFIX" == "ci" ]] || [[ "$PR_TITLE_PREFIX" == "revert" ]] || [[ "$PR_TITLE_PREFIX" == "fix" ]] || [[ "$PR_TITLE_PREFIX" == "feat" ]] || [[ "$PR_TITLE_PREFIX" == "chore" ]] || [[ "$PR_TITLE_PREFIX" == "chore(docs)" ]] || [[ "$PR_TITLE_PREFIX" == "chore(deps)" ]] || [[ "$PR_TITLE_PREFIX" == "*" ]] || [[ "$PR_TITLE_PREFIX" == "Synchronize common files from prometheus/prometheus" ]]; then
exit 0 exit 0
fi fi

View File

@@ -6,6 +6,7 @@ on:
branches: branches:
- master - master
pull_request: pull_request:
workflow_dispatch:
release: release:
types: types:
- published - published
@@ -16,10 +17,7 @@ permissions:
packages: write packages: write
env: env:
VERSION_PROMU: '0.14.0' VERSION_PROMU: '0.17.0'
VERSION_CONTAINERD: '1.7.21'
VERSION_BUILDKIT: '0.15.2'
VERSION_BUILDX: '0.16.2'
jobs: jobs:
build: build:
@@ -33,27 +31,6 @@ jobs:
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
# https://github.com/pl4nty/Windows-Containers/blob/Main/helpful_tools/Install-BuildKit-GitHubActions/workflow.yaml
- name: Setup containerd
run: |
curl.exe -L https://github.com/containerd/containerd/releases/download/v${{ env.VERSION_CONTAINERD }}/containerd-${{ env.VERSION_CONTAINERD }}-windows-amd64.tar.gz -o containerd.tar.gz
tar.exe xvf containerd.tar.gz
.\bin\containerd.exe --register-service
Start-Service containerd
- name: Setup BuildKit
run: |
curl.exe -L https://github.com/moby/buildkit/releases/download/v${{ env.VERSION_BUILDKIT }}/buildkit-v${{ env.VERSION_BUILDKIT }}.windows-amd64.tar.gz -o buildkit.tar.gz
tar.exe xvf buildkit.tar.gz
.\bin\buildkitd.exe --register-service
Start-Service buildkitd
- name: Setup Docker Buildx
run: |
curl.exe -L https://github.com/docker/buildx/releases/download/v${{ env.VERSION_BUILDX }}/buildx-v${{ env.VERSION_BUILDX }}.windows-amd64.exe -o $env:ProgramData\Docker\cli-plugins\docker-buildx.exe
- uses: docker/setup-buildx-action@v3
with:
driver: remote
endpoint: npipe:////./pipe/buildkitd
- name: Install WiX - name: Install WiX
run: dotnet tool install --global wix run: dotnet tool install --global wix
@@ -114,16 +91,27 @@ jobs:
output\windows_exporter-*.exe output\windows_exporter-*.exe
output\windows_exporter-*.msi output\windows_exporter-*.msi
- name: Build Docker Artifacts - name: Release
run: make build-all if: startsWith(github.ref, 'refs/tags/')
env: env:
VERSION: >- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
${{ run: |
startsWith(github.ref, 'refs/tags/') && 'latest' || $TagName = $env:GITHUB_REF -replace 'refs/tags/', ''
( Get-ChildItem -Path output\* -Include @('windows_exporter*.msi', 'windows_exporter*.exe', 'sha256sums.txt') | Foreach-Object {gh release upload $TagName $_}
github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || github.ref_name docker:
) name: Build docker images
}} runs-on: ubuntu-latest
needs:
- build
steps:
- uses: actions/checkout@v4
with:
fetch-depth: '0'
- name: Download Artifacts
uses: actions/download-artifact@v4
with:
name: windows_exporter_binaries
- name: Login to Docker Hub - name: Login to Docker Hub
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
@@ -137,8 +125,8 @@ jobs:
# uses: docker/login-action@v3 # uses: docker/login-action@v3
# with: # with:
# registry: quay.io # registry: quay.io
# username: 'robot' # username: ${{ secrets.QUAY_USER }}
# password: ${{ secrets.QUAY_IO_API_TOKEN }} # password: ${{ secrets.QUAY_PASS }}
- name: Login to GitHub container registry - name: Login to GitHub container registry
if: ${{ github.event_name != 'pull_request' }} if: ${{ github.event_name != 'pull_request' }}
@@ -148,19 +136,32 @@ jobs:
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Latest image - name: Docker meta
if: ${{ github.event_name != 'pull_request' }} id: meta
env: uses: docker/metadata-action@v5
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with:
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && 'latest' || github.ref_name }} images: |
run: | ghcr.io/prometheus-community/windows-exporter
make push-all docker.io/prometheuscommunity/windows-exporter
# quay.io/prometheuscommunity/windows-exporter
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=ref,event=pr
labels: |
org.opencontainers.image.title=windows_exporter
org.opencontainers.image.description=A Prometheus exporter for Windows machines.
org.opencontainers.image.vendor=The Prometheus Community
org.opencontainers.image.licenses=MIT
- name: Release - name: Set up Docker Buildx
if: startsWith(github.ref, 'refs/tags/') uses: docker/setup-buildx-action@v3
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Build and push
run: | uses: docker/build-push-action@v6
$TagName = $env:GITHUB_REF -replace 'refs/tags/', '' with:
Get-ChildItem -Path output\* -Include @('windows_exporter*.msi', 'windows_exporter*.exe', 'sha256sums.txt') | Foreach-Object {gh release upload $TagName $_} context: .
make push-all push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: windows/amd64

View File

@@ -1,9 +1,13 @@
# Note this image doesn't really matter for hostprocess but it is good to build per OS version # mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0
# the files in the image are copied to $env:CONTAINER_SANDBOX_MOUNT_POINT on the host # Using this image as a base for HostProcess containers has a few advantages over using other base images for Windows containers including:
# but the file system is the Host NOT the container # - Smaller image size
ARG BASE="mcr.microsoft.com/windows/nanoserver:ltsc2022" # - OS compatibility (works on any Windows version that supports containers)
# This image MUST be built with docker buildx build (buildx) command on a Linux system.
# Ref: https://github.com/microsoft/windows-host-process-containers-base-image
ARG BASE="mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0"
FROM $BASE FROM $BASE
ENV PATH="C:\Windows\system32;C:\Windows;" COPY windows_exporter*-amd64.exe /windows_exporter.exe
COPY output/amd64/windows_exporter.exe /windows_exporter.exe
ENTRYPOINT ["windows_exporter.exe"] ENTRYPOINT ["windows_exporter.exe"]

View File

@@ -1,22 +0,0 @@
# Build this Docker Image on any platform with
# docker buildx build -t a --platform=windows/amd64 .
ARG BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0
FROM --platform=$BUILDPLATFORM golang:1.21 as builder
ARG TARGETARCH
ARG TARGETOS
# Get dependencies
WORKDIR /w
COPY go.mod go.sum ./
RUN go mod download
RUN go install github.com/prometheus/promu@latest
# Build windows_exporter
COPY . ./
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH make windows_exporter.exe
FROM $BASE
COPY --from=builder /w/windows_exporter.exe /windows_exporter.exe
ENTRYPOINT ["windows_exporter.exe"]

View File

@@ -36,7 +36,7 @@ lint:
.PHONY: e2e-test .PHONY: e2e-test
e2e-test: windows_exporter.exe e2e-test: windows_exporter.exe
pwsh -NonInteractive -ExecutionPolicy Bypass -File .\tools\end-to-end-test.ps1 powershell -NonInteractive -ExecutionPolicy Bypass -File .\tools\end-to-end-test.ps1
.PHONY: promtool .PHONY: promtool
promtool: windows_exporter.exe promtool: windows_exporter.exe
@@ -64,31 +64,19 @@ build-hostprocess:
sub-build-%: sub-build-%:
$(MAKE) OS=$* build-image $(MAKE) OS=$* build-image
build-all: $(addprefix sub-build-,$(ALL_OS)) build-hostprocess build-all: crossbuild
@for docker_repo in ${DOCKER_REPO}; do \
push: echo $(DOCKER) buildx build -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) .; \
set -x; \
for docker_repo in ${DOCKER_REPO}; do \
for osversion in ${ALL_OS}; do \
$(DOCKER) tag local/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion} $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \
$(DOCKER) push $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \
$(DOCKER) manifest create --amend $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \
full_version=`$(DOCKER) manifest inspect $(BASE_IMAGE):$${osversion} | grep "os.version" | head -n 1 | awk -F\" '{print $$4}'` || true; \
$(DOCKER) manifest annotate --os windows --arch amd64 --os-version $${full_version} $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-$${osversion}; \
done; \
$(DOCKER) manifest push --purge $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION); \
done done
# We can't load the image into the local docker store, so we have to build and push it in one go push:
push-hostprocess: @for docker_repo in ${DOCKER_REPO}; do \
set -x; \ echo $(DOCKER) buildx build --push -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) .; \
for docker_repo in ${DOCKER_REPO}; do \
$(DOCKER) buildx build --push --build-arg=BASE=mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0 -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION)-hostprocess .; \
done done
.PHONY: push-all .PHONY: push-all
push-all: build-all push-all: build-all
$(MAKE) DOCKER_REPO="$(ALL_DOCKER_REPOS)" push # push-hostprocess - disabled until it works on Windows $(MAKE) DOCKER_REPO="$(ALL_DOCKER_REPOS)" push
# Mandatory target for container description sync action # Mandatory target for container description sync action
.PHONY: docker-repo-name .PHONY: docker-repo-name

View File

@@ -1,6 +1,12 @@
# windows_exporter # windows_exporter
![Build Status](https://github.com/prometheus-community/windows_exporter/workflows/windows_exporter%20CI/CD/badge.svg) [![CI](https://github.com/prometheus-community/windows_exporter/actions/workflows/release.yml/badge.svg)](https://github.com/prometheus-community/windows_exporter)
[![Linting](https://github.com/prometheus-community/windows_exporter/actions/workflows/lint.yml/badge.svg)](https://github.com/prometheus-community/windows_exporter)
[![GitHub license](https://img.shields.io/github/license/prometheus-community/windows_exporter)](https://github.com/prometheus-community/windows_exporter/blob/master/LICENSE.txt)
[![Current Release](https://img.shields.io/github/release/prometheus-community/windows_exporter.svg?logo=github)](https://github.com/prometheus-community/windows_exporter/releases/latest)
[![GitHub Repo stars](https://img.shields.io/github/stars/prometheus-community/windows_exporter?style=flat&logo=github)](https://github.com/prometheus-community/windows_exporter/stargazers)
[![GitHub all releases](https://img.shields.io/github/downloads/prometheus-community/windows_exporter/total?logo=github)](https://github.com/prometheus-community/windows_exporter/releases/latest)
[![Go Report Card](https://goreportcard.com/badge/github.com/prometheus-community/windows_exporter)](https://goreportcard.com/report/github.com/prometheus-community/windows_exporter)
A Prometheus exporter for Windows machines. A Prometheus exporter for Windows machines.
@@ -35,6 +41,7 @@ Name | Description | Enabled by default
[netframework](docs/collector.netframework.md) | .NET Framework metrics | [netframework](docs/collector.netframework.md) | .NET Framework metrics |
[net](docs/collector.net.md) | Network interface I/O | &#10003; [net](docs/collector.net.md) | Network interface I/O | &#10003;
[os](docs/collector.os.md) | OS metrics (memory, processes, users) | &#10003; [os](docs/collector.os.md) | OS metrics (memory, processes, users) | &#10003;
[pagefile](docs/collector.pagefile.md) | pagefile metrics |
[perfdata](docs/collector.perfdata.md) | Custom perfdata metrics | [perfdata](docs/collector.perfdata.md) | Custom perfdata metrics |
[physical_disk](docs/collector.physical_disk.md) | physical disk metrics | &#10003; [physical_disk](docs/collector.physical_disk.md) | physical disk metrics | &#10003;
[printer](docs/collector.printer.md) | Printer metrics | [printer](docs/collector.printer.md) | Printer metrics |
@@ -51,6 +58,7 @@ Name | Description | Enabled by default
[textfile](docs/collector.textfile.md) | Read prometheus metrics from a text file | [textfile](docs/collector.textfile.md) | Read prometheus metrics from a text file |
[thermalzone](docs/collector.thermalzone.md) | Thermal information | [thermalzone](docs/collector.thermalzone.md) | Thermal information |
[time](docs/collector.time.md) | Windows Time Service | [time](docs/collector.time.md) | Windows Time Service |
[udp](docs/collector.udp.md) | UDP connections |
[update](docs/collector.update.md) | Windows Update Service | [update](docs/collector.update.md) | Windows Update Service |
[vmware](docs/collector.vmware.md) | Performance counters installed by the Vmware Guest agent | [vmware](docs/collector.vmware.md) | Performance counters installed by the Vmware Guest agent |

View File

@@ -41,5 +41,6 @@ This directory contains documentation of the collectors in the windows_exporter,
- [`textfile`](collector.textfile.md) - [`textfile`](collector.textfile.md)
- [`thermalzone`](collector.thermalzone.md) - [`thermalzone`](collector.thermalzone.md)
- [`time`](collector.time.md) - [`time`](collector.time.md)
- [`udp`](collector.udp.md)
- [`update`](collector.update.md) - [`update`](collector.update.md)
- [`vmware`](collector.vmware.md) - [`vmware`](collector.vmware.md)

View File

@@ -14,12 +14,10 @@ None
## Metrics ## Metrics
| Name | Description | Type | Labels | | Name | Description | Type | Labels |
|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------| |-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
| `windows_os_info` | Contains full product name & version in labels. Note that the `major_version` for Windows 11 is "10"; a build number greater than 22000 represents Windows 11. | gauge | `product`, `version`, `major_version`, `minor_version`, `build_number` | | `windows_os_hostname` | Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain | gauge | `domain`, `fqdn`, `hostname` |
| `windows_os_paging_limit_bytes` | Total number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files | gauge | None | | `windows_os_info` | Contains full product name & version in labels. Note that the `major_version` for Windows 11 is "10"; a build number greater than 22000 represents Windows 11. | gauge | `product`, `version`, `major_version`, `minor_version`, `build_number` |
| `windows_os_paging_free_bytes` | Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out | gauge | None |
### Example metric ### Example metric

View File

@@ -0,0 +1,38 @@
# pagefile collector
The pagefile collector exposes metrics about the pagefile usage
|||
-|-
Metric name prefix | `pagefile`
Classes | [`Win32_OperatingSystem`](https://msdn.microsoft.com/en-us/library/aa394239)
Enabled by default? | Yes
## Flags
None
## Metrics
| Name | Description | Type | Labels |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------|-------|--------|
| `windows_pagefile_free_bytes` | Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out | gauge | `file` |
| `windows_pagefile_limit_bytes` | Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files | gauge | `file` |
### Example metric
```
# HELP windows_pagefile_free_bytes OperatingSystem.FreeSpaceInPagingFiles
# TYPE windows_pagefile_free_bytes gauge
windows_pagefile_free_bytes{file="C:\\pagefile.sys"} 6.025797632e+09
# HELP windows_pagefile_limit_bytes OperatingSystem.SizeStoredInPagingFiles
# TYPE windows_pagefile_limit_bytes gauge
windows_pagefile_limit_bytes{file="C:\\pagefile.sys"} 6.442450944e+09
```
## Useful queries
_This collector does not yet have useful queries, we would appreciate your help adding them!_
## Alerting examples
_This collector does not yet have alerting examples, we would appreciate your help adding them!_

View File

@@ -35,7 +35,7 @@ metrics.
Enables IIS process name queries. IIS process names are combined with their app pool name to form the `process` label. Enables IIS process name queries. IIS process names are combined with their app pool name to form the `process` label.
Disabled by default, and can be enabled with `--collector.process.iis=true`. Disabled by default, and can be enabled with `--collector.process.iis`. NOTE: Just plain parameter without `true`.
### Example ### Example

View File

@@ -1,12 +1,11 @@
# tcp collector # tcp collector
The tcp collector exposes metrics about the TCP/IPv4 network stack. The tcp collector exposes metrics about the TCP network stack.
||| |||
-|- -|-
Metric name prefix | `tcp` Metric name prefix | `tcp`
Data source | Perflib Data source | Perflib
Classes | [`Win32_PerfRawData_Tcpip_TCPv4`](https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx), Win32_PerfRawData_Tcpip_TCPv6
Enabled by default? | No Enabled by default? | No
## Flags ## Flags
@@ -15,18 +14,18 @@ None
## Metrics ## Metrics
Name | Description | Type | Labels | Name | Description | Type | Labels |
-----|-------------|------|------- |--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
`windows_tcp_connection_failures_total` | Number of times TCP connections have made a direct transition to the CLOSED state from the SYN-SENT state or the SYN-RCVD state, plus the number of times TCP connections have made a direct transition from the SYN-RCVD state to the LISTEN state | counter | af | `windows_tcp_connection_failures_total` | Number of times TCP connections have made a direct transition to the CLOSED state from the SYN-SENT state or the SYN-RCVD state, plus the number of times TCP connections have made a direct transition from the SYN-RCVD state to the LISTEN state | counter | af |
`windows_tcp_connections_active_total` | Number of times TCP connections have made a direct transition from the CLOSED state to the SYN-SENT state.| counter | af | `windows_tcp_connections_active_total` | Number of times TCP connections have made a direct transition from the CLOSED state to the SYN-SENT state. | counter | af |
`windows_tcp_connections_established` | Number of TCP connections for which the current state is either ESTABLISHED or CLOSE-WAIT. | gauge | af | `windows_tcp_connections_established` | Number of TCP connections for which the current state is either ESTABLISHED or CLOSE-WAIT. | gauge | af |
`windows_tcp_connections_passive_total` | Number of times TCP connections have made a direct transition from the LISTEN state to the SYN-RCVD state. | counter | af | `windows_tcp_connections_passive_total` | Number of times TCP connections have made a direct transition from the LISTEN state to the SYN-RCVD state. | counter | af |
`windows_tcp_connections_reset_total` | Connections Reset is the number of times TCP connections have made a direct transition to the CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state. | counter | af | `windows_tcp_connections_reset_total` | Connections Reset is the number of times TCP connections have made a direct transition to the CLOSED state from either the ESTABLISHED state or the CLOSE-WAIT state. | counter | af |
`windows_tcp_segments_total` | Total segments sent or received using the TCP protocol | counter | af | `windows_tcp_segments_total` | Total segments sent or received using the TCP protocol | counter | af |
`windows_tcp_segments_received_total` | Total segments received, including those received in error. This count includes segments received on currently established connections | counter | af | `windows_tcp_segments_received_total` | Total segments received, including those received in error. This count includes segments received on currently established connections | counter | af |
`windows_tcp_segments_retransmitted_total` | Total segments retransmitted. That is, segments transmitted that contain one or more previously transmitted bytes | counter | af | `windows_tcp_segments_retransmitted_total` | Total segments retransmitted. That is, segments transmitted that contain one or more previously transmitted bytes | counter | af |
`windows_tcp_segments_sent_total` | Total segments sent, including those on current connections, but excluding those containing *only* retransmitted bytes | counter | af | `windows_tcp_segments_sent_total` | Total segments sent, including those on current connections, but excluding those containing *only* retransmitted bytes | counter | af |
`windows_tcp_connections_state_count` | Number of TCP connections by state among: CLOSED, LISTENING, SYN_SENT, SYN_RECEIVED, ESTABLISHED, FIN_WAIT1, FIN_WAIT2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT, DELETE_TCB | gauge | af | `windows_tcp_connections_state_count` | Number of TCP connections by state among: CLOSED, LISTENING, SYN_SENT, SYN_RECEIVED, ESTABLISHED, FIN_WAIT1, FIN_WAIT2, CLOSE_WAIT, CLOSING, LAST_ACK, TIME_WAIT, DELETE_TCB | gauge | af |
### Example metric ### Example metric
_This collector does not yet have explained examples, we would appreciate your help adding them!_ _This collector does not yet have explained examples, we would appreciate your help adding them!_

View File

@@ -5,15 +5,19 @@ If the Windows Time Service is stopped after collection has started, collector m
Please note the Time Service perflib counters are only available on [Windows Server 2016 or newer](https://docs.microsoft.com/en-us/windows-server/networking/windows-time-service/windows-server-2016-improvements). Please note the Time Service perflib counters are only available on [Windows Server 2016 or newer](https://docs.microsoft.com/en-us/windows-server/networking/windows-time-service/windows-server-2016-improvements).
| | | | | |
|---------------------|---------| |---------------------|--------|
| Metric name prefix | `time` | | Metric name prefix | `time` |
| Data source | Perflib | | Data source | PDH |
| Enabled by default? | No | | Enabled by default? | No |
## Flags ## Flags
None ### `--collectors.time.enabled`
Comma-separated list of collectors to use, for example: `--collectors.time.enabled=ntp,system_time`.
Matching is case-sensitive.
## Metrics ## Metrics

31
docs/collector.udp.md Normal file
View File

@@ -0,0 +1,31 @@
# udp collector
The udp collector exposes metrics about the UDP network stack.
|||
-|-
Metric name prefix | `udp`
Data source | Perflib
Enabled by default? | No
## Flags
None
## Metrics
| Name | Description | Type | Labels |
|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
| `windows_udp_datagram_datagram_no_port_total` | Number of received UDP datagrams for which there was no application at the destination port | counter | af |
| `windows_udp_datagram_received_errors_total` | Number of received UDP datagrams that could not be delivered for reasons other than the lack of an application at the destination port | counter | af |
| `windows_udp_datagram_received_total` | Number of UDP datagrams segments received | counter | af |
| `windows_udp_datagram_sent_total` | Number of UDP datagrams segments sent | counter | af |
### Example metric
_This collector does not yet have explained examples, we would appreciate your help adding them!_
## Useful queries
_This collector does not yet have any useful queries added, we would appreciate your help adding them!_
## Alerting examples
_This collector does not yet have alerting examples, we would appreciate your help adding them!_

View File

@@ -2,11 +2,11 @@
The vmware collector exposes metrics about a VMware guest VM The vmware collector exposes metrics about a VMware guest VM
||| | | |
-|- |---------------------|----------------------|
Metric name prefix | `vmware` | Metric name prefix | `vmware` |
Classes | `Win32_PerfRawData_vmGuestLib_VMem`, `Win32_PerfRawData_vmGuestLib_VCPU` | Source | Performance counters |
Enabled by default? | No | Enabled by default? | No |
## Flags ## Flags
@@ -14,27 +14,27 @@ None
## Metrics ## Metrics
Name | Description | Type | Labels | Name | Description | Type | Labels |
-----|-------------|------|------- |---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
`windows_vmware_mem_active_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_active_bytes` | The estimated amount of memory the virtual machine is actively using. | gauge | None |
`windows_vmware_mem_ballooned_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_ballooned_bytes` | The amount of memory that has been reclaimed from this virtual machine via the VMware Memory Balloon mechanism. | gauge | None |
`windows_vmware_mem_limit_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_limit_bytes` | The maximum amount of memory that is allowed to the virtual machine. Assigning a Memory Limit ensures that this virtual machine never consumes more than a certain amount of the allowed memory. By limiting the amount of memory consumed, a portion of this shared resource is allowed to other virtual machines. | gauge | None |
`windows_vmware_mem_mapped_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_mapped_bytes` | The mapped memory size of this virtual machine. This is the current total amount of guest memory that is backed by physical memory. Note that this number may include pages of memory shared between multiple virtual machines and thus may be an overestimate of the amount of physical host memory consumed by this virtual machine. | gauge | None |
`windows_vmware_mem_overhead_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_overhead_bytes` | The amount of overhead memory associated with this virtual machine consumed on the host system. | gauge | None |
`windows_vmware_mem_reservation_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_reservation_bytes` | The minimum amount of memory that is guaranteed to the virtual machine. Assigning a Memory Reservation ensures that even as other virtual machines on the same host consume memory, there is still a certain minimum amount for this virtual machine. | gauge | None |
`windows_vmware_mem_shared_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_shared_bytes` | The amount of physical memory associated with this virtual machine that is copy-on-write (COW) shared on the host. | gauge | None |
`windows_vmware_mem_shared_saved_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_shared_saved_bytes` | The estimated amount of physical memory on the host saved from copy-on-write (COW) shared guest physical memory. | gauge | None |
`windows_vmware_mem_shares` | _Not yet documented_ | gauge | None | `windows_vmware_mem_shares` | The number of memory shares allocated to the virtual machine. | gauge | None |
`windows_vmware_mem_swapped_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_swapped_bytes` | The amount of memory associated with this virtual machine that has been swapped by ESX. | gauge | None |
`windows_vmware_mem_target_size_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_target_size_bytes` | Memory Target Size | gauge | None |
`windows_vmware_mem_used_bytes` | _Not yet documented_ | gauge | None | `windows_vmware_mem_used_bytes` | The estimated amount of physical host memory currently consumed for this virtual machines physical memory. | gauge | None |
`windows_vmware_cpu_limit_mhz` | _Not yet documented_ | gauge | None | `windows_vmware_cpu_limit_mhz` | The maximum processing power in MHz allowed to the virtual machine. Assigning a CPU Limit ensures that this virtual machine never consumes more than a certain amount of the available processor power. By limiting the amount of processing power consumed, a portion of the processing power becomes available to other virtual machines. | gauge | None |
`windows_vmware_cpu_reservation_mhz` | _Not yet documented_ | gauge | None | `windows_vmware_cpu_reservation_mhz` | The minimum processing power in MHz available to the virtual machine. Assigning a CPU Reservation ensures that even as other virtual machines on the same host consume shared processing power, there is still a certain minimum amount for this virtual machine. | gauge | None |
`windows_vmware_cpu_shares` | _Not yet documented_ | gauge | None | `windows_vmware_cpu_shares` | The number of CPU shares allocated to the virtual machine. | gauge | None |
`windows_vmware_cpu_stolen_seconds_total` | _Not yet documented_ | counter | None | `windows_vmware_cpu_stolen_seconds_total` | The time that the VM was runnable but not scheduled to run | counter | None |
`windows_vmware_cpu_time_seconds_total` | _Not yet documented_ | counter | None | `windows_vmware_cpu_time_seconds_total` | Current load of the VMs virtual processor | counter | None |
`windows_vmware_effective_vm_speed_mhz` | _Not yet documented_ | gauge | None | `windows_vmware_cpu_effective_vm_speed_mhz` | The effective speed of the VMs virtual CPU | gauge | None |
`windows_vmware_host_processor_speed_mhz` | _Not yet documented_ | gauge | None | `windows_vmware_host_processor_speed_mhz` | Host Processor speed | gauge | None |
### Example metric ### Example metric
_This collector does not yet have explained examples, we would appreciate your help adding them!_ _This collector does not yet have explained examples, we would appreciate your help adding them!_

View File

@@ -28,6 +28,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/httphandler" "github.com/prometheus-community/windows_exporter/internal/httphandler"
"github.com/prometheus-community/windows_exporter/internal/log" "github.com/prometheus-community/windows_exporter/internal/log"
"github.com/prometheus-community/windows_exporter/internal/log/flag" "github.com/prometheus-community/windows_exporter/internal/log/flag"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus-community/windows_exporter/pkg/collector" "github.com/prometheus-community/windows_exporter/pkg/collector"
@@ -96,6 +97,11 @@ func run() int {
"process.priority", "process.priority",
"Priority of the exporter process. Higher priorities may improve exporter responsiveness during periods of system load. Can be one of [\"realtime\", \"high\", \"abovenormal\", \"normal\", \"belownormal\", \"low\"]", "Priority of the exporter process. Higher priorities may improve exporter responsiveness during periods of system load. Can be one of [\"realtime\", \"high\", \"abovenormal\", \"normal\", \"belownormal\", \"low\"]",
).Default("normal").String() ).Default("normal").String()
togglePDH = app.Flag(
"perfcounter.engine",
"EXPERIMENTAL: Performance counter engine to use. Can be one of \"pdh\", \"registry\". PDH is in experimental state. This flag will be removed in 0.31.",
).Default("registry").String()
) )
logConfig := &log.Config{} logConfig := &log.Config{}
@@ -173,6 +179,12 @@ func run() int {
logger.Debug("Logging has Started") logger.Debug("Logging has Started")
if v, ok := os.LookupEnv("WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE"); ok && v == "pdh" || *togglePDH == "pdh" {
logger.Info("Using performance data helper from PHD.dll for performance counter collection. This is in experimental state.")
toggle.PHDEnabled = true
}
if *printCollectors { if *printCollectors {
printCollectorsToStdout() printCollectorsToStdout()
@@ -215,10 +227,6 @@ func run() int {
logger.Info("Enabled collectors: " + strings.Join(enabledCollectorList, ", ")) logger.Info("Enabled collectors: " + strings.Join(enabledCollectorList, ", "))
if utils.PDHEnabled() {
logger.Info("Using performance data helper from PHD.dll for performance counter collection. This is in experimental state.")
}
mux := http.NewServeMux() mux := http.NewServeMux()
mux.Handle("GET /health", httphandler.NewHealthHandler()) mux.Handle("GET /health", httphandler.NewHealthHandler())
mux.Handle("GET /version", httphandler.NewVersionHandler()) mux.Handle("GET /version", httphandler.NewVersionHandler())

2
go.mod
View File

@@ -14,7 +14,7 @@ require (
github.com/prometheus/common v0.60.1 github.com/prometheus/common v0.60.1
github.com/prometheus/exporter-toolkit v0.13.1 github.com/prometheus/exporter-toolkit v0.13.1
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
golang.org/x/sys v0.26.0 golang.org/x/sys v0.27.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )

4
go.sum
View File

@@ -160,8 +160,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/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.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.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=

View File

@@ -11,6 +11,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@@ -63,7 +64,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -75,7 +76,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
requestsPerSecond, requestsPerSecond,
requestProcessingTime, requestProcessingTime,
@@ -183,7 +184,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -14,8 +14,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -96,7 +96,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -108,7 +108,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
adLoginConnectionFailures, adLoginConnectionFailures,
certificateAuthentications, certificateAuthentications,
@@ -426,7 +426,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -12,8 +12,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -81,7 +81,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -93,7 +93,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
asyncCopyReadsTotal, asyncCopyReadsTotal,
asyncDataMapsTotal, asyncDataMapsTotal,
@@ -314,7 +314,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect implements the Collector interface. // Collect implements the Collector interface.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -11,6 +11,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@@ -67,7 +68,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -79,7 +80,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
c1TimeSeconds, c1TimeSeconds,
c2TimeSeconds, c2TimeSeconds,
@@ -108,7 +109,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
var err error var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V1, "Processor Information", perfdata.AllInstances, counters) c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "Processor Information", perfdata.AllInstances, counters)
if err != nil { if err != nil {
return fmt.Errorf("failed to create Processor Information collector: %w", err) return fmt.Errorf("failed to create Processor Information collector: %w", err)
} }
@@ -231,7 +232,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -13,8 +13,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -148,7 +148,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -173,7 +173,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
logger.Info("dfsr collector is in an experimental state! Metrics for this collector have not been tested.") logger.Info("dfsr collector is in an experimental state! Metrics for this collector have not been tested.")
//nolint:nestif //nolint:nestif
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
var err error var err error
if slices.Contains(c.config.CollectorsEnabled, "connection") { if slices.Contains(c.config.CollectorsEnabled, "connection") {
@@ -567,7 +567,7 @@ func (c *Collector) getDFSRChildCollectors(enabledCollectors []string) []dfsrCol
// Collect implements the Collector interface. // Collect implements the Collector interface.
// Sends metric values for each metric to the provided prometheus Metric channel. // Sends metric values for each metric to the provided prometheus Metric channel.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -12,8 +12,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -77,7 +77,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -89,7 +89,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
acksTotal, acksTotal,
activeQueueLength, activeQueueLength,
@@ -281,7 +281,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -12,8 +12,8 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -185,7 +185,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -208,7 +208,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
collectorFuncs := map[string]func() error{ collectorFuncs := map[string]func() error{
adAccessProcesses: c.buildADAccessProcesses, adAccessProcesses: c.buildADAccessProcesses,
transportQueues: c.buildTransportQueues, transportQueues: c.buildTransportQueues,
@@ -283,7 +283,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect collects exchange metrics and sends them to prometheus. // Collect collects exchange metrics and sends them to prometheus.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(ch) return c.collectPDH(ch)
} }

View File

@@ -16,7 +16,7 @@ const (
percentDiskWriteTime = "% Disk Write Time" percentDiskWriteTime = "% Disk Write Time"
percentFreeSpace = "% Free Space" percentFreeSpace = "% Free Space"
percentIdleTime = "% Idle Time" percentIdleTime = "% Idle Time"
SplitIOPerSec = "Split IO/Sec" splitIOPerSec = "Split IO/Sec"
) )
// Win32_PerfRawData_PerfDisk_LogicalDisk docs: // Win32_PerfRawData_PerfDisk_LogicalDisk docs:

View File

@@ -4,7 +4,6 @@ package logical_disk
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"regexp" "regexp"
@@ -17,8 +16,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -130,7 +129,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -142,7 +141,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
currentDiskQueueLength, currentDiskQueueLength,
avgDiskReadQueueLength, avgDiskReadQueueLength,
@@ -156,7 +155,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
percentFreeSpace, percentFreeSpace,
freeSpace, freeSpace,
percentIdleTime, percentIdleTime,
SplitIOPerSec, splitIOPerSec,
avgDiskSecPerRead, avgDiskSecPerRead,
avgDiskSecPerWrite, avgDiskSecPerWrite,
avgDiskSecPerTransfer, avgDiskSecPerTransfer,
@@ -302,7 +301,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(logger, ch) return c.collectPDH(logger, ch)
} }
@@ -329,10 +328,6 @@ func (c *Collector) collectPDH(logger *slog.Logger, ch chan<- prometheus.Metric)
return fmt.Errorf("failed to collect LogicalDisk metrics: %w", err) return fmt.Errorf("failed to collect LogicalDisk metrics: %w", err)
} }
if len(perfData) == 0 {
return errors.New("perflib query for LogicalDisk returned empty result set")
}
for name, volume := range perfData { for name, volume := range perfData {
if name == "_Total" || if name == "_Total" ||
c.config.VolumeExclude.MatchString(name) || c.config.VolumeExclude.MatchString(name) ||
@@ -453,7 +448,7 @@ func (c *Collector) collectPDH(logger *slog.Logger, ch chan<- prometheus.Metric)
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.splitIOs, c.splitIOs,
prometheus.CounterValue, prometheus.CounterValue,
volume[SplitIOPerSec].FirstValue, volume[splitIOPerSec].FirstValue,
name, name,
) )

View File

@@ -16,8 +16,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -94,7 +94,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -106,7 +106,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
availableBytes, availableBytes,
availableKBytes, availableKBytes,
@@ -386,7 +386,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
errs := make([]error, 0, 2) errs := make([]error, 0, 2)
var err error var err error
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
err = c.collectPDH(ch) err = c.collectPDH(ch)
} else { } else {
err = c.collectPerformanceData(ctx, logger, ch) err = c.collectPerformanceData(ctx, logger, ch)

View File

@@ -16,8 +16,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -138,7 +138,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -150,7 +150,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
BytesReceivedPerSec, BytesReceivedPerSec,
BytesSentPerSec, BytesSentPerSec,
@@ -283,7 +283,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
if slices.Contains(c.config.CollectorsEnabled, "metrics") { if slices.Contains(c.config.CollectorsEnabled, "metrics") {
var err error var err error
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
err = c.collectPDH(ch) err = c.collectPDH(ch)
} else { } else {
err = c.collect(ctx, logger, ch) err = c.collect(ctx, logger, ch)

View File

@@ -34,9 +34,14 @@ var ConfigDefaults = Config{}
type Collector struct { type Collector struct {
config Config config Config
hostname *prometheus.Desc hostname *prometheus.Desc
osInformation *prometheus.Desc osInformation *prometheus.Desc
pagingFreeBytes *prometheus.Desc
// pagingFreeBytes
// Deprecated: Use windows_paging_free_bytes instead.
pagingFreeBytes *prometheus.Desc
// pagingLimitBytes
// Deprecated: Use windows_paging_total_bytes instead.
pagingLimitBytes *prometheus.Desc pagingLimitBytes *prometheus.Desc
// users // users
@@ -151,13 +156,13 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
) )
c.pagingLimitBytes = prometheus.NewDesc( c.pagingLimitBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "paging_limit_bytes"), prometheus.BuildFQName(types.Namespace, Name, "paging_limit_bytes"),
"OperatingSystem.SizeStoredInPagingFiles", "Deprecated: Use windows_pagefile_limit_bytes instead.",
nil, nil,
nil, nil,
) )
c.pagingFreeBytes = prometheus.NewDesc( c.pagingFreeBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "paging_free_bytes"), prometheus.BuildFQName(types.Namespace, Name, "paging_free_bytes"),
"OperatingSystem.FreeSpaceInPagingFiles", "Deprecated: Use windows_pagefile_free_bytes instead.",
nil, nil,
nil, nil,
) )

View File

@@ -0,0 +1,5 @@
package pagefile
const (
usage = "% Usage"
)

View File

@@ -0,0 +1,136 @@
//go:build windows
package pagefile
import (
"fmt"
"log/slog"
"os"
"strings"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/psapi"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "pagefile"
type Config struct{}
var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI metrics.
type Collector struct {
config Config
perfDataCollector perfdata.Collector
pagingFreeBytes *prometheus.Desc
pagingLimitBytes *prometheus.Desc
}
func New(config *Config) *Collector {
if config == nil {
config = &ConfigDefaults
}
c := &Collector{
config: *config,
}
return c
}
func NewWithFlags(_ *kingpin.Application) *Collector {
return &Collector{}
}
func (c *Collector) GetName() string {
return Name
}
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{}, nil
}
func (c *Collector) Close(_ *slog.Logger) error {
return nil
}
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{
usage,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "Paging File", perfdata.AllInstances, counters)
if err != nil {
return fmt.Errorf("failed to create Paging File collector: %w", err)
}
c.pagingLimitBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "limit_bytes"),
"Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files",
[]string{"file"},
nil,
)
c.pagingFreeBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "free_bytes"),
"Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out",
[]string{"file"},
nil,
)
return nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
return c.collectPaging(ch)
}
func (c *Collector) collectPaging(ch chan<- prometheus.Metric) error {
data, err := c.perfDataCollector.Collect()
if err != nil {
return fmt.Errorf("failed to collect Paging File metrics: %w", err)
}
gpi, err := psapi.GetPerformanceInfo()
if err != nil {
return err
}
for fileName, pageFile := range data {
fileString := strings.ReplaceAll(fileName, `\??\`, "")
file, err := os.Stat(fileString)
var fileSize float64
// For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting.
if err == nil {
fileSize = float64(file.Size())
}
ch <- prometheus.MustNewConstMetric(
c.pagingFreeBytes,
prometheus.GaugeValue,
fileSize-(pageFile[usage].FirstValue*float64(gpi.PageSize)),
fileString,
)
ch <- prometheus.MustNewConstMetric(
c.pagingLimitBytes,
prometheus.GaugeValue,
fileSize,
fileString,
)
}
return nil
}

View File

@@ -0,0 +1,16 @@
package pagefile_test
import (
"testing"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/testutils"
)
func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, pagefile.Name, pagefile.NewWithFlags)
}
func TestCollector(t *testing.T) {
testutils.TestCollector(t, pagefile.New, nil)
}

View File

@@ -0,0 +1,16 @@
package physical_disk
const (
CurrentDiskQueueLength = "Current Disk Queue Length"
DiskReadBytesPerSec = "Disk Read Bytes/sec"
DiskReadsPerSec = "Disk Reads/sec"
DiskWriteBytesPerSec = "Disk Write Bytes/sec"
DiskWritesPerSec = "Disk Writes/sec"
PercentDiskReadTime = "% Disk Read Time"
PercentDiskWriteTime = "% Disk Write Time"
PercentIdleTime = "% Idle Time"
SplitIOPerSec = "Split IO/Sec"
AvgDiskSecPerRead = "Avg. Disk sec/Read"
AvgDiskSecPerWrite = "Avg. Disk sec/Write"
AvgDiskSecPerTransfer = "Avg. Disk sec/Transfer"
)

View File

@@ -10,8 +10,8 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -32,6 +32,8 @@ var ConfigDefaults = Config{
type Collector struct { type Collector struct {
config Config config Config
perfDataCollector perfdata.Collector
idleTime *prometheus.Desc idleTime *prometheus.Desc
readBytesTotal *prometheus.Desc readBytesTotal *prometheus.Desc
readLatency *prometheus.Desc readLatency *prometheus.Desc
@@ -107,7 +109,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{"PhysicalDisk"}, nil return []string{}, nil
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
@@ -115,6 +117,28 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{
CurrentDiskQueueLength,
DiskReadBytesPerSec,
DiskReadsPerSec,
DiskWriteBytesPerSec,
DiskWritesPerSec,
PercentDiskReadTime,
PercentDiskWriteTime,
PercentIdleTime,
SplitIOPerSec,
AvgDiskSecPerRead,
AvgDiskSecPerWrite,
AvgDiskSecPerTransfer,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "PhysicalDisk", perfdata.AllInstances, counters)
if err != nil {
return fmt.Errorf("failed to create PhysicalDisk collector: %w", err)
}
c.requestsQueued = prometheus.NewDesc( c.requestsQueued = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "requests_queued"), prometheus.BuildFQName(types.Namespace, Name, "requests_queued"),
"The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)", "The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)",
@@ -204,139 +228,111 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) if err := c.collect(ch); err != nil {
if err := c.collect(ctx, logger, ch); err != nil { return fmt.Errorf("failed collecting physical_disk metrics: %w", err)
logger.Error("failed collecting physical_disk metrics",
slog.Any("err", err),
)
return err
} }
return nil return nil
} }
// PhysicalDisk func (c *Collector) collect(ch chan<- prometheus.Metric) error {
// Win32_PerfRawData_PerfDisk_PhysicalDisk docs: perfData, err := c.perfDataCollector.Collect()
// - https://docs.microsoft.com/en-us/previous-versions/aa394308(v=vs.85) - Win32_PerfRawData_PerfDisk_PhysicalDisk class. if err != nil {
type PhysicalDisk struct { return fmt.Errorf("failed to collect PhysicalDisk metrics: %w", err)
Name string
CurrentDiskQueueLength float64 `perflib:"Current Disk Queue Length"`
DiskReadBytesPerSec float64 `perflib:"Disk Read Bytes/sec"`
DiskReadsPerSec float64 `perflib:"Disk Reads/sec"`
DiskWriteBytesPerSec float64 `perflib:"Disk Write Bytes/sec"`
DiskWritesPerSec float64 `perflib:"Disk Writes/sec"`
PercentDiskReadTime float64 `perflib:"% Disk Read Time"`
PercentDiskWriteTime float64 `perflib:"% Disk Write Time"`
PercentIdleTime float64 `perflib:"% Idle Time"`
SplitIOPerSec float64 `perflib:"Split IO/Sec"`
AvgDiskSecPerRead float64 `perflib:"Avg. Disk sec/Read"`
AvgDiskSecPerWrite float64 `perflib:"Avg. Disk sec/Write"`
AvgDiskSecPerTransfer float64 `perflib:"Avg. Disk sec/Transfer"`
}
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
var dst []PhysicalDisk
if err := v1.UnmarshalObject(ctx.PerfObjects["PhysicalDisk"], &dst, logger); err != nil {
return err
} }
for _, disk := range dst { for name, disk := range perfData {
if disk.Name == "_Total" || if c.config.DiskExclude.MatchString(name) ||
c.config.DiskExclude.MatchString(disk.Name) || !c.config.DiskInclude.MatchString(name) {
!c.config.DiskInclude.MatchString(disk.Name) {
continue continue
} }
// Parse physical disk number from disk.Name. Mountpoint information is // Parse physical disk number from disk.Name. Mountpoint information is
// sometimes included, e.g. "1 C:". // sometimes included, e.g. "1 C:".
disk_number, _, _ := strings.Cut(disk.Name, " ") disk_number, _, _ := strings.Cut(name, " ")
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.requestsQueued, c.requestsQueued,
prometheus.GaugeValue, prometheus.GaugeValue,
disk.CurrentDiskQueueLength, disk[CurrentDiskQueueLength].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readBytesTotal, c.readBytesTotal,
prometheus.CounterValue, prometheus.CounterValue,
disk.DiskReadBytesPerSec, disk[DiskReadBytesPerSec].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readsTotal, c.readsTotal,
prometheus.CounterValue, prometheus.CounterValue,
disk.DiskReadsPerSec, disk[DiskReadsPerSec].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.writeBytesTotal, c.writeBytesTotal,
prometheus.CounterValue, prometheus.CounterValue,
disk.DiskWriteBytesPerSec, disk[DiskWriteBytesPerSec].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.writesTotal, c.writesTotal,
prometheus.CounterValue, prometheus.CounterValue,
disk.DiskWritesPerSec, disk[DiskWritesPerSec].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readTime, c.readTime,
prometheus.CounterValue, prometheus.CounterValue,
disk.PercentDiskReadTime, disk[PercentDiskReadTime].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.writeTime, c.writeTime,
prometheus.CounterValue, prometheus.CounterValue,
disk.PercentDiskWriteTime, disk[PercentDiskWriteTime].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.idleTime, c.idleTime,
prometheus.CounterValue, prometheus.CounterValue,
disk.PercentIdleTime, disk[PercentIdleTime].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.splitIOs, c.splitIOs,
prometheus.CounterValue, prometheus.CounterValue,
disk.SplitIOPerSec, disk[SplitIOPerSec].FirstValue,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readLatency, c.readLatency,
prometheus.CounterValue, prometheus.CounterValue,
disk.AvgDiskSecPerRead*perftypes.TicksToSecondScaleFactor, disk[AvgDiskSecPerRead].FirstValue*perftypes.TicksToSecondScaleFactor,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.writeLatency, c.writeLatency,
prometheus.CounterValue, prometheus.CounterValue,
disk.AvgDiskSecPerWrite*perftypes.TicksToSecondScaleFactor, disk[AvgDiskSecPerWrite].FirstValue*perftypes.TicksToSecondScaleFactor,
disk_number, disk_number,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readWriteLatency, c.readWriteLatency,
prometheus.CounterValue, prometheus.CounterValue,
disk.AvgDiskSecPerTransfer*perftypes.TicksToSecondScaleFactor, disk[AvgDiskSecPerTransfer].FirstValue*perftypes.TicksToSecondScaleFactor,
disk_number, disk_number,
) )
} }

View File

@@ -5,6 +5,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk" "github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/testutils" "github.com/prometheus-community/windows_exporter/internal/testutils"
"github.com/prometheus-community/windows_exporter/internal/types"
) )
func BenchmarkCollector(b *testing.B) { func BenchmarkCollector(b *testing.B) {
@@ -12,7 +13,7 @@ func BenchmarkCollector(b *testing.B) {
} }
func TestCollector(t *testing.T) { func TestCollector(t *testing.T) {
t.Skip() testutils.TestCollector(t, physical_disk.New, &physical_disk.Config{
DiskInclude: types.RegExpAny,
testutils.TestCollector(t, physical_disk.New, nil) })
} }

View File

@@ -16,8 +16,8 @@ import (
"github.com/prometheus-community/windows_exporter/internal/perfdata" "github.com/prometheus-community/windows_exporter/internal/perfdata"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
v2 "github.com/prometheus-community/windows_exporter/internal/perfdata/v2" v2 "github.com/prometheus-community/windows_exporter/internal/perfdata/v2"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
@@ -130,7 +130,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return []string{}, nil return []string{}, nil
} }
@@ -156,7 +156,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
c.workerProcessMIQueryQuery = miQuery c.workerProcessMIQueryQuery = miQuery
c.miSession = miSession c.miSession = miSession
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
counters := []string{ counters := []string{
processID, processID,
percentProcessorTime, percentProcessorTime,
@@ -315,7 +315,7 @@ type WorkerProcess struct {
} }
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
if utils.PDHEnabled() { if toggle.IsPDHEnabled() {
return c.collectPDH(logger, ch) return c.collectPDH(logger, ch)
} }

View File

@@ -10,3 +10,7 @@ import (
func BenchmarkCollector(b *testing.B) { func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, service.Name, service.NewWithFlags) testutils.FuncBenchmarkCollector(b, service.Name, service.NewWithFlags)
} }
func TestCollector(t *testing.T) {
testutils.TestCollector(t, service.New, nil)
}

View File

@@ -0,0 +1,11 @@
package system
const (
ContextSwitchesPersec = "Context Switches/sec"
ExceptionDispatchesPersec = "Exception Dispatches/sec"
ProcessorQueueLength = "Processor Queue Length"
SystemCallsPersec = "System Calls/sec"
SystemUpTime = "System Up Time"
Processes = "Processes"
Threads = "Threads"
)

View File

@@ -4,11 +4,13 @@ package system
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -23,6 +25,8 @@ var ConfigDefaults = Config{}
type Collector struct { type Collector struct {
config Config config Config
perfDataCollector perfdata.Collector
contextSwitchesTotal *prometheus.Desc contextSwitchesTotal *prometheus.Desc
exceptionDispatchesTotal *prometheus.Desc exceptionDispatchesTotal *prometheus.Desc
processorQueueLength *prometheus.Desc processorQueueLength *prometheus.Desc
@@ -54,7 +58,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{"System"}, nil return []string{}, nil
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
@@ -62,6 +66,23 @@ func (c *Collector) Close(_ *slog.Logger) error {
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{
ContextSwitchesPersec,
ExceptionDispatchesPersec,
ProcessorQueueLength,
SystemCallsPersec,
SystemUpTime,
Processes,
Threads,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "System", nil, counters)
if err != nil {
return fmt.Errorf("failed to create System collector: %w", err)
}
c.contextSwitchesTotal = prometheus.NewDesc( c.contextSwitchesTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"), prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"),
"Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)", "Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)",
@@ -117,78 +138,59 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) if err := c.collect(ch); err != nil {
if err := c.collect(ctx, logger, ch); err != nil { return fmt.Errorf("failed collecting system metrics: %w", err)
logger.Error("failed collecting system metrics",
slog.Any("err", err),
)
return err
} }
return nil return nil
} }
// Win32_PerfRawData_PerfOS_System docs: func (c *Collector) collect(ch chan<- prometheus.Metric) error {
// - https://web.archive.org/web/20050830140516/http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_perfrawdata_perfos_system.asp perfData, err := c.perfDataCollector.Collect()
type system struct { if err != nil {
ContextSwitchesPersec float64 `perflib:"Context Switches/sec"` return fmt.Errorf("failed to collect System metrics: %w", err)
ExceptionDispatchesPersec float64 `perflib:"Exception Dispatches/sec"`
ProcessorQueueLength float64 `perflib:"Processor Queue Length"`
SystemCallsPersec float64 `perflib:"System Calls/sec"`
SystemUpTime float64 `perflib:"System Up Time"`
Processes float64 `perflib:"Processes"`
Threads float64 `perflib:"Threads"`
}
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
var dst []system
if err := v1.UnmarshalObject(ctx.PerfObjects["System"], &dst, logger); err != nil {
return err
} }
if len(dst) == 0 { data, ok := perfData[perftypes.EmptyInstance]
return errors.New("no data returned from Performance Counter") if !ok {
return errors.New("query for System returned empty result set")
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.contextSwitchesTotal, c.contextSwitchesTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].ContextSwitchesPersec, data[ContextSwitchesPersec].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.exceptionDispatchesTotal, c.exceptionDispatchesTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].ExceptionDispatchesPersec, data[ExceptionDispatchesPersec].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.processorQueueLength, c.processorQueueLength,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].ProcessorQueueLength, data[ProcessorQueueLength].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.processes, c.processes,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].Processes, data[Processes].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.systemCallsTotal, c.systemCallsTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].SystemCallsPersec, data[SystemCallsPersec].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.systemUpTime, c.systemUpTime,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].SystemUpTime, data[SystemUpTime].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.threads, c.threads,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].Threads, data[Threads].FirstValue,
) )
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value. // Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.

View File

@@ -3,6 +3,7 @@
package tcp package tcp
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"slices" "slices"
@@ -97,6 +98,11 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
if slices.Contains(c.config.CollectorsEnabled, "metrics") {
c.perfDataCollector4.Close()
c.perfDataCollector6.Close()
}
return nil return nil
} }
@@ -115,12 +121,12 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
var err error var err error
c.perfDataCollector4, err = perfdata.NewCollector(perfdata.V1, "TCPv4", nil, counters) c.perfDataCollector4, err = perfdata.NewCollector(perfdata.V2, "TCPv4", nil, counters)
if err != nil { if err != nil {
return fmt.Errorf("failed to create TCPv4 collector: %w", err) return fmt.Errorf("failed to create TCPv4 collector: %w", err)
} }
c.perfDataCollector6, err = perfdata.NewCollector(perfdata.V1, "TCPv6", nil, counters) c.perfDataCollector6, err = perfdata.NewCollector(perfdata.V2, "TCPv6", nil, counters)
if err != nil { if err != nil {
return fmt.Errorf("failed to create TCPv6 collector: %w", err) return fmt.Errorf("failed to create TCPv6 collector: %w", err)
} }
@@ -190,30 +196,22 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) errs := make([]error, 0, 2)
if slices.Contains(c.config.CollectorsEnabled, "metrics") { if slices.Contains(c.config.CollectorsEnabled, "metrics") {
if err := c.collect(ch); err != nil { if err := c.collect(ch); err != nil {
logger.Error("failed collecting tcp metrics", errs = append(errs, fmt.Errorf("failed collecting tcp metrics: %w", err))
slog.Any("err", err),
)
return err
} }
} }
if slices.Contains(c.config.CollectorsEnabled, "connections_state") { if slices.Contains(c.config.CollectorsEnabled, "connections_state") {
if err := c.collectConnectionsState(ch); err != nil { if err := c.collectConnectionsState(ch); err != nil {
logger.Error("failed collecting tcp connection state metrics", errs = append(errs, fmt.Errorf("failed collecting tcp connection state metrics: %w", err))
slog.Any("err", err),
)
return err
} }
} }
return nil return errors.Join(errs...)
} }
func (c *Collector) collect(ch chan<- prometheus.Metric) error { func (c *Collector) collect(ch chan<- prometheus.Metric) error {

View File

@@ -0,0 +1,23 @@
package terminal_services
const (
handleCount = "Handle Count"
pageFaultsPersec = "Page Faults/sec"
pageFileBytes = "Page File Bytes"
pageFileBytesPeak = "Page File Bytes Peak"
percentPrivilegedTime = "% Privileged Time"
percentProcessorTime = "% Processor Time"
percentUserTime = "% User Time"
poolNonpagedBytes = "Pool Nonpaged Bytes"
poolPagedBytes = "Pool Paged Bytes"
privateBytes = "Private Bytes"
threadCount = "Thread Count"
virtualBytes = "Virtual Bytes"
virtualBytesPeak = "Virtual Bytes Peak"
workingSet = "Working Set"
workingSetPeak = "Working Set Peak"
successfulConnections = "Successful Connections"
pendingConnections = "Pending Connections"
failedConnections = "Failed Connections"
)

View File

@@ -12,7 +12,8 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32" "github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils" "github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
@@ -32,7 +33,7 @@ type Win32_ServerFeature struct {
ID uint32 ID uint32
} }
func isConnectionBrokerServer(logger *slog.Logger, miSession *mi.Session) bool { func isConnectionBrokerServer(miSession *mi.Session) bool {
var dst []Win32_ServerFeature var dst []Win32_ServerFeature
if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature"))); err != nil { if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature"))); err != nil {
return false return false
@@ -44,8 +45,6 @@ func isConnectionBrokerServer(logger *slog.Logger, miSession *mi.Session) bool {
} }
} }
logger.Debug("host is not a connection broker skipping Connection Broker performance metrics.")
return false return false
} }
@@ -58,6 +57,9 @@ type Collector struct {
connectionBrokerEnabled bool connectionBrokerEnabled bool
perfDataCollectorTerminalServicesSession perfdata.Collector
perfDataCollectorBroker perfdata.Collector
hServer windows.Handle hServer windows.Handle
sessionInfo *prometheus.Desc sessionInfo *prometheus.Desc
@@ -98,10 +100,7 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{ return []string{}, nil
"Terminal Services Session",
"Remote Desktop Connection Broker Counterset",
}, nil
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
@@ -110,6 +109,12 @@ func (c *Collector) Close(_ *slog.Logger) error {
return fmt.Errorf("failed to close WTS server: %w", err) return fmt.Errorf("failed to close WTS server: %w", err)
} }
c.perfDataCollectorTerminalServicesSession.Close()
if c.connectionBrokerEnabled {
c.perfDataCollectorBroker.Close()
}
return nil return nil
} }
@@ -120,7 +125,49 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
c.connectionBrokerEnabled = isConnectionBrokerServer(logger, miSession) counters := []string{
handleCount,
pageFaultsPersec,
pageFileBytes,
pageFileBytesPeak,
percentPrivilegedTime,
percentProcessorTime,
percentUserTime,
poolNonpagedBytes,
poolPagedBytes,
privateBytes,
threadCount,
virtualBytes,
virtualBytesPeak,
workingSet,
workingSetPeak,
}
var err error
c.perfDataCollectorTerminalServicesSession, err = perfdata.NewCollector(perfdata.V2, "Terminal Services Session", perfdata.AllInstances, counters)
if err != nil {
return fmt.Errorf("failed to create Terminal Services Session collector: %w", err)
}
c.connectionBrokerEnabled = isConnectionBrokerServer(miSession)
if c.connectionBrokerEnabled {
counters = []string{
successfulConnections,
pendingConnections,
failedConnections,
}
var err error
c.perfDataCollectorBroker, err = perfdata.NewCollector(perfdata.V2, "Remote Desktop Connection Broker Counterset", perfdata.AllInstances, counters)
if err != nil {
return fmt.Errorf("failed to create Remote Desktop Connection Broker Counterset collector: %w", err)
}
} else {
logger.Debug("host is not a connection broker skipping Connection Broker performance metrics.")
}
c.sessionInfo = prometheus.NewDesc( c.sessionInfo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "session_info"), prometheus.BuildFQName(types.Namespace, Name, "session_info"),
@@ -213,8 +260,6 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
nil, nil,
) )
var err error
c.hServer, err = wtsapi32.WTSOpenServer("") c.hServer, err = wtsapi32.WTSOpenServer("")
if err != nil { if err != nil {
return fmt.Errorf("failed to open WTS server: %w", err) return fmt.Errorf("failed to open WTS server: %w", err)
@@ -225,71 +270,40 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) logger = logger.With(slog.String("collector", Name))
if err := c.collectWTSSessions(logger, ch); err != nil {
logger.Error("failed collecting terminal services session infos",
slog.Any("err", err),
)
return err errs := make([]error, 0, 3)
if err := c.collectWTSSessions(logger, ch); err != nil {
errs = append(errs, fmt.Errorf("failed collecting terminal services session infos: %w", err))
} }
if err := c.collectTSSessionCounters(ctx, logger, ch); err != nil { if err := c.collectTSSessionCounters(ch); err != nil {
logger.Error("failed collecting terminal services session count metrics", errs = append(errs, fmt.Errorf("failed collecting terminal services session count metrics: %w", err))
slog.Any("err", err),
)
return err
} }
// only collect CollectionBrokerPerformance if host is a Connection Broker // only collect CollectionBrokerPerformance if host is a Connection Broker
if c.connectionBrokerEnabled { if c.connectionBrokerEnabled {
if err := c.collectCollectionBrokerPerformanceCounter(ctx, logger, ch); err != nil { if err := c.collectCollectionBrokerPerformanceCounter(ch); err != nil {
logger.Error("failed collecting Connection Broker performance metrics", errs = append(errs, fmt.Errorf("failed collecting Connection Broker performance metrics: %w", err))
slog.Any("err", err),
)
return err
} }
} }
return nil return errors.Join(errs...)
} }
type perflibTerminalServicesSession struct { func (c *Collector) collectTSSessionCounters(ch chan<- prometheus.Metric) error {
Name string perfData, err := c.perfDataCollectorTerminalServicesSession.Collect()
HandleCount float64 `perflib:"Handle Count"`
PageFaultsPersec float64 `perflib:"Page Faults/sec"`
PageFileBytes float64 `perflib:"Page File Bytes"`
PageFileBytesPeak float64 `perflib:"Page File Bytes Peak"`
PercentPrivilegedTime float64 `perflib:"% Privileged Time"`
PercentProcessorTime float64 `perflib:"% Processor Time"`
PercentUserTime float64 `perflib:"% User Time"`
PoolNonpagedBytes float64 `perflib:"Pool Nonpaged Bytes"`
PoolPagedBytes float64 `perflib:"Pool Paged Bytes"`
PrivateBytes float64 `perflib:"Private Bytes"`
ThreadCount float64 `perflib:"Thread Count"`
VirtualBytes float64 `perflib:"Virtual Bytes"`
VirtualBytesPeak float64 `perflib:"Virtual Bytes Peak"`
WorkingSet float64 `perflib:"Working Set"`
WorkingSetPeak float64 `perflib:"Working Set Peak"`
}
func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
dst := make([]perflibTerminalServicesSession, 0)
err := v1.UnmarshalObject(ctx.PerfObjects["Terminal Services Session"], &dst, logger)
if err != nil { if err != nil {
return err return fmt.Errorf("failed to collect Terminal Services Session metrics: %w", err)
} }
names := make(map[string]bool) names := make(map[string]bool)
for _, d := range dst { for name, data := range perfData {
// only connect metrics for remote named sessions // only connect metrics for remote named sessions
n := strings.ToLower(d.Name) n := strings.ToLower(name)
if n == "" || n == "services" || n == "console" { if n == "" || n == "services" || n == "console" {
continue continue
} }
@@ -303,138 +317,130 @@ func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger *s
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.handleCount, c.handleCount,
prometheus.GaugeValue, prometheus.GaugeValue,
d.HandleCount, data[handleCount].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.pageFaultsPerSec, c.pageFaultsPerSec,
prometheus.CounterValue, prometheus.CounterValue,
d.PageFaultsPersec, data[pageFaultsPersec].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.pageFileBytes, c.pageFileBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
d.PageFileBytes, data[pageFileBytes].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.pageFileBytesPeak, c.pageFileBytesPeak,
prometheus.GaugeValue, prometheus.GaugeValue,
d.PageFileBytesPeak, data[pageFileBytesPeak].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.percentCPUTime, c.percentCPUTime,
prometheus.CounterValue, prometheus.CounterValue,
d.PercentPrivilegedTime, data[percentPrivilegedTime].FirstValue,
d.Name, name,
"privileged", "privileged",
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.percentCPUTime, c.percentCPUTime,
prometheus.CounterValue, prometheus.CounterValue,
d.PercentProcessorTime, data[percentProcessorTime].FirstValue,
d.Name, name,
"processor", "processor",
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.percentCPUTime, c.percentCPUTime,
prometheus.CounterValue, prometheus.CounterValue,
d.PercentUserTime, data[percentUserTime].FirstValue,
d.Name, name,
"user", "user",
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.poolNonPagedBytes, c.poolNonPagedBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
d.PoolNonpagedBytes, data[poolNonpagedBytes].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.poolPagedBytes, c.poolPagedBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
d.PoolPagedBytes, data[poolPagedBytes].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.privateBytes, c.privateBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
d.PrivateBytes, data[privateBytes].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.threadCount, c.threadCount,
prometheus.GaugeValue, prometheus.GaugeValue,
d.ThreadCount, data[threadCount].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.virtualBytes, c.virtualBytes,
prometheus.GaugeValue, prometheus.GaugeValue,
d.VirtualBytes, data[virtualBytes].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.virtualBytesPeak, c.virtualBytesPeak,
prometheus.GaugeValue, prometheus.GaugeValue,
d.VirtualBytesPeak, data[virtualBytesPeak].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.workingSet, c.workingSet,
prometheus.GaugeValue, prometheus.GaugeValue,
d.WorkingSet, data[workingSet].FirstValue,
d.Name, name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.workingSetPeak, c.workingSetPeak,
prometheus.GaugeValue, prometheus.GaugeValue,
d.WorkingSetPeak, data[workingSetPeak].FirstValue,
d.Name, name,
) )
} }
return nil return nil
} }
type perflibRemoteDesktopConnectionBrokerCounterset struct { func (c *Collector) collectCollectionBrokerPerformanceCounter(ch chan<- prometheus.Metric) error {
SuccessfulConnections float64 `perflib:"Successful Connections"` perfData, err := c.perfDataCollectorBroker.Collect()
PendingConnections float64 `perflib:"Pending Connections"`
FailedConnections float64 `perflib:"Failed Connections"`
}
func (c *Collector) collectCollectionBrokerPerformanceCounter(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
dst := make([]perflibRemoteDesktopConnectionBrokerCounterset, 0)
err := v1.UnmarshalObject(ctx.PerfObjects["Remote Desktop Connection Broker Counterset"], &dst, logger)
if err != nil { if err != nil {
return err return fmt.Errorf("failed to collect Remote Desktop Connection Broker Counterset metrics: %w", err)
} }
if len(dst) == 0 { data, ok := perfData[perftypes.EmptyInstance]
return errors.New("WMI query returned empty result set") if !ok {
return errors.New("query for Remote Desktop Connection Broker Counterset returned empty result set")
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.connectionBrokerPerformance, c.connectionBrokerPerformance,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].SuccessfulConnections, data[successfulConnections].FirstValue,
"Successful", "Successful",
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.connectionBrokerPerformance, c.connectionBrokerPerformance,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].PendingConnections, data[pendingConnections].FirstValue,
"Pending", "Pending",
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.connectionBrokerPerformance, c.connectionBrokerPerformance,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].FailedConnections, data[failedConnections].FirstValue,
"Failed", "Failed",
) )
@@ -448,6 +454,12 @@ func (c *Collector) collectWTSSessions(logger *slog.Logger, ch chan<- prometheus
} }
for _, session := range sessions { for _, session := range sessions {
// only connect metrics for remote named sessions
n := strings.ReplaceAll(session.SessionName, "#", " ")
if n == "" || n == "Services" || n == "Console" {
continue
}
userName := session.UserName userName := session.UserName
if session.DomainName != "" { if session.DomainName != "" {
userName = fmt.Sprintf("%s\\%s", session.DomainName, session.UserName) userName = fmt.Sprintf("%s\\%s", session.DomainName, session.UserName)
@@ -458,12 +470,11 @@ func (c *Collector) collectWTSSessions(logger *slog.Logger, ch chan<- prometheus
if session.State == stateID { if session.State == stateID {
isState = 1.0 isState = 1.0
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.sessionInfo, c.sessionInfo,
prometheus.GaugeValue, prometheus.GaugeValue,
isState, isState,
strings.ReplaceAll(session.SessionName, "#", " "), n,
userName, userName,
session.HostName, session.HostName,
stateName, stateName,

View File

@@ -0,0 +1,10 @@
package time
const (
ClockFrequencyAdjustmentPPBTotal = "Clock Frequency Adjustment (ppb)"
ComputedTimeOffset = "Computed Time Offset"
NTPClientTimeSourceCount = "NTP Client Time Source Count"
NTPRoundTripDelay = "NTP Roundtrip Delay"
NTPServerIncomingRequestsTotal = "NTP Server Incoming Requests"
NTPServerOutgoingResponsesTotal = "NTP Server Outgoing Responses"
)

View File

@@ -4,28 +4,46 @@ package time
import ( import (
"errors" "errors"
"fmt"
"log/slog" "log/slog"
"slices"
"strings"
"time" "time"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/headers/kernel32" "github.com/prometheus-community/windows_exporter/internal/headers/kernel32"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1" "github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
) )
const Name = "time" const (
Name = "time"
type Config struct{} collectorSystemTime = "system_time"
collectorNTP = "ntp"
)
var ConfigDefaults = Config{} type Config struct {
CollectorsEnabled []string `yaml:"collectors_enabled"`
}
var ConfigDefaults = Config{
CollectorsEnabled: []string{
collectorSystemTime,
collectorNTP,
},
}
// Collector is a Prometheus Collector for Perflib counter metrics. // Collector is a Prometheus Collector for Perflib counter metrics.
type Collector struct { type Collector struct {
config Config config Config
perfDataCollector perfdata.Collector
currentTime *prometheus.Desc currentTime *prometheus.Desc
timezone *prometheus.Desc timezone *prometheus.Desc
clockFrequencyAdjustmentPPBTotal *prometheus.Desc clockFrequencyAdjustmentPPBTotal *prometheus.Desc
@@ -41,6 +59,10 @@ func New(config *Config) *Collector {
config = &ConfigDefaults config = &ConfigDefaults
} }
if config.CollectorsEnabled == nil {
config.CollectorsEnabled = ConfigDefaults.CollectorsEnabled
}
c := &Collector{ c := &Collector{
config: *config, config: *config,
} }
@@ -48,8 +70,26 @@ func New(config *Config) *Collector {
return c return c
} }
func NewWithFlags(_ *kingpin.Application) *Collector { func NewWithFlags(app *kingpin.Application) *Collector {
return &Collector{} c := &Collector{
config: ConfigDefaults,
}
c.config.CollectorsEnabled = make([]string, 0)
var collectorsEnabled string
app.Flag(
"collector.time.enabled",
"Comma-separated list of collectors to use. Defaults to all, if not specified. ntp may not available on all systems.",
).Default(strings.Join(ConfigDefaults.CollectorsEnabled, ",")).StringVar(&collectorsEnabled)
app.Action(func(*kingpin.ParseContext) error {
c.config.CollectorsEnabled = strings.Split(collectorsEnabled, ",")
return nil
})
return c
} }
func (c *Collector) GetName() string { func (c *Collector) GetName() string {
@@ -57,14 +97,40 @@ func (c *Collector) GetName() string {
} }
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) { func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{"Windows Time Service"}, nil return []string{}, nil
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
if slices.Contains(c.config.CollectorsEnabled, collectorNTP) {
c.perfDataCollector.Close()
}
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
for _, collector := range c.config.CollectorsEnabled {
if !slices.Contains([]string{collectorSystemTime, collectorNTP}, collector) {
return fmt.Errorf("unknown collector: %s", collector)
}
}
counters := []string{
ClockFrequencyAdjustmentPPBTotal,
ComputedTimeOffset,
NTPClientTimeSourceCount,
NTPRoundTripDelay,
NTPServerIncomingRequestsTotal,
NTPServerOutgoingResponsesTotal,
}
var err error
c.perfDataCollector, err = perfdata.NewCollector(perfdata.V2, "Windows Time Service", nil, counters)
if err != nil {
return fmt.Errorf("failed to create Windows Time Service collector: %w", err)
}
c.currentTime = prometheus.NewDesc( c.currentTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"), prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"),
"OperatingSystem.LocalDateTime", "OperatingSystem.LocalDateTime",
@@ -119,40 +185,24 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name))
errs := make([]error, 0, 2) errs := make([]error, 0, 2)
if err := c.collectTime(ch); err != nil { if slices.Contains(c.config.CollectorsEnabled, collectorSystemTime) {
logger.Error("failed collecting time metrics", if err := c.collectTime(ch); err != nil {
slog.Any("err", err), errs = append(errs, fmt.Errorf("failed collecting time metrics: %w", err))
) }
errs = append(errs, err)
} }
if err := c.collectNTP(ctx, logger, ch); err != nil { if slices.Contains(c.config.CollectorsEnabled, collectorNTP) {
logger.Error("failed collecting time ntp metrics", if err := c.collectNTP(ch); err != nil {
slog.Any("err", err), errs = append(errs, fmt.Errorf("failed collecting time ntp metrics: %w", err))
) }
errs = append(errs, err)
} }
return errors.Join(errs...) return errors.Join(errs...)
} }
// Perflib "Windows Time Service".
type windowsTime struct {
ClockFrequencyAdjustmentPPBTotal float64 `perflib:"Clock Frequency Adjustment (ppb)"`
ComputedTimeOffset float64 `perflib:"Computed Time Offset"`
NTPClientTimeSourceCount float64 `perflib:"NTP Client Time Source Count"`
NTPRoundTripDelay float64 `perflib:"NTP Roundtrip Delay"`
NTPServerIncomingRequestsTotal float64 `perflib:"NTP Server Incoming Requests"`
NTPServerOutgoingResponsesTotal float64 `perflib:"NTP Server Outgoing Responses"`
}
func (c *Collector) collectTime(ch chan<- prometheus.Metric) error { func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.currentTime, c.currentTime,
@@ -178,48 +228,46 @@ func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
return nil return nil
} }
func (c *Collector) collectNTP(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) collectNTP(ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) perfData, err := c.perfDataCollector.Collect()
if err != nil {
var dst []windowsTime // Single-instance class, array is required but will have single entry. return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
if err := v1.UnmarshalObject(ctx.PerfObjects["Windows Time Service"], &dst, logger); err != nil {
return err
} }
if len(dst) == 0 { data, ok := perfData[perftypes.EmptyInstance]
return errors.New("no data returned for Windows Time Service") if !ok {
return errors.New("query for Windows Time Service returned empty result set")
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.clockFrequencyAdjustmentPPBTotal, c.clockFrequencyAdjustmentPPBTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].ClockFrequencyAdjustmentPPBTotal, data[ClockFrequencyAdjustmentPPBTotal].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.computedTimeOffset, c.computedTimeOffset,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].ComputedTimeOffset/1000000, // microseconds -> seconds data[ComputedTimeOffset].FirstValue/1000000, // microseconds -> seconds
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ntpClientTimeSourceCount, c.ntpClientTimeSourceCount,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].NTPClientTimeSourceCount, data[NTPClientTimeSourceCount].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ntpRoundTripDelay, c.ntpRoundTripDelay,
prometheus.GaugeValue, prometheus.GaugeValue,
dst[0].NTPRoundTripDelay/1000000, // microseconds -> seconds data[NTPRoundTripDelay].FirstValue/1000000, // microseconds -> seconds
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ntpServerIncomingRequestsTotal, c.ntpServerIncomingRequestsTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].NTPServerIncomingRequestsTotal, data[NTPServerIncomingRequestsTotal].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.ntpServerOutgoingResponsesTotal, c.ntpServerOutgoingResponsesTotal,
prometheus.CounterValue, prometheus.CounterValue,
dst[0].NTPServerOutgoingResponsesTotal, data[NTPServerOutgoingResponsesTotal].FirstValue,
) )
return nil return nil

View File

@@ -10,3 +10,7 @@ import (
func BenchmarkCollector(b *testing.B) { func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, time.Name, time.NewWithFlags) testutils.FuncBenchmarkCollector(b, time.Name, time.NewWithFlags)
} }
func TestCollector(t *testing.T) {
testutils.TestCollector(t, time.New, nil)
}

View File

@@ -0,0 +1,15 @@
package udp
// The TCPv6 performance object uses the same fields.
// https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.tcpstate?view=net-8.0.
const (
datagramsNoPortPerSec = "Datagrams No Port/sec"
datagramsReceivedPerSec = "Datagrams Received/sec"
datagramsReceivedErrors = "Datagrams Received Errors"
datagramsSentPerSec = "Datagrams Sent/sec"
)
// Datagrams No Port/sec is the rate of received UDP datagrams for which there was no application at the destination port.
// Datagrams Received Errors is the number of received UDP datagrams that could not be delivered for reasons other than the lack of an application at the destination port.
// Datagrams Received/sec is the rate at which UDP datagrams are delivered to UDP users.
// Datagrams Sent/sec is the rate at which UDP datagrams are sent from the entity.

View File

@@ -0,0 +1,168 @@
//go:build windows
package udp
import (
"fmt"
"log/slog"
"github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus/client_golang/prometheus"
)
const Name = "udp"
type Config struct{}
var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_Tcpip_TCPv{4,6} metrics.
type Collector struct {
config Config
perfDataCollector4 perfdata.Collector
perfDataCollector6 perfdata.Collector
datagramsNoPortTotal *prometheus.Desc
datagramsReceivedTotal *prometheus.Desc
datagramsReceivedErrorsTotal *prometheus.Desc
datagramsSentTotal *prometheus.Desc
}
func New(config *Config) *Collector {
if config == nil {
config = &ConfigDefaults
}
c := &Collector{
config: *config,
}
return c
}
func NewWithFlags(_ *kingpin.Application) *Collector {
c := &Collector{
config: ConfigDefaults,
}
return c
}
func (c *Collector) GetName() string {
return Name
}
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
return []string{}, nil
}
func (c *Collector) Close(_ *slog.Logger) error {
c.perfDataCollector4.Close()
c.perfDataCollector6.Close()
return nil
}
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
counters := []string{
datagramsNoPortPerSec,
datagramsReceivedPerSec,
datagramsReceivedErrors,
datagramsSentPerSec,
}
var err error
c.perfDataCollector4, err = perfdata.NewCollector(perfdata.V2, "UDPv4", nil, counters)
if err != nil {
return fmt.Errorf("failed to create UDPv4 collector: %w", err)
}
c.perfDataCollector6, err = perfdata.NewCollector(perfdata.V2, "UDPv6", nil, counters)
if err != nil {
return fmt.Errorf("failed to create UDPv6 collector: %w", err)
}
c.datagramsNoPortTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "datagram_no_port_total"),
"Number of received UDP datagrams for which there was no application at the destination port",
[]string{"af"},
nil,
)
c.datagramsReceivedTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "datagram_received_total"),
"UDP datagrams are delivered to UDP users",
[]string{"af"},
nil,
)
c.datagramsReceivedErrorsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "datagram_received_errors_total"),
"Number of received UDP datagrams that could not be delivered for reasons other than the lack of an application at the destination port",
[]string{"af"},
nil,
)
c.datagramsSentTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "datagram_sent_total"),
"UDP datagrams are sent from the entity",
[]string{"af"},
nil,
)
return nil
}
// Collect sends the metric values for each metric
// to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
return c.collect(ch)
}
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
data, err := c.perfDataCollector4.Collect()
if err != nil {
return fmt.Errorf("failed to collect UDPv4 metrics: %w", err)
}
c.writeUDPCounters(ch, data[perftypes.EmptyInstance], []string{"ipv4"})
data, err = c.perfDataCollector6.Collect()
if err != nil {
return fmt.Errorf("failed to collect UDPv6 metrics: %w", err)
}
c.writeUDPCounters(ch, data[perftypes.EmptyInstance], []string{"ipv6"})
return nil
}
func (c *Collector) writeUDPCounters(ch chan<- prometheus.Metric, metrics map[string]perftypes.CounterValues, labels []string) {
ch <- prometheus.MustNewConstMetric(
c.datagramsNoPortTotal,
prometheus.CounterValue,
metrics[datagramsNoPortPerSec].FirstValue,
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.datagramsReceivedErrorsTotal,
prometheus.CounterValue,
metrics[datagramsReceivedErrors].FirstValue,
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.datagramsReceivedTotal,
prometheus.GaugeValue,
metrics[datagramsReceivedPerSec].FirstValue,
labels...,
)
ch <- prometheus.MustNewConstMetric(
c.datagramsSentTotal,
prometheus.CounterValue,
metrics[datagramsSentPerSec].FirstValue,
labels...,
)
}

View File

@@ -0,0 +1,16 @@
package udp_test
import (
"testing"
"github.com/prometheus-community/windows_exporter/internal/collector/udp"
"github.com/prometheus-community/windows_exporter/internal/testutils"
)
func BenchmarkCollector(b *testing.B) {
testutils.FuncBenchmarkCollector(b, udp.Name, udp.NewWithFlags)
}
func TestCollector(t *testing.T) {
testutils.TestCollector(t, udp.New, nil)
}

View File

@@ -0,0 +1,24 @@
package vmware
const (
couEffectiveVMSpeedMHz = "Effective VM Speed in MHz" // \VM Processor(*)\Effective VM Speed in MHz
cpuHostProcessorSpeedMHz = "Host processor speed in MHz" // \VM Processor(*)\Host processor speed in MHz
cpuLimitMHz = "Limit in MHz" // \VM Processor(*)\Limit in MHz
cpuReservationMHz = "Reservation in MHz" // \VM Processor(*)\Reservation in MHz
cpuShares = "Shares" // \VM Processor(*)\Shares
cpuStolenMs = "CPU stolen time" // \VM Processor(*)\CPU stolen time
cpuTimePercents = "% Processor Time" // \VM Processor(*)\% Processor Time
memActiveMB = "MemActiveMB" // \VM Memory\Memory Active in MB
memBalloonedMB = "MemBalloonedMB" // \VM Memory\Memory Ballooned in MB
memLimitMB = "MemLimitMB" // \VM Memory\Memory Limit in MB
memMappedMB = "MemMappedMB" // \VM Memory\Memory Mapped in MB
memOverheadMB = "MemOverheadMB" // \VM Memory\Memory Overhead in MB
memReservationMB = "MemReservationMB" // \VM Memory\Memory Reservation in MB
memSharedMB = "MemSharedMB" // \VM Memory\Memory Shared in MB
memSharedSavedMB = "MemSharedSavedMB" // \VM Memory\Memory Shared Saved in MB
memShares = "MemShares" // \VM Memory\Memory Shares
memSwappedMB = "MemSwappedMB" // \VM Memory\Memory Swapped in MB
memTargetSizeMB = "MemTargetSizeMB" // \VM Memory\Memory Target Size
memUsedMB = "MemUsedMB" // \VM Memory\Memory Used in MB
)

View File

@@ -9,8 +9,10 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes" "github.com/prometheus-community/windows_exporter/internal/perfdata/perftypes"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
@@ -22,10 +24,9 @@ var ConfigDefaults = Config{}
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_vmGuestLib_VMem/Win32_PerfRawData_vmGuestLib_VCPU metrics.
type Collector struct { type Collector struct {
config Config config Config
miSession *mi.Session perfDataCollectorCPU perfdata.Collector
miQueryCPU mi.Query perfDataCollectorMemory perfdata.Collector
miQueryMem mi.Query
memActive *prometheus.Desc memActive *prometheus.Desc
memBallooned *prometheus.Desc memBallooned *prometheus.Desc
@@ -40,13 +41,13 @@ type Collector struct {
memTargetSize *prometheus.Desc memTargetSize *prometheus.Desc
memUsed *prometheus.Desc memUsed *prometheus.Desc
cpuLimitMHz *prometheus.Desc cpuLimitMHz *prometheus.Desc
cpuReservationMHz *prometheus.Desc cpuReservationMHz *prometheus.Desc
cpuShares *prometheus.Desc cpuShares *prometheus.Desc
cpuStolenTotal *prometheus.Desc cpuStolenTotal *prometheus.Desc
cpuTimeTotal *prometheus.Desc cpuTimeTotal *prometheus.Desc
effectiveVMSpeedMHz *prometheus.Desc cpuEffectiveVMSpeedMHz *prometheus.Desc
hostProcessorSpeedMHz *prometheus.Desc hostProcessorSpeedMHz *prometheus.Desc
} }
func New(config *Config) *Collector { func New(config *Config) *Collector {
@@ -74,141 +75,162 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
} }
func (c *Collector) Close(_ *slog.Logger) error { func (c *Collector) Close(_ *slog.Logger) error {
c.perfDataCollectorCPU.Close()
c.perfDataCollectorMemory.Close()
return nil return nil
} }
func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
if miSession == nil { counters := []string{
return errors.New("miSession is nil") cpuLimitMHz,
cpuReservationMHz,
cpuShares,
cpuStolenMs,
cpuTimePercents,
couEffectiveVMSpeedMHz,
cpuHostProcessorSpeedMHz,
} }
miQuery, err := mi.NewQuery("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU") var err error
c.perfDataCollectorCPU, err = perfdata.NewCollector(perfdata.V2, "VM Processor", perftypes.TotalInstance, counters)
if err != nil { if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err) return fmt.Errorf("failed to create VM Processor collector: %w", err)
} }
c.miQueryCPU = miQuery
miQuery, err = mi.NewQuery("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem")
if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err)
}
c.miQueryMem = miQuery
c.miSession = miSession
c.memActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"),
"(MemActiveMB)",
nil,
nil,
)
c.memBallooned = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_ballooned_bytes"),
"(MemBalloonedMB)",
nil,
nil,
)
c.memLimit = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_limit_bytes"),
"(MemLimitMB)",
nil,
nil,
)
c.memMapped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_mapped_bytes"),
"(MemMappedMB)",
nil,
nil,
)
c.memOverhead = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_overhead_bytes"),
"(MemOverheadMB)",
nil,
nil,
)
c.memReservation = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_reservation_bytes"),
"(MemReservationMB)",
nil,
nil,
)
c.memShared = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shared_bytes"),
"(MemSharedMB)",
nil,
nil,
)
c.memSharedSaved = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shared_saved_bytes"),
"(MemSharedSavedMB)",
nil,
nil,
)
c.memShares = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shares"),
"(MemShares)",
nil,
nil,
)
c.memSwapped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_swapped_bytes"),
"(MemSwappedMB)",
nil,
nil,
)
c.memTargetSize = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_target_size_bytes"),
"(MemTargetSizeMB)",
nil,
nil,
)
c.memUsed = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_used_bytes"),
"(MemUsedMB)",
nil,
nil,
)
c.cpuLimitMHz = prometheus.NewDesc( c.cpuLimitMHz = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cpu_limit_mhz"), prometheus.BuildFQName(types.Namespace, Name, "cpu_limit_mhz"),
"(CpuLimitMHz)", "The maximum processing power in MHz allowed to the virtual machine. Assigning a CPU Limit ensures that this virtual machine never consumes more than a certain amount of the available processor power. By limiting the amount of processing power consumed, a portion of the processing power becomes available to other virtual machines.",
nil, nil,
nil, nil,
) )
c.cpuReservationMHz = prometheus.NewDesc( c.cpuReservationMHz = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cpu_reservation_mhz"), prometheus.BuildFQName(types.Namespace, Name, "cpu_reservation_mhz"),
"(CpuReservationMHz)", "The minimum processing power in MHz available to the virtual machine. Assigning a CPU Reservation ensures that even as other virtual machines on the same host consume shared processing power, there is still a certain minimum amount for this virtual machine.",
nil, nil,
nil, nil,
) )
c.cpuShares = prometheus.NewDesc( c.cpuShares = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cpu_shares"), prometheus.BuildFQName(types.Namespace, Name, "cpu_shares"),
"(CpuShares)", "The number of CPU shares allocated to the virtual machine.",
nil, nil,
nil, nil,
) )
c.cpuStolenTotal = prometheus.NewDesc( c.cpuStolenTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cpu_stolen_seconds_total"), prometheus.BuildFQName(types.Namespace, Name, "cpu_stolen_seconds_total"),
"(CpuStolenMs)", "The time that the VM was runnable but not scheduled to run.",
nil, nil,
nil, nil,
) )
c.cpuTimeTotal = prometheus.NewDesc( c.cpuTimeTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "cpu_time_seconds_total"), prometheus.BuildFQName(types.Namespace, Name, "cpu_time_seconds_total"),
"(CpuTimePercents)", "Current load of the VMs virtual processor",
nil, nil,
nil, nil,
) )
c.effectiveVMSpeedMHz = prometheus.NewDesc( c.cpuEffectiveVMSpeedMHz = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "effective_vm_speed_mhz"), prometheus.BuildFQName(types.Namespace, Name, "cpu_effective_vm_speed_mhz_total"),
"(EffectiveVMSpeedMHz)", "The effective speed of the VMs virtual CPU",
nil, nil,
nil, nil,
) )
c.hostProcessorSpeedMHz = prometheus.NewDesc( c.hostProcessorSpeedMHz = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "host_processor_speed_mhz"), prometheus.BuildFQName(types.Namespace, Name, "host_processor_speed_mhz"),
"(HostProcessorSpeedMHz)", "Host Processor speed",
nil,
nil,
)
counters = []string{
memActiveMB,
memBalloonedMB,
memLimitMB,
memMappedMB,
memOverheadMB,
memReservationMB,
memSharedMB,
memSharedSavedMB,
memShares,
memSwappedMB,
memTargetSizeMB,
memUsedMB,
}
c.perfDataCollectorMemory, err = perfdata.NewCollector(perfdata.V2, "VM Memory", nil, counters)
if err != nil {
return fmt.Errorf("failed to create VM Memory collector: %w", err)
}
c.memActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_active_bytes"),
"The estimated amount of memory the virtual machine is actively using.",
nil,
nil,
)
c.memBallooned = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_ballooned_bytes"),
"The amount of memory that has been reclaimed from this virtual machine via the VMware Memory Balloon mechanism.",
nil,
nil,
)
c.memLimit = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_limit_bytes"),
"The maximum amount of memory that is allowed to the virtual machine. Assigning a Memory Limit ensures that this virtual machine never consumes more than a certain amount of the allowed memory. By limiting the amount of memory consumed, a portion of this shared resource is allowed to other virtual machines.",
nil,
nil,
)
c.memMapped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_mapped_bytes"),
"The mapped memory size of this virtual machine. This is the current total amount of guest memory that is backed by physical memory. Note that this number may include pages of memory shared between multiple virtual machines and thus may be an overestimate of the amount of physical host memory consumed by this virtual machine.",
nil,
nil,
)
c.memOverhead = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_overhead_bytes"),
"The amount of overhead memory associated with this virtual machine consumed on the host system.",
nil,
nil,
)
c.memReservation = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_reservation_bytes"),
"The minimum amount of memory that is guaranteed to the virtual machine. Assigning a Memory Reservation ensures that even as other virtual machines on the same host consume memory, there is still a certain minimum amount for this virtual machine.",
nil,
nil,
)
c.memShared = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shared_bytes"),
"The amount of physical memory associated with this virtual machine that is copy-on-write (COW) shared on the host.",
nil,
nil,
)
c.memSharedSaved = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shared_saved_bytes"),
"The estimated amount of physical memory on the host saved from copy-on-write (COW) shared guest physical memory.",
nil,
nil,
)
c.memShares = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_shares"),
"The number of memory shares allocated to the virtual machine.",
nil,
nil,
)
c.memSwapped = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_swapped_bytes"),
"The amount of memory associated with this virtual machine that has been swapped by ESX.",
nil,
nil,
)
c.memTargetSize = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_target_size_bytes"),
"Memory Target Size.",
nil,
nil,
)
c.memUsed = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "mem_used_bytes"),
"The estimated amount of physical host memory currently consumed for this virtual machines physical memory.",
nil, nil,
nil, nil,
) )
@@ -218,192 +240,157 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error { func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
logger = logger.With(slog.String("collector", Name)) errs := make([]error, 0, 2)
if err := c.collectMem(ch); err != nil {
logger.Error("failed collecting vmware memory metrics",
slog.Any("err", err),
)
return err
}
if err := c.collectCpu(ch); err != nil { if err := c.collectCpu(ch); err != nil {
logger.Error("failed collecting vmware cpu metrics", errs = append(errs, fmt.Errorf("failed collecting vmware cpu metrics: %w", err))
slog.Any("err", err),
)
return err
} }
return nil if err := c.collectMem(ch); err != nil {
} errs = append(errs, fmt.Errorf("failed collecting vmware memory metrics: %w", err))
}
type Win32_PerfRawData_vmGuestLib_VMem struct { return errors.Join(errs...)
MemActiveMB uint64 `mi:"MemActiveMB"`
MemBalloonedMB uint64 `mi:"MemBalloonedMB"`
MemLimitMB uint64 `mi:"MemLimitMB"`
MemMappedMB uint64 `mi:"MemMappedMB"`
MemOverheadMB uint64 `mi:"MemOverheadMB"`
MemReservationMB uint64 `mi:"MemReservationMB"`
MemSharedMB uint64 `mi:"MemSharedMB"`
MemSharedSavedMB uint64 `mi:"MemSharedSavedMB"`
MemShares uint64 `mi:"MemShares"`
MemSwappedMB uint64 `mi:"MemSwappedMB"`
MemTargetSizeMB uint64 `mi:"MemTargetSizeMB"`
MemUsedMB uint64 `mi:"MemUsedMB"`
}
type Win32_PerfRawData_vmGuestLib_VCPU struct {
CpuLimitMHz uint64 `mi:"CpuLimitMHz"`
CpuReservationMHz uint64 `mi:"CpuReservationMHz"`
CpuShares uint64 `mi:"CpuShares"`
CpuStolenMs uint64 `mi:"CpuStolenMs"`
CpuTimePercents uint64 `mi:"CpuTimePercents"`
EffectiveVMSpeedMHz uint64 `mi:"EffectiveVMSpeedMHz"`
HostProcessorSpeedMHz uint64 `mi:"HostProcessorSpeedMHz"`
} }
func (c *Collector) collectMem(ch chan<- prometheus.Metric) error { func (c *Collector) collectMem(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_vmGuestLib_VMem perfData, err := c.perfDataCollectorMemory.Collect()
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryMem); err != nil { if err != nil {
return fmt.Errorf("WMI query failed: %w", err) return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
} }
if len(dst) == 0 { data, ok := perfData[perftypes.EmptyInstance]
return errors.New("WMI query returned empty result set") if !ok {
return errors.New("query for VM Memory returned empty result set")
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memActive, c.memActive,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemActiveMB), utils.MBToBytes(data[memActiveMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memBallooned, c.memBallooned,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemBalloonedMB), utils.MBToBytes(data[memBalloonedMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memLimit, c.memLimit,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemLimitMB), utils.MBToBytes(data[memLimitMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memMapped, c.memMapped,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemMappedMB), utils.MBToBytes(data[memMappedMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memOverhead, c.memOverhead,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemOverheadMB), utils.MBToBytes(data[memOverheadMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memReservation, c.memReservation,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemReservationMB), utils.MBToBytes(data[memReservationMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memShared, c.memShared,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemSharedMB), utils.MBToBytes(data[memSharedMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memSharedSaved, c.memSharedSaved,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemSharedSavedMB), utils.MBToBytes(data[memSharedSavedMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memShares, c.memShares,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].MemShares), data[memShares].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memSwapped, c.memSwapped,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemSwappedMB), utils.MBToBytes(data[memSwappedMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memTargetSize, c.memTargetSize,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemTargetSizeMB), utils.MBToBytes(data[memTargetSizeMB].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.memUsed, c.memUsed,
prometheus.GaugeValue, prometheus.GaugeValue,
mbToBytes(dst[0].MemUsedMB), utils.MBToBytes(data[memUsedMB].FirstValue),
) )
return nil return nil
} }
// mbToBytes moved to utils package
func mbToBytes(mb uint64) float64 {
return float64(mb * 1024 * 1024)
}
func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error { func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error {
var dst []Win32_PerfRawData_vmGuestLib_VCPU perfData, err := c.perfDataCollectorCPU.Collect()
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryCPU); err != nil { if err != nil {
return fmt.Errorf("WMI query failed: %w", err) return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
} }
if len(dst) == 0 { data, ok := perfData["_Total"]
return errors.New("WMI query returned empty result set") if !ok {
return errors.New("query for VM CPU returned empty result set")
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.cpuLimitMHz, c.cpuLimitMHz,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].CpuLimitMHz), data[cpuLimitMHz].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.cpuReservationMHz, c.cpuReservationMHz,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].CpuReservationMHz), data[cpuReservationMHz].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.cpuShares, c.cpuShares,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].CpuShares), data[cpuShares].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.cpuStolenTotal, c.cpuStolenTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].CpuStolenMs)*perftypes.TicksToSecondScaleFactor, utils.MilliSecToSec(data[cpuStolenMs].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.cpuTimeTotal, c.cpuTimeTotal,
prometheus.CounterValue, prometheus.CounterValue,
float64(dst[0].CpuTimePercents)*perftypes.TicksToSecondScaleFactor, utils.MilliSecToSec(data[cpuTimePercents].FirstValue),
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.effectiveVMSpeedMHz, c.cpuEffectiveVMSpeedMHz,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].EffectiveVMSpeedMHz), data[couEffectiveVMSpeedMHz].FirstValue,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.hostProcessorSpeedMHz, c.hostProcessorSpeedMHz,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(dst[0].HostProcessorSpeedMHz), data[cpuHostProcessorSpeedMHz].FirstValue,
) )
return nil return nil

View File

@@ -1,6 +1,7 @@
package wtsapi32 package wtsapi32
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"unsafe" "unsafe"
@@ -129,7 +130,7 @@ func WTSOpenServer(server string) (windows.Handle, error) {
func WTSCloseServer(server windows.Handle) error { func WTSCloseServer(server windows.Handle) error {
r1, _, err := procWTSCloseServer.Call(uintptr(server)) r1, _, err := procWTSCloseServer.Call(uintptr(server))
if r1 != 1 { if r1 != 1 && !errors.Is(err, windows.ERROR_SUCCESS) {
return fmt.Errorf("failed to close server: %w", err) return fmt.Errorf("failed to close server: %w", err)
} }
@@ -170,8 +171,7 @@ func WTSEnumerateSessionsEx(server windows.Handle, logger *slog.Logger) ([]WTSSe
if sessionInfoPointer != 0 { if sessionInfoPointer != 0 {
defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) { defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) {
err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries) if err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries); err != nil {
if err != nil {
logger.Warn("failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err)) logger.Warn("failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err))
} }
}(WTSTypeSessionInfoLevel1, sessionInfoPointer, count) }(WTSTypeSessionInfoLevel1, sessionInfoPointer, count)

View File

@@ -5,8 +5,10 @@ package mi
import ( import (
"errors" "errors"
"fmt" "fmt"
"math"
"reflect" "reflect"
"sync" "sync"
"time"
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@@ -14,6 +16,10 @@ import (
// We have to registry a global callback function, since the amount of callbacks is limited. // We have to registry a global callback function, since the amount of callbacks is limited.
var operationUnmarshalCallbacksInstanceResult = sync.OnceValue[uintptr](func() uintptr { var operationUnmarshalCallbacksInstanceResult = sync.OnceValue[uintptr](func() uintptr {
// Workaround for a deadlock issue in go.
// Ref: https://github.com/golang/go/issues/55015
go time.Sleep(time.Duration(math.MaxInt64))
return windows.NewCallback(func( return windows.NewCallback(func(
operation *Operation, operation *Operation,
callbacks *OperationUnmarshalCallbacks, callbacks *OperationUnmarshalCallbacks,

View File

@@ -212,9 +212,16 @@ func (s *Session) QueryUnmarshal(dst any,
errs := make([]error, 0) errs := make([]error, 0)
for err := range errCh { // We need an active go routine to prevent a
if err != nil { // fatal error: all goroutines are asleep - deadlock!
// ref: https://github.com/golang/go/issues/55015
// go time.Sleep(5 * time.Second)
for {
if err, ok := <-errCh; err != nil {
errs = append(errs, err) errs = append(errs, err)
} else if !ok {
break
} }
} }

View File

@@ -4,8 +4,8 @@ import "github.com/prometheus/client_golang/prometheus"
// Conversion factors. // Conversion factors.
const ( const (
TicksToSecondScaleFactor = 1 / 1e7 TicksToSecondScaleFactor = 1 / 1e7
WindowsEpoch = 116444736000000000 WindowsEpoch int64 = 116444736000000000
) )
// Based on https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go // Based on https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go

View File

@@ -4,6 +4,8 @@ import "github.com/prometheus/client_golang/prometheus"
const EmptyInstance = "------" const EmptyInstance = "------"
var TotalInstance = []string{"_Total"}
type CounterValues struct { type CounterValues struct {
Type prometheus.ValueType Type prometheus.ValueType
FirstValue float64 FirstValue float64

View File

@@ -5,6 +5,7 @@ package v2
import ( import (
"errors" "errors"
"fmt" "fmt"
"slices"
"strings" "strings"
"unsafe" "unsafe"
@@ -14,9 +15,10 @@ import (
) )
type Collector struct { type Collector struct {
object string object string
counters map[string]Counter counters map[string]Counter
handle pdhQueryHandle handle pdhQueryHandle
totalCounterRequested bool
} }
type Counter struct { type Counter struct {
@@ -24,7 +26,7 @@ type Counter struct {
Desc string Desc string
Instances map[string]pdhCounterHandle Instances map[string]pdhCounterHandle
Type uint32 Type uint32
Frequency float64 Frequency int64
} }
func NewCollector(object string, instances []string, counters []string) (*Collector, error) { func NewCollector(object string, instances []string, counters []string) (*Collector, error) {
@@ -39,9 +41,10 @@ func NewCollector(object string, instances []string, counters []string) (*Collec
} }
collector := &Collector{ collector := &Collector{
object: object, object: object,
counters: make(map[string]Counter, len(counters)), counters: make(map[string]Counter, len(counters)),
handle: handle, handle: handle,
totalCounterRequested: slices.Contains(instances, "_Total"),
} }
for _, counterName := range counters { for _, counterName := range counters {
@@ -67,30 +70,30 @@ func NewCollector(object string, instances []string, counters []string) (*Collec
counter.Instances[instance] = counterHandle counter.Instances[instance] = counterHandle
if counter.Type == 0 { if counter.Type != 0 {
// Get the info with the current buffer size continue
bufLen := uint32(0) }
if ret := PdhGetCounterInfo(counterHandle, 1, &bufLen, nil); ret != PdhMoreData { // Get the info with the current buffer size
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret)) bufLen := uint32(0)
}
buf := make([]byte, bufLen) if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, nil); ret != PdhMoreData {
if ret := PdhGetCounterInfo(counterHandle, 1, &bufLen, &buf[0]); ret != ErrorSuccess { return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret)) }
}
ci := (*PdhCounterInfo)(unsafe.Pointer(&buf[0])) buf := make([]byte, bufLen)
counter.Type = ci.DwType if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, &buf[0]); ret != ErrorSuccess {
counter.Desc = windows.UTF16PtrToString(ci.SzExplainText) return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
}
frequency := float64(0) ci := (*PdhCounterInfo)(unsafe.Pointer(&buf[0]))
counter.Type = ci.DwType
counter.Desc = windows.UTF16PtrToString(ci.SzExplainText)
if ret := PdhGetCounterTimeBase(counterHandle, &frequency); ret != ErrorSuccess { if counter.Type == perftypes.PERF_ELAPSED_TIME {
if ret := PdhGetCounterTimeBase(counterHandle, &counter.Frequency); ret != ErrorSuccess {
return nil, fmt.Errorf("PdhGetCounterTimeBase: %w", NewPdhError(ret)) return nil, fmt.Errorf("PdhGetCounterTimeBase: %w", NewPdhError(ret))
} }
counter.Frequency = frequency
} }
} }
@@ -153,7 +156,7 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
continue continue
} }
items := (*[1 << 20]PdhRawCounterItem)(unsafe.Pointer(&buf[0]))[:itemCount] items := unsafe.Slice((*PdhRawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
if data == nil { if data == nil {
data = make(map[string]map[string]perftypes.CounterValues, itemCount) data = make(map[string]map[string]perftypes.CounterValues, itemCount)
@@ -169,7 +172,7 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
for _, item := range items { for _, item := range items {
if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData { if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData {
instanceName := windows.UTF16PtrToString(item.SzName) instanceName := windows.UTF16PtrToString(item.SzName)
if strings.HasSuffix(instanceName, "_Total") { if strings.HasSuffix(instanceName, "_Total") && !c.totalCounterRequested {
continue continue
} }
@@ -191,14 +194,14 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
switch counter.Type { switch counter.Type {
case perftypes.PERF_ELAPSED_TIME: case perftypes.PERF_ELAPSED_TIME:
values.FirstValue = float64(item.RawValue.FirstValue-perftypes.WindowsEpoch) / counter.Frequency values.FirstValue = float64((item.RawValue.FirstValue - perftypes.WindowsEpoch) / counter.Frequency)
values.SecondValue = float64(item.RawValue.SecondValue-perftypes.WindowsEpoch) / counter.Frequency
case perftypes.PERF_100NSEC_TIMER, perftypes.PERF_PRECISION_100NS_TIMER: case perftypes.PERF_100NSEC_TIMER, perftypes.PERF_PRECISION_100NS_TIMER:
values.FirstValue = float64(item.RawValue.FirstValue) * perftypes.TicksToSecondScaleFactor values.FirstValue = float64(item.RawValue.FirstValue) * perftypes.TicksToSecondScaleFactor
values.SecondValue = float64(item.RawValue.SecondValue) * perftypes.TicksToSecondScaleFactor case perftypes.PERF_AVERAGE_BULK:
default:
values.FirstValue = float64(item.RawValue.FirstValue) values.FirstValue = float64(item.RawValue.FirstValue)
values.SecondValue = float64(item.RawValue.SecondValue) values.SecondValue = float64(item.RawValue.SecondValue)
default:
values.FirstValue = float64(item.RawValue.FirstValue)
} }
data[instanceName][counter.Name] = values data[instanceName][counter.Name] = values

View File

@@ -622,7 +622,7 @@ func PdhGetRawCounterArray(hCounter pdhCounterHandle, lpdwBufferSize *uint32, lp
// //
// lpdwItemCount // lpdwItemCount
// Time base that specifies the number of performance values a counter samples per second. // Time base that specifies the number of performance values a counter samples per second.
func PdhGetCounterTimeBase(hCounter pdhCounterHandle, pTimeBase *float64) uint32 { func PdhGetCounterTimeBase(hCounter pdhCounterHandle, pTimeBase *int64) uint32 {
ret, _, _ := pdhPdhGetCounterTimeBase.Call( ret, _, _ := pdhPdhGetCounterTimeBase.Call(
uintptr(hCounter), uintptr(hCounter),
uintptr(unsafe.Pointer(pTimeBase))) uintptr(unsafe.Pointer(pTimeBase)))

View File

@@ -11,6 +11,7 @@ import (
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/toggle"
"github.com/prometheus-community/windows_exporter/pkg/collector" "github.com/prometheus-community/windows_exporter/pkg/collector"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@@ -46,7 +47,8 @@ func FuncBenchmarkCollector[C collector.Collector](b *testing.B, name string, co
func TestCollector[C collector.Collector, V interface{}](t *testing.T, fn func(*V) C, conf *V) { func TestCollector[C collector.Collector, V interface{}](t *testing.T, fn func(*V) C, conf *V) {
t.Helper() t.Helper()
t.Setenv("WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE", "pdh")
toggle.PHDEnabled = true
var ( var (
metrics []prometheus.Metric metrics []prometheus.Metric

7
internal/toggle/main.go Normal file
View File

@@ -0,0 +1,7 @@
package toggle
var PHDEnabled bool
func IsPDHEnabled() bool {
return PHDEnabled
}

View File

@@ -3,7 +3,6 @@
package utils package utils
import ( import (
"os"
"strings" "strings"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
@@ -27,19 +26,3 @@ func ExpandEnabledCollectors(enabled string) []string {
return result return result
} }
func PDHEnabled() bool {
if v, ok := os.LookupEnv("WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE"); ok && v == "pdh" {
return true
}
return false
}
func MIEnabled() bool {
if v, ok := os.LookupEnv("WINDOWS_EXPORTER_WMI_ENGINE"); ok && v == "mi" {
return true
}
return false
}

View File

@@ -6,6 +6,10 @@ func MilliSecToSec(t float64) float64 {
return t / 1000 return t / 1000
} }
func MBToBytes(mb float64) float64 {
return mb * 1024 * 1024
}
func BoolToFloat(b bool) float64 { func BoolToFloat(b bool) float64 {
if b { if b {
return 1.0 return 1.0

View File

@@ -39,6 +39,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework" "github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps" "github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os" "github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata" "github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk" "github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer" "github.com/prometheus-community/windows_exporter/internal/collector/printer"
@@ -55,6 +56,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/textfile" "github.com/prometheus-community/windows_exporter/internal/collector/textfile"
"github.com/prometheus-community/windows_exporter/internal/collector/thermalzone" "github.com/prometheus-community/windows_exporter/internal/collector/thermalzone"
"github.com/prometheus-community/windows_exporter/internal/collector/time" "github.com/prometheus-community/windows_exporter/internal/collector/time"
"github.com/prometheus-community/windows_exporter/internal/collector/udp"
"github.com/prometheus-community/windows_exporter/internal/collector/update" "github.com/prometheus-community/windows_exporter/internal/collector/update"
"github.com/prometheus-community/windows_exporter/internal/collector/vmware" "github.com/prometheus-community/windows_exporter/internal/collector/vmware"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
@@ -106,6 +108,7 @@ func NewWithConfig(config Config) *MetricCollectors {
collectors[netframework.Name] = netframework.New(&config.NetFramework) collectors[netframework.Name] = netframework.New(&config.NetFramework)
collectors[nps.Name] = nps.New(&config.Nps) collectors[nps.Name] = nps.New(&config.Nps)
collectors[os.Name] = os.New(&config.OS) collectors[os.Name] = os.New(&config.OS)
collectors[pagefile.Name] = pagefile.New(&config.Paging)
collectors[perfdata.Name] = perfdata.New(&config.PerfData) collectors[perfdata.Name] = perfdata.New(&config.PerfData)
collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk) collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk)
collectors[printer.Name] = printer.New(&config.Printer) collectors[printer.Name] = printer.New(&config.Printer)
@@ -122,6 +125,7 @@ func NewWithConfig(config Config) *MetricCollectors {
collectors[textfile.Name] = textfile.New(&config.Textfile) collectors[textfile.Name] = textfile.New(&config.Textfile)
collectors[thermalzone.Name] = thermalzone.New(&config.ThermalZone) collectors[thermalzone.Name] = thermalzone.New(&config.ThermalZone)
collectors[time.Name] = time.New(&config.Time) collectors[time.Name] = time.New(&config.Time)
collectors[udp.Name] = udp.New(&config.UDP)
collectors[update.Name] = update.New(&config.Update) collectors[update.Name] = update.New(&config.Update)
collectors[vmware.Name] = vmware.New(&config.Vmware) collectors[vmware.Name] = vmware.New(&config.Vmware)

View File

@@ -29,6 +29,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework" "github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps" "github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os" "github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata" "github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk" "github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer" "github.com/prometheus-community/windows_exporter/internal/collector/printer"
@@ -45,6 +46,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/textfile" "github.com/prometheus-community/windows_exporter/internal/collector/textfile"
"github.com/prometheus-community/windows_exporter/internal/collector/thermalzone" "github.com/prometheus-community/windows_exporter/internal/collector/thermalzone"
"github.com/prometheus-community/windows_exporter/internal/collector/time" "github.com/prometheus-community/windows_exporter/internal/collector/time"
"github.com/prometheus-community/windows_exporter/internal/collector/udp"
"github.com/prometheus-community/windows_exporter/internal/collector/update" "github.com/prometheus-community/windows_exporter/internal/collector/update"
"github.com/prometheus-community/windows_exporter/internal/collector/vmware" "github.com/prometheus-community/windows_exporter/internal/collector/vmware"
) )
@@ -78,6 +80,7 @@ type Config struct {
NetFramework netframework.Config `yaml:"net_framework"` NetFramework netframework.Config `yaml:"net_framework"`
Nps nps.Config `yaml:"nps"` Nps nps.Config `yaml:"nps"`
OS os.Config `yaml:"os"` OS os.Config `yaml:"os"`
Paging pagefile.Config `yaml:"paging"`
PerfData perfdata.Config `yaml:"perf_data"` PerfData perfdata.Config `yaml:"perf_data"`
PhysicalDisk physical_disk.Config `yaml:"physical_disk"` PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
Printer printer.Config `yaml:"printer"` Printer printer.Config `yaml:"printer"`
@@ -94,6 +97,7 @@ type Config struct {
Textfile textfile.Config `yaml:"textfile"` Textfile textfile.Config `yaml:"textfile"`
ThermalZone thermalzone.Config `yaml:"thermal_zone"` ThermalZone thermalzone.Config `yaml:"thermal_zone"`
Time time.Config `yaml:"time"` Time time.Config `yaml:"time"`
UDP udp.Config `yaml:"udp"`
Update update.Config `yaml:"update"` Update update.Config `yaml:"update"`
Vmware vmware.Config `yaml:"vmware"` Vmware vmware.Config `yaml:"vmware"`
} }
@@ -130,6 +134,7 @@ var ConfigDefaults = Config{
NetFramework: netframework.ConfigDefaults, NetFramework: netframework.ConfigDefaults,
Nps: nps.ConfigDefaults, Nps: nps.ConfigDefaults,
OS: os.ConfigDefaults, OS: os.ConfigDefaults,
Paging: pagefile.ConfigDefaults,
PerfData: perfdata.ConfigDefaults, PerfData: perfdata.ConfigDefaults,
PhysicalDisk: physical_disk.ConfigDefaults, PhysicalDisk: physical_disk.ConfigDefaults,
Printer: printer.ConfigDefaults, Printer: printer.ConfigDefaults,
@@ -146,6 +151,7 @@ var ConfigDefaults = Config{
Textfile: textfile.ConfigDefaults, Textfile: textfile.ConfigDefaults,
ThermalZone: thermalzone.ConfigDefaults, ThermalZone: thermalzone.ConfigDefaults,
Time: time.ConfigDefaults, Time: time.ConfigDefaults,
UDP: udp.ConfigDefaults,
Update: update.ConfigDefaults, Update: update.ConfigDefaults,
Vmware: vmware.ConfigDefaults, Vmware: vmware.ConfigDefaults,
} }

View File

@@ -33,6 +33,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/netframework" "github.com/prometheus-community/windows_exporter/internal/collector/netframework"
"github.com/prometheus-community/windows_exporter/internal/collector/nps" "github.com/prometheus-community/windows_exporter/internal/collector/nps"
"github.com/prometheus-community/windows_exporter/internal/collector/os" "github.com/prometheus-community/windows_exporter/internal/collector/os"
"github.com/prometheus-community/windows_exporter/internal/collector/pagefile"
"github.com/prometheus-community/windows_exporter/internal/collector/perfdata" "github.com/prometheus-community/windows_exporter/internal/collector/perfdata"
"github.com/prometheus-community/windows_exporter/internal/collector/physical_disk" "github.com/prometheus-community/windows_exporter/internal/collector/physical_disk"
"github.com/prometheus-community/windows_exporter/internal/collector/printer" "github.com/prometheus-community/windows_exporter/internal/collector/printer"
@@ -49,6 +50,7 @@ import (
"github.com/prometheus-community/windows_exporter/internal/collector/textfile" "github.com/prometheus-community/windows_exporter/internal/collector/textfile"
"github.com/prometheus-community/windows_exporter/internal/collector/thermalzone" "github.com/prometheus-community/windows_exporter/internal/collector/thermalzone"
"github.com/prometheus-community/windows_exporter/internal/collector/time" "github.com/prometheus-community/windows_exporter/internal/collector/time"
"github.com/prometheus-community/windows_exporter/internal/collector/udp"
"github.com/prometheus-community/windows_exporter/internal/collector/update" "github.com/prometheus-community/windows_exporter/internal/collector/update"
"github.com/prometheus-community/windows_exporter/internal/collector/vmware" "github.com/prometheus-community/windows_exporter/internal/collector/vmware"
) )
@@ -88,6 +90,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
netframework.Name: NewBuilderWithFlags(netframework.NewWithFlags), netframework.Name: NewBuilderWithFlags(netframework.NewWithFlags),
nps.Name: NewBuilderWithFlags(nps.NewWithFlags), nps.Name: NewBuilderWithFlags(nps.NewWithFlags),
os.Name: NewBuilderWithFlags(os.NewWithFlags), os.Name: NewBuilderWithFlags(os.NewWithFlags),
pagefile.Name: NewBuilderWithFlags(pagefile.NewWithFlags),
perfdata.Name: NewBuilderWithFlags(perfdata.NewWithFlags), perfdata.Name: NewBuilderWithFlags(perfdata.NewWithFlags),
physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags), physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags),
printer.Name: NewBuilderWithFlags(printer.NewWithFlags), printer.Name: NewBuilderWithFlags(printer.NewWithFlags),
@@ -104,6 +107,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
textfile.Name: NewBuilderWithFlags(textfile.NewWithFlags), textfile.Name: NewBuilderWithFlags(textfile.NewWithFlags),
thermalzone.Name: NewBuilderWithFlags(thermalzone.NewWithFlags), thermalzone.Name: NewBuilderWithFlags(thermalzone.NewWithFlags),
time.Name: NewBuilderWithFlags(time.NewWithFlags), time.Name: NewBuilderWithFlags(time.NewWithFlags),
udp.Name: NewBuilderWithFlags(udp.NewWithFlags),
update.Name: NewBuilderWithFlags(update.NewWithFlags), update.Name: NewBuilderWithFlags(update.NewWithFlags),
vmware.Name: NewBuilderWithFlags(vmware.NewWithFlags), vmware.Name: NewBuilderWithFlags(vmware.NewWithFlags),
} }

View File

@@ -87,8 +87,6 @@ test_alpha_total 42
# TYPE windows_cpu_interrupts_total counter # TYPE windows_cpu_interrupts_total counter
# HELP windows_cpu_logical_processor Total number of logical processors # HELP windows_cpu_logical_processor Total number of logical processors
# TYPE windows_cpu_logical_processor gauge # TYPE windows_cpu_logical_processor gauge
# HELP windows_net_nic_address_info A metric with a constant '1' value labeled with the network interface's address information.
# TYPE windows_net_nic_address_info gauge
# HELP windows_cpu_parking_status Parking Status represents whether a processor is parked or not # HELP windows_cpu_parking_status Parking Status represents whether a processor is parked or not
# TYPE windows_cpu_parking_status gauge # TYPE windows_cpu_parking_status gauge
# HELP windows_cpu_processor_mperf_total Processor MPerf is the number of TSC ticks incremented while executing instructions # HELP windows_cpu_processor_mperf_total Processor MPerf is the number of TSC ticks incremented while executing instructions
@@ -120,16 +118,22 @@ windows_exporter_collector_success{collector="cpu"} 1
windows_exporter_collector_success{collector="cpu_info"} 1 windows_exporter_collector_success{collector="cpu_info"} 1
windows_exporter_collector_success{collector="cs"} 1 windows_exporter_collector_success{collector="cs"} 1
windows_exporter_collector_success{collector="logical_disk"} 1 windows_exporter_collector_success{collector="logical_disk"} 1
windows_exporter_collector_success{collector="logon"} 1
windows_exporter_collector_success{collector="memory"} 1 windows_exporter_collector_success{collector="memory"} 1
windows_exporter_collector_success{collector="net"} 1 windows_exporter_collector_success{collector="net"} 1
windows_exporter_collector_success{collector="os"} 1 windows_exporter_collector_success{collector="os"} 1
windows_exporter_collector_success{collector="pagefile"} 1
windows_exporter_collector_success{collector="perfdata"} 1 windows_exporter_collector_success{collector="perfdata"} 1
windows_exporter_collector_success{collector="physical_disk"} 1 windows_exporter_collector_success{collector="physical_disk"} 1
windows_exporter_collector_success{collector="printer"} 1
windows_exporter_collector_success{collector="process"} 1 windows_exporter_collector_success{collector="process"} 1
windows_exporter_collector_success{collector="scheduled_task"} 1 windows_exporter_collector_success{collector="scheduled_task"} 1
windows_exporter_collector_success{collector="service"} 1 windows_exporter_collector_success{collector="service"} 1
windows_exporter_collector_success{collector="system"} 1 windows_exporter_collector_success{collector="system"} 1
windows_exporter_collector_success{collector="tcp"} 1
windows_exporter_collector_success{collector="textfile"} 1 windows_exporter_collector_success{collector="textfile"} 1
windows_exporter_collector_success{collector="time"} 1
windows_exporter_collector_success{collector="udp"} 1
# HELP windows_exporter_collector_timeout windows_exporter: Whether the collector timed out. # HELP windows_exporter_collector_timeout windows_exporter: Whether the collector timed out.
# TYPE windows_exporter_collector_timeout gauge # TYPE windows_exporter_collector_timeout gauge
windows_exporter_collector_timeout{collector="cache"} 0 windows_exporter_collector_timeout{collector="cache"} 0
@@ -137,16 +141,22 @@ windows_exporter_collector_timeout{collector="cpu"} 0
windows_exporter_collector_timeout{collector="cpu_info"} 0 windows_exporter_collector_timeout{collector="cpu_info"} 0
windows_exporter_collector_timeout{collector="cs"} 0 windows_exporter_collector_timeout{collector="cs"} 0
windows_exporter_collector_timeout{collector="logical_disk"} 0 windows_exporter_collector_timeout{collector="logical_disk"} 0
windows_exporter_collector_timeout{collector="logon"} 0
windows_exporter_collector_timeout{collector="memory"} 0 windows_exporter_collector_timeout{collector="memory"} 0
windows_exporter_collector_timeout{collector="net"} 0 windows_exporter_collector_timeout{collector="net"} 0
windows_exporter_collector_timeout{collector="os"} 0 windows_exporter_collector_timeout{collector="os"} 0
windows_exporter_collector_timeout{collector="pagefile"} 0
windows_exporter_collector_timeout{collector="perfdata"} 0 windows_exporter_collector_timeout{collector="perfdata"} 0
windows_exporter_collector_timeout{collector="physical_disk"} 0 windows_exporter_collector_timeout{collector="physical_disk"} 0
windows_exporter_collector_timeout{collector="printer"} 0
windows_exporter_collector_timeout{collector="process"} 0 windows_exporter_collector_timeout{collector="process"} 0
windows_exporter_collector_timeout{collector="scheduled_task"} 0 windows_exporter_collector_timeout{collector="scheduled_task"} 0
windows_exporter_collector_timeout{collector="service"} 0 windows_exporter_collector_timeout{collector="service"} 0
windows_exporter_collector_timeout{collector="system"} 0 windows_exporter_collector_timeout{collector="system"} 0
windows_exporter_collector_timeout{collector="tcp"} 0
windows_exporter_collector_timeout{collector="textfile"} 0 windows_exporter_collector_timeout{collector="textfile"} 0
windows_exporter_collector_timeout{collector="time"} 0
windows_exporter_collector_timeout{collector="udp"} 0
# HELP windows_exporter_perflib_snapshot_duration_seconds Duration of perflib snapshot capture # HELP windows_exporter_perflib_snapshot_duration_seconds Duration of perflib snapshot capture
# TYPE windows_exporter_perflib_snapshot_duration_seconds gauge # TYPE windows_exporter_perflib_snapshot_duration_seconds gauge
# HELP windows_exporter_scrape_duration_seconds windows_exporter: Total scrape duration. # HELP windows_exporter_scrape_duration_seconds windows_exporter: Total scrape duration.
@@ -185,6 +195,8 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_logical_disk_write_seconds_total counter # TYPE windows_logical_disk_write_seconds_total counter
# HELP windows_logical_disk_writes_total The number of write operations on the disk (LogicalDisk.DiskWritesPerSec) # HELP windows_logical_disk_writes_total The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)
# TYPE windows_logical_disk_writes_total counter # TYPE windows_logical_disk_writes_total counter
# HELP windows_logon_session_logon_timestamp_seconds timestamp of the logon session in seconds.
# TYPE windows_logon_session_logon_timestamp_seconds gauge
# HELP windows_memory_available_bytes The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to the standby (cached), free and zero page lists (AvailableBytes) # HELP windows_memory_available_bytes The amount of physical memory immediately available for allocation to a process or for system use. It is equal to the sum of memory assigned to the standby (cached), free and zero page lists (AvailableBytes)
# TYPE windows_memory_available_bytes gauge # TYPE windows_memory_available_bytes gauge
# HELP windows_memory_cache_bytes (CacheBytes) # HELP windows_memory_cache_bytes (CacheBytes)
@@ -229,15 +241,15 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_memory_standby_cache_normal_priority_bytes gauge # TYPE windows_memory_standby_cache_normal_priority_bytes gauge
# HELP windows_memory_standby_cache_reserve_bytes The amount of physical memory, in bytes, that is assigned to the reserve standby cache page lists. This memory contains cached data and code that is not actively in use by processes, the system and the system cache (StandbyCacheReserveBytes) # HELP windows_memory_standby_cache_reserve_bytes The amount of physical memory, in bytes, that is assigned to the reserve standby cache page lists. This memory contains cached data and code that is not actively in use by processes, the system and the system cache (StandbyCacheReserveBytes)
# TYPE windows_memory_standby_cache_reserve_bytes gauge # TYPE windows_memory_standby_cache_reserve_bytes gauge
# HELP windows_memory_swap_page_operations_total Total number of swap page read and writes (PagesPersec) # HELP windows_memory_swap_page_operations_total Total number of swap page read and writes (PagesPerSec)
# TYPE windows_memory_swap_page_operations_total counter # TYPE windows_memory_swap_page_operations_total counter
# HELP windows_memory_swap_page_reads_total Number of disk page reads (a single read operation reading several pages is still only counted once) (PageReadsPersec) # HELP windows_memory_swap_page_reads_total Number of disk page reads (a single read operation reading several pages is still only counted once) (PageReadsPerSec)
# TYPE windows_memory_swap_page_reads_total counter # TYPE windows_memory_swap_page_reads_total counter
# HELP windows_memory_swap_page_writes_total Number of disk page writes (a single write operation writing several pages is still only counted once) (PageWritesPersec) # HELP windows_memory_swap_page_writes_total Number of disk page writes (a single write operation writing several pages is still only counted once) (PageWritesPerSec)
# TYPE windows_memory_swap_page_writes_total counter # TYPE windows_memory_swap_page_writes_total counter
# HELP windows_memory_swap_pages_read_total Number of pages read across all page reads (ie counting all pages read even if they are read in a single operation) (PagesInputPersec) # HELP windows_memory_swap_pages_read_total Number of pages read across all page reads (ie counting all pages read even if they are read in a single operation) (PagesInputPerSec)
# TYPE windows_memory_swap_pages_read_total counter # TYPE windows_memory_swap_pages_read_total counter
# HELP windows_memory_swap_pages_written_total Number of pages written across all page writes (ie counting all pages written even if they are written in a single operation) (PagesOutputPersec) # HELP windows_memory_swap_pages_written_total Number of pages written across all page writes (ie counting all pages written even if they are written in a single operation) (PagesOutputPerSec)
# TYPE windows_memory_swap_pages_written_total counter # TYPE windows_memory_swap_pages_written_total counter
# HELP windows_memory_system_cache_resident_bytes The size, in bytes, of the portion of the system file cache which is currently resident and active in physical memory (SystemCacheResidentBytes) # HELP windows_memory_system_cache_resident_bytes The size, in bytes, of the portion of the system file cache which is currently resident and active in physical memory (SystemCacheResidentBytes)
# TYPE windows_memory_system_cache_resident_bytes gauge # TYPE windows_memory_system_cache_resident_bytes gauge
@@ -249,11 +261,11 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_memory_system_driver_resident_bytes gauge # TYPE windows_memory_system_driver_resident_bytes gauge
# HELP windows_memory_system_driver_total_bytes The size, in bytes, of the pageable virtual memory currently being used by device drivers. Pageable memory can be written to disk when it is not being used (SystemDriverTotalBytes) # HELP windows_memory_system_driver_total_bytes The size, in bytes, of the pageable virtual memory currently being used by device drivers. Pageable memory can be written to disk when it is not being used (SystemDriverTotalBytes)
# TYPE windows_memory_system_driver_total_bytes gauge # TYPE windows_memory_system_driver_total_bytes gauge
# HELP windows_memory_transition_faults_total Number of faults rate at which page faults are resolved by recovering pages that were being used by another process sharing the page, or were on the modified page list or the standby list, or were being written to disk at the time of the page fault (TransitionFaultsPersec) # HELP windows_memory_transition_faults_total Number of faults rate at which page faults are resolved by recovering pages that were being used by another process sharing the page, or were on the modified page list or the standby list, or were being written to disk at the time of the page fault (TransitionFaultsPerSec)
# TYPE windows_memory_transition_faults_total counter # TYPE windows_memory_transition_faults_total counter
# HELP windows_memory_transition_pages_repurposed_total Transition Pages RePurposed is the rate at which the number of transition cache pages were reused for a different purpose (TransitionPagesRePurposedPersec) # HELP windows_memory_transition_pages_repurposed_total Transition Pages RePurposed is the rate at which the number of transition cache pages were reused for a different purpose (TransitionPagesRePurposedPerSec)
# TYPE windows_memory_transition_pages_repurposed_total counter # TYPE windows_memory_transition_pages_repurposed_total counter
# HELP windows_memory_write_copies_total The number of page faults caused by attempting to write that were satisfied by copying the page from elsewhere in physical memory (WriteCopiesPersec) # HELP windows_memory_write_copies_total The number of page faults caused by attempting to write that were satisfied by copying the page from elsewhere in physical memory (WriteCopiesPerSec)
# TYPE windows_memory_write_copies_total counter # TYPE windows_memory_write_copies_total counter
# HELP windows_net_bytes_received_total (Network.BytesReceivedPerSec) # HELP windows_net_bytes_received_total (Network.BytesReceivedPerSec)
# TYPE windows_net_bytes_received_total counter # TYPE windows_net_bytes_received_total counter
@@ -263,6 +275,8 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_net_bytes_total counter # TYPE windows_net_bytes_total counter
# HELP windows_net_current_bandwidth_bytes (Network.CurrentBandwidth) # HELP windows_net_current_bandwidth_bytes (Network.CurrentBandwidth)
# TYPE windows_net_current_bandwidth_bytes gauge # TYPE windows_net_current_bandwidth_bytes gauge
# HELP windows_net_nic_address_info A metric with a constant '1' value labeled with the network interface's address information.
# TYPE windows_net_nic_address_info gauge
# HELP windows_net_output_queue_length_packets (Network.OutputQueueLength) # HELP windows_net_output_queue_length_packets (Network.OutputQueueLength)
# TYPE windows_net_output_queue_length_packets gauge # TYPE windows_net_output_queue_length_packets gauge
# HELP windows_net_packets_outbound_discarded_total (Network.PacketsOutboundDiscarded) # HELP windows_net_packets_outbound_discarded_total (Network.PacketsOutboundDiscarded)
@@ -285,9 +299,9 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_os_hostname gauge # TYPE windows_os_hostname gauge
# HELP windows_os_info Contains full product name & version in labels. Note that the "major_version" for Windows 11 is \\"10\\"; a build number greater than 22000 represents Windows 11. # HELP windows_os_info Contains full product name & version in labels. Note that the "major_version" for Windows 11 is \\"10\\"; a build number greater than 22000 represents Windows 11.
# TYPE windows_os_info gauge # TYPE windows_os_info gauge
# HELP windows_os_paging_free_bytes OperatingSystem.FreeSpaceInPagingFiles # HELP windows_os_paging_free_bytes Deprecated: Use windows_pagefile_free_bytes instead.
# TYPE windows_os_paging_free_bytes gauge # TYPE windows_os_paging_free_bytes gauge
# HELP windows_os_paging_limit_bytes OperatingSystem.SizeStoredInPagingFiles # HELP windows_os_paging_limit_bytes Deprecated: Use windows_pagefile_limit_bytes instead.
# TYPE windows_os_paging_limit_bytes gauge # TYPE windows_os_paging_limit_bytes gauge
# HELP windows_os_physical_memory_free_bytes Deprecated: Use `windows_memory_physical_free_bytes` instead. # HELP windows_os_physical_memory_free_bytes Deprecated: Use `windows_memory_physical_free_bytes` instead.
# TYPE windows_os_physical_memory_free_bytes gauge # TYPE windows_os_physical_memory_free_bytes gauge
@@ -309,6 +323,10 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_os_virtual_memory_free_bytes gauge # TYPE windows_os_virtual_memory_free_bytes gauge
# HELP windows_os_visible_memory_bytes Deprecated: Use `windows_memory_physical_total_bytes` instead. # HELP windows_os_visible_memory_bytes Deprecated: Use `windows_memory_physical_total_bytes` instead.
# TYPE windows_os_visible_memory_bytes gauge # TYPE windows_os_visible_memory_bytes gauge
# HELP windows_pagefile_free_bytes Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out
# TYPE windows_pagefile_free_bytes gauge
# HELP windows_pagefile_limit_bytes Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files
# TYPE windows_pagefile_limit_bytes gauge
# HELP windows_perfdata_memory_cache_faults_sec Performance data for \\Memory\\Cache Faults/sec # HELP windows_perfdata_memory_cache_faults_sec Performance data for \\Memory\\Cache Faults/sec
# TYPE windows_perfdata_memory_cache_faults_sec counter # TYPE windows_perfdata_memory_cache_faults_sec counter
# HELP windows_perfdata_processor_information__privileged_time Performance data for \\Processor Information\\% Privileged Time # HELP windows_perfdata_processor_information__privileged_time Performance data for \\Processor Information\\% Privileged Time
@@ -339,16 +357,26 @@ windows_exporter_collector_timeout{collector="textfile"} 0
# TYPE windows_physical_disk_write_seconds_total counter # TYPE windows_physical_disk_write_seconds_total counter
# HELP windows_physical_disk_writes_total The number of write operations on the disk (PhysicalDisk.DiskWritesPerSec) # HELP windows_physical_disk_writes_total The number of write operations on the disk (PhysicalDisk.DiskWritesPerSec)
# TYPE windows_physical_disk_writes_total counter # TYPE windows_physical_disk_writes_total counter
# HELP windows_printer_job_count Number of jobs processed by the printer since the last reset
# TYPE windows_printer_job_count counter
# HELP windows_printer_status Printer status
# TYPE windows_printer_status gauge
# HELP windows_scheduled_task_last_result The result that was returned the last time the registered task was run
# TYPE windows_scheduled_task_last_result gauge
windows_scheduled_task_last_result{task="/Microsoft/Windows/PLA/GAEvents"} 0
# HELP windows_scheduled_task_missed_runs The number of times the registered task missed a scheduled run
# TYPE windows_scheduled_task_missed_runs gauge
windows_scheduled_task_missed_runs{task="/Microsoft/Windows/PLA/GAEvents"} 0
# HELP windows_scheduled_task_state The current state of a scheduled task # HELP windows_scheduled_task_state The current state of a scheduled task
# TYPE windows_scheduled_task_state gauge # TYPE windows_scheduled_task_state gauge
windows_scheduled_task_state{state="disabled",task="/Microsoft/Windows/Maintenance/WinSAT"} 1 windows_scheduled_task_state{state="disabled",task="/Microsoft/Windows/PLA/GAEvents"} 0
windows_scheduled_task_state{state="queued",task="/Microsoft/Windows/Maintenance/WinSAT"} 0 windows_scheduled_task_state{state="queued",task="/Microsoft/Windows/PLA/GAEvents"} 0
windows_scheduled_task_state{state="ready",task="/Microsoft/Windows/Maintenance/WinSAT"} 0 windows_scheduled_task_state{state="ready",task="/Microsoft/Windows/PLA/GAEvents"} 0
windows_scheduled_task_state{state="running",task="/Microsoft/Windows/Maintenance/WinSAT"} 0 windows_scheduled_task_state{state="running",task="/Microsoft/Windows/PLA/GAEvents"} 1
windows_scheduled_task_state{state="unknown",task="/Microsoft/Windows/Maintenance/WinSAT"} 0 windows_scheduled_task_state{state="unknown",task="/Microsoft/Windows/PLA/GAEvents"} 0
# HELP windows_service_info A metric with a constant '1' value labeled with service information # HELP windows_service_info A metric with a constant '1' value labeled with service information
# TYPE windows_service_info gauge # TYPE windows_service_info gauge
windows_service_info{display_name="Themes",name="Themes",path_name="C:\\WINDOWS\\System32\\svchost.exe -k netsvcs -p",run_as="LocalSystem"} 1 windows_service_info{display_name="Themes",name="Themes",path_name="C:\\Windows\\System32\\svchost.exe -k netsvcs -p",run_as="LocalSystem"} 1
# HELP windows_service_process Process of started service. The value is the creation time of the process as a unix timestamp. # HELP windows_service_process Process of started service. The value is the creation time of the process as a unix timestamp.
# TYPE windows_service_process gauge # TYPE windows_service_process gauge
# HELP windows_service_start_mode The start mode of the service (StartMode) # HELP windows_service_start_mode The start mode of the service (StartMode)
@@ -383,9 +411,53 @@ windows_service_state{name="Themes",state="stopped"} 0
# TYPE windows_system_system_up_time gauge # TYPE windows_system_system_up_time gauge
# HELP windows_system_threads Current number of threads (WMI source: PerfOS_System.Threads) # HELP windows_system_threads Current number of threads (WMI source: PerfOS_System.Threads)
# TYPE windows_system_threads gauge # TYPE windows_system_threads gauge
# HELP windows_tcp_connection_failures_total (TCP.ConnectionFailures)
# TYPE windows_tcp_connection_failures_total counter
# HELP windows_tcp_connections_active_total (TCP.ConnectionsActive)
# TYPE windows_tcp_connections_active_total counter
# HELP windows_tcp_connections_established (TCP.ConnectionsEstablished)
# TYPE windows_tcp_connections_established gauge
# HELP windows_tcp_connections_passive_total (TCP.ConnectionsPassive)
# TYPE windows_tcp_connections_passive_total counter
# HELP windows_tcp_connections_reset_total (TCP.ConnectionsReset)
# TYPE windows_tcp_connections_reset_total counter
# HELP windows_tcp_connections_state_count Number of TCP connections by state and address family
# TYPE windows_tcp_connections_state_count gauge
# HELP windows_tcp_segments_received_total (TCP.SegmentsReceivedTotal)
# TYPE windows_tcp_segments_received_total counter
# HELP windows_tcp_segments_retransmitted_total (TCP.SegmentsRetransmittedTotal)
# TYPE windows_tcp_segments_retransmitted_total counter
# HELP windows_tcp_segments_sent_total (TCP.SegmentsSentTotal)
# TYPE windows_tcp_segments_sent_total counter
# HELP windows_tcp_segments_total (TCP.SegmentsTotal)
# TYPE windows_tcp_segments_total counter
# HELP windows_textfile_mtime_seconds Unixtime mtime of textfiles successfully read. # HELP windows_textfile_mtime_seconds Unixtime mtime of textfiles successfully read.
# TYPE windows_textfile_mtime_seconds gauge # TYPE windows_textfile_mtime_seconds gauge
# HELP windows_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise # HELP windows_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise
# TYPE windows_textfile_scrape_error gauge # TYPE windows_textfile_scrape_error gauge
windows_textfile_scrape_error 0 windows_textfile_scrape_error 0
# HELP windows_time_clock_frequency_adjustment_ppb_total Total adjustment made to the local system clock frequency by W32Time in Parts Per Billion (PPB) units.
# TYPE windows_time_clock_frequency_adjustment_ppb_total counter
# HELP windows_time_computed_time_offset_seconds Absolute time offset between the system clock and the chosen time source, in seconds
# TYPE windows_time_computed_time_offset_seconds gauge
# HELP windows_time_current_timestamp_seconds OperatingSystem.LocalDateTime
# TYPE windows_time_current_timestamp_seconds gauge
# HELP windows_time_ntp_client_time_sources Active number of NTP Time sources being used by the client
# TYPE windows_time_ntp_client_time_sources gauge
# HELP windows_time_ntp_round_trip_delay_seconds Roundtrip delay experienced by the NTP client in receiving a response from the server for the most recent request, in seconds
# TYPE windows_time_ntp_round_trip_delay_seconds gauge
# HELP windows_time_ntp_server_incoming_requests_total Total number of requests received by NTP server
# TYPE windows_time_ntp_server_incoming_requests_total counter
# HELP windows_time_ntp_server_outgoing_responses_total Total number of requests responded to by NTP server
# TYPE windows_time_ntp_server_outgoing_responses_total counter
# HELP windows_time_timezone OperatingSystem.LocalDateTime
# TYPE windows_time_timezone gauge
# HELP windows_udp_datagram_no_port_total Number of received UDP datagrams for which there was no application at the destination port
# TYPE windows_udp_datagram_no_port_total counter
# HELP windows_udp_datagram_received_errors_total Number of received UDP datagrams that could not be delivered for reasons other than the lack of an application at the destination port
# TYPE windows_udp_datagram_received_errors_total counter
# HELP windows_udp_datagram_received_total UDP datagrams are delivered to UDP users
# TYPE windows_udp_datagram_received_total gauge
# HELP windows_udp_datagram_sent_total UDP datagrams are sent from the entity
# TYPE windows_udp_datagram_sent_total counter

View File

@@ -10,7 +10,7 @@ if (-not (Test-Path -Path '..\windows_exporter.exe')) {
Write-Output "..\windows_exporter.exe not found. Consider running \`go build\` first" Write-Output "..\windows_exporter.exe not found. Consider running \`go build\` first"
} }
$temp_dir = Join-Path $env:TEMP $(New-Guid) | ForEach-Object { mkdir $_ } $temp_dir = Join-Path $env:TEMP $([guid]::newguid()) | ForEach-Object { mkdir $_ }
# Create temporary directory for textfile collector # Create temporary directory for textfile collector
$textfile_dir = "$($temp_dir)/textfile" $textfile_dir = "$($temp_dir)/textfile"
@@ -18,14 +18,14 @@ mkdir $textfile_dir | Out-Null
Copy-Item 'e2e-textfile.prom' -Destination "$($textfile_dir)/e2e-textfile.prom" Copy-Item 'e2e-textfile.prom' -Destination "$($textfile_dir)/e2e-textfile.prom"
# Omit dynamic collector information that will change after each run # Omit dynamic collector information that will change after each run
$skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|windows_exporter_scrape_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_cache|windows_logical_disk|windows_physical_disk|windows_memory|windows_net|windows_os|windows_process|windows_service_process|windows_system|windows_perfdata|windows_textfile_mtime_seconds)" $skip_re = "^(go_|windows_exporter_build_info|windows_exporter_collector_duration_seconds|windows_exporter_perflib_snapshot_duration_seconds|windows_exporter_scrape_duration_seconds|process_|windows_textfile_mtime_seconds|windows_cpu|windows_cs|windows_cache|windows_logon|windows_pagefile|windows_logical_disk|windows_physical_disk|windows_memory|windows_net|windows_os|windows_process|windows_service_process|windows_printer|windows_udp|windows_tcp|windows_system|windows_time|windows_session|windows_perfdata|windows_textfile_mtime_seconds)"
# Start process in background, awaiting HTTP requests. # Start process in background, awaiting HTTP requests.
# Use default collectors, port and address: http://localhost:9182/metrics # Use default collectors, port and address: http://localhost:9182/metrics
$exporter_proc = Start-Process ` $exporter_proc = Start-Process `
-PassThru ` -PassThru `
-FilePath ..\windows_exporter.exe ` -FilePath ..\windows_exporter.exe `
-ArgumentList "--log.level=debug","--web.disable-exporter-metrics","--collectors.enabled=[defaults],cache,cpu_info,textfile,process,perfdata,scheduled_task","--collector.process.include=explorer.exe","--collector.scheduled_task.include=.*WinSAT","--collector.service.include=Themes","--collector.textfile.directories=$($textfile_dir)",@" -ArgumentList "--log.level=debug","--web.disable-exporter-metrics","--collectors.enabled=[defaults],cpu_info,textfile,process,pagefile,perfdata,scheduled_task,tcp,udp,time,system,service,logical_disk,printer,os,net,memory,logon,cache","--collector.process.include=explorer.exe","--collector.scheduled_task.include=.*GAEvents","--collector.service.include=Themes","--collector.textfile.directories=$($textfile_dir)",@"
--collector.perfdata.objects="[{\"object\":\"Processor Information\",\"instance_label\":\"core\",\"instances\":[\"*\"],\"counters\":{\"% Processor Time\":{},\"% Privileged Time\":{}}},{\"object\":\"Memory\",\"counters\":{\"Cache Faults/sec\":{\"type\":\"counter\"}}}]" --collector.perfdata.objects="[{\"object\":\"Processor Information\",\"instance_label\":\"core\",\"instances\":[\"*\"],\"counters\":{\"% Processor Time\":{},\"% Privileged Time\":{}}},{\"object\":\"Memory\",\"counters\":{\"Cache Faults/sec\":{\"type\":\"counter\"}}}]"
"@ ` "@ `
-WindowStyle Hidden ` -WindowStyle Hidden `

View File

@@ -85,7 +85,7 @@ $script_path = $MyInvocation.MyCommand.Path
$working_dir = Split-Path $script_path $working_dir = Split-Path $script_path
Push-Location $working_dir Push-Location $working_dir
$temp_dir = Join-Path $env:TEMP $(New-Guid) | ForEach-Object { mkdir $_ } $temp_dir = Join-Path $env:TEMP $([guid]::newguid()) | ForEach-Object { mkdir $_ }
# Start process in background, awaiting HTTP requests. # Start process in background, awaiting HTTP requests.
# Listen on 9183/TCP, preventing conflicts with 9182/TCP used by end-to-end-test.ps1 # Listen on 9183/TCP, preventing conflicts with 9182/TCP used by end-to-end-test.ps1
@@ -113,13 +113,29 @@ for ($i=1; $i -le 5; $i++) {
# windows_memory_pool_nonpaged_allocs_total is wrong for years. It's not a gauge, but a counter. # windows_memory_pool_nonpaged_allocs_total is wrong for years. It's not a gauge, but a counter.
$skip_re = "^([#]?\s*(HELP|TYPE)?\s*go_|windows_memory_pool_nonpaged_allocs_total)" $skip_re = "^([#]?\s*(HELP|TYPE)?\s*go_|windows_memory_pool_nonpaged_allocs_total)"
# Need to remove carriage returns, as promtool expects LF line endings try {
$output = ((Invoke-WebRequest -UseBasicParsing -URI http://127.0.0.1:9183/metrics).Content) -Split "`r?`n" | Select-String -NotMatch $skip_re | Join-String -Separator "`n" # Need to remove carriage returns, as promtool expects LF line endings
# Join the split lines back to a single String (with LF line endings!) $output = ((Invoke-WebRequest -UseBasicParsing -URI http://127.0.0.1:9183/metrics).Content) -Split "`r?`n" | Select-String -NotMatch $skip_re | Join-String -Separator "`n"
$output = $output -Join "`n" # $output = (((Invoke-WebRequest -UseBasicParsing -URI http://127.0.0.1:9183/metrics).Content) -Split "`r?`n" | Select-String -NotMatch $skip_re) -join "`n"
Stop-Process -Id $exporter_proc.Id # Join the split lines back to a single String (with LF line endings!)
$output = $output -Join "`n"
Stop-Process -Id $exporter_proc.Id
} catch {
Write-Host "STDOUT"
Get-Content "$($temp_dir)/windows_exporter.log"
Write-Host "STDERR"
Get-Content "$($temp_dir)/windows_exporter_error.log"
throw $_
}
$ExitCode = Start-RawProcess -InputVar $output -CommandName promtool.exe -CommandArgs @("check metrics") $ExitCode = Start-RawProcess -InputVar $output -CommandName promtool.exe -CommandArgs @("check metrics")
if ($ExitCode -ne 0) { if ($ExitCode -ne 0) {
Write-Host "OUTPUT"
Write-Host $output
Write-Host "Promtool command returned exit code $($ExitCode). See output for details." Write-Host "Promtool command returned exit code $($ExitCode). See output for details."
EXIT 1 EXIT 1
} }