mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-08 05:56:37 +00:00
Compare commits
12 Commits
v0.30.0-be
...
v0.30.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a9a4e5831 | ||
|
|
df8513ab8e | ||
|
|
1956330ac4 | ||
|
|
baa4dc16ae | ||
|
|
d13d726453 | ||
|
|
31bcf42473 | ||
|
|
f332361723 | ||
|
|
b4f50c542c | ||
|
|
b53f18bcc6 | ||
|
|
eeb7955f5e | ||
|
|
55181f5bac | ||
|
|
e6c9253f15 |
2
.github/workflows/pr-check.yaml
vendored
2
.github/workflows/pr-check.yaml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
- name: check
|
||||
run: |
|
||||
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
|
||||
fi
|
||||
|
||||
|
||||
103
.github/workflows/release.yml
vendored
103
.github/workflows/release.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
@@ -16,10 +17,7 @@ permissions:
|
||||
packages: write
|
||||
|
||||
env:
|
||||
VERSION_PROMU: '0.14.0'
|
||||
VERSION_CONTAINERD: '1.7.21'
|
||||
VERSION_BUILDKIT: '0.15.2'
|
||||
VERSION_BUILDX: '0.16.2'
|
||||
VERSION_PROMU: '0.17.0'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -33,27 +31,6 @@ jobs:
|
||||
with:
|
||||
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
|
||||
run: dotnet tool install --global wix
|
||||
|
||||
@@ -114,16 +91,27 @@ jobs:
|
||||
output\windows_exporter-*.exe
|
||||
output\windows_exporter-*.msi
|
||||
|
||||
- name: Build Docker Artifacts
|
||||
run: make build-all
|
||||
- name: Release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
VERSION: >-
|
||||
${{
|
||||
startsWith(github.ref, 'refs/tags/') && 'latest' ||
|
||||
(
|
||||
github.event_name == 'pull_request' && format('pr-{0}', github.event.number) || github.ref_name
|
||||
)
|
||||
}}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$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 $_}
|
||||
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
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
@@ -137,8 +125,8 @@ jobs:
|
||||
# uses: docker/login-action@v3
|
||||
# with:
|
||||
# registry: quay.io
|
||||
# username: 'robot'
|
||||
# password: ${{ secrets.QUAY_IO_API_TOKEN }}
|
||||
# username: ${{ secrets.QUAY_USER }}
|
||||
# password: ${{ secrets.QUAY_PASS }}
|
||||
|
||||
- name: Login to GitHub container registry
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
@@ -148,19 +136,32 @@ jobs:
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push Latest image
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION: ${{ startsWith(github.ref, 'refs/tags/') && 'latest' || github.ref_name }}
|
||||
run: |
|
||||
make push-all
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: |
|
||||
ghcr.io/prometheus-community/windows-exporter
|
||||
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
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
$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 $_}
|
||||
make push-all
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
platforms: windows/amd64
|
||||
|
||||
16
Dockerfile
16
Dockerfile
@@ -1,9 +1,13 @@
|
||||
# Note this image doesn't really matter for hostprocess but it is good to build per OS version
|
||||
# the files in the image are copied to $env:CONTAINER_SANDBOX_MOUNT_POINT on the host
|
||||
# but the file system is the Host NOT the container
|
||||
ARG BASE="mcr.microsoft.com/windows/nanoserver:ltsc2022"
|
||||
# mcr.microsoft.com/oss/kubernetes/windows-host-process-containers-base-image:v1.0.0
|
||||
# Using this image as a base for HostProcess containers has a few advantages over using other base images for Windows containers including:
|
||||
# - Smaller image size
|
||||
# - 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
|
||||
|
||||
ENV PATH="C:\Windows\system32;C:\Windows;"
|
||||
COPY output/amd64/windows_exporter.exe /windows_exporter.exe
|
||||
COPY windows_exporter*-amd64.exe /windows_exporter.exe
|
||||
ENTRYPOINT ["windows_exporter.exe"]
|
||||
|
||||
@@ -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"]
|
||||
28
Makefile
28
Makefile
@@ -36,7 +36,7 @@ lint:
|
||||
|
||||
.PHONY: e2e-test
|
||||
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
|
||||
promtool: windows_exporter.exe
|
||||
@@ -64,31 +64,19 @@ build-hostprocess:
|
||||
sub-build-%:
|
||||
$(MAKE) OS=$* build-image
|
||||
|
||||
build-all: $(addprefix sub-build-,$(ALL_OS)) build-hostprocess
|
||||
|
||||
push:
|
||||
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); \
|
||||
build-all: crossbuild
|
||||
@for docker_repo in ${DOCKER_REPO}; do \
|
||||
echo $(DOCKER) buildx build -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) .; \
|
||||
done
|
||||
|
||||
# We can't load the image into the local docker store, so we have to build and push it in one go
|
||||
push-hostprocess:
|
||||
set -x; \
|
||||
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 .; \
|
||||
push:
|
||||
@for docker_repo in ${DOCKER_REPO}; do \
|
||||
echo $(DOCKER) buildx build --push -f Dockerfile -t $${docker_repo}/$(DOCKER_IMAGE_NAME):$(VERSION) .; \
|
||||
done
|
||||
|
||||
.PHONY: push-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
|
||||
.PHONY: docker-repo-name
|
||||
|
||||
10
README.md
10
README.md
@@ -1,6 +1,12 @@
|
||||
# windows_exporter
|
||||
|
||||

|
||||
[](https://github.com/prometheus-community/windows_exporter)
|
||||
[](https://github.com/prometheus-community/windows_exporter)
|
||||
[](https://github.com/prometheus-community/windows_exporter/blob/master/LICENSE.txt)
|
||||
[](https://github.com/prometheus-community/windows_exporter/releases/latest)
|
||||
[](https://github.com/prometheus-community/windows_exporter/stargazers)
|
||||
[](https://github.com/prometheus-community/windows_exporter/releases/latest)
|
||||
[](https://goreportcard.com/report/github.com/prometheus-community/windows_exporter)
|
||||
|
||||
A Prometheus exporter for Windows machines.
|
||||
|
||||
@@ -35,6 +41,7 @@ Name | Description | Enabled by default
|
||||
[netframework](docs/collector.netframework.md) | .NET Framework metrics |
|
||||
[net](docs/collector.net.md) | Network interface I/O | ✓
|
||||
[os](docs/collector.os.md) | OS metrics (memory, processes, users) | ✓
|
||||
[pagefile](docs/collector.pagefile.md) | pagefile metrics |
|
||||
[perfdata](docs/collector.perfdata.md) | Custom perfdata metrics |
|
||||
[physical_disk](docs/collector.physical_disk.md) | physical disk 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 |
|
||||
[thermalzone](docs/collector.thermalzone.md) | Thermal information |
|
||||
[time](docs/collector.time.md) | Windows Time Service |
|
||||
[udp](docs/collector.udp.md) | UDP connections |
|
||||
[update](docs/collector.update.md) | Windows Update Service |
|
||||
[vmware](docs/collector.vmware.md) | Performance counters installed by the Vmware Guest agent |
|
||||
|
||||
|
||||
@@ -41,5 +41,6 @@ This directory contains documentation of the collectors in the windows_exporter,
|
||||
- [`textfile`](collector.textfile.md)
|
||||
- [`thermalzone`](collector.thermalzone.md)
|
||||
- [`time`](collector.time.md)
|
||||
- [`udp`](collector.udp.md)
|
||||
- [`update`](collector.update.md)
|
||||
- [`vmware`](collector.vmware.md)
|
||||
|
||||
@@ -14,13 +14,11 @@ None
|
||||
|
||||
## Metrics
|
||||
|
||||
| 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_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_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 |
|
||||
| Name | Description | Type | Labels |
|
||||
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
|
||||
| `windows_os_hostname` | Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain | gauge | `domain`, `fqdn`, `hostname` |
|
||||
| `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` |
|
||||
|
||||
|
||||
### Example metric
|
||||
|
||||
```
|
||||
@@ -36,4 +34,4 @@ windows_os_info{build_number="19045",major_version="10",minor_version="0",produc
|
||||
_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!_
|
||||
_This collector does not yet have alerting examples, we would appreciate your help adding them!_
|
||||
|
||||
38
docs/collector.pagefile.md
Normal file
38
docs/collector.pagefile.md
Normal 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!_
|
||||
@@ -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.
|
||||
|
||||
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
|
||||
@@ -44,7 +44,7 @@ Note that multiple processes with the same name will be disambiguated by
|
||||
Windows by adding a number suffix, such as `firefox#2`. Your [regexp](https://en.wikipedia.org/wiki/Regular_expression) must take
|
||||
these suffixes into consideration.
|
||||
|
||||
:warning: The regexp is case-sensitive, so `--collector.process.include="FIREFOX.*"` will **NOT** match a process named `firefox` .
|
||||
:warning: The regexp is case-sensitive, so `--collector.process.include="FIREFOX.*"` will **NOT** match a process named `firefox` .
|
||||
|
||||
To specify multiple names, use the pipe `|` character:
|
||||
```
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
# 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`
|
||||
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
|
||||
|
||||
## Flags
|
||||
@@ -15,18 +14,18 @@ None
|
||||
|
||||
## Metrics
|
||||
|
||||
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_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_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_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_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_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
|
||||
| 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_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_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_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_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_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
|
||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||
|
||||
@@ -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).
|
||||
|
||||
| | |
|
||||
|---------------------|---------|
|
||||
| Metric name prefix | `time` |
|
||||
| Data source | Perflib |
|
||||
| Enabled by default? | No |
|
||||
| | |
|
||||
|---------------------|--------|
|
||||
| Metric name prefix | `time` |
|
||||
| Data source | PDH |
|
||||
| Enabled by default? | No |
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
31
docs/collector.udp.md
Normal file
31
docs/collector.udp.md
Normal 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!_
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
The vmware collector exposes metrics about a VMware guest VM
|
||||
|
||||
|||
|
||||
-|-
|
||||
Metric name prefix | `vmware`
|
||||
Classes | `Win32_PerfRawData_vmGuestLib_VMem`, `Win32_PerfRawData_vmGuestLib_VCPU`
|
||||
Enabled by default? | No
|
||||
| | |
|
||||
|---------------------|----------------------|
|
||||
| Metric name prefix | `vmware` |
|
||||
| Source | Performance counters |
|
||||
| Enabled by default? | No |
|
||||
|
||||
## Flags
|
||||
|
||||
@@ -14,27 +14,27 @@ None
|
||||
|
||||
## Metrics
|
||||
|
||||
Name | Description | Type | Labels
|
||||
-----|-------------|------|-------
|
||||
`windows_vmware_mem_active_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_ballooned_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_limit_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_mapped_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_overhead_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_reservation_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_shared_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_shared_saved_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_shares` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_swapped_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_target_size_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_mem_used_bytes` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_cpu_limit_mhz` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_cpu_reservation_mhz` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_cpu_shares` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_cpu_stolen_seconds_total` | _Not yet documented_ | counter | None
|
||||
`windows_vmware_cpu_time_seconds_total` | _Not yet documented_ | counter | None
|
||||
`windows_vmware_effective_vm_speed_mhz` | _Not yet documented_ | gauge | None
|
||||
`windows_vmware_host_processor_speed_mhz` | _Not yet documented_ | gauge | None
|
||||
| Name | Description | Type | Labels |
|
||||
|---------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
|
||||
| `windows_vmware_mem_active_bytes` | The estimated amount of memory the virtual machine is actively using. | 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` | 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` | 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` | The amount of overhead memory associated with this virtual machine consumed on the host system. | 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` | 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` | 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` | The number of memory shares allocated to the virtual machine. | 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` | Memory Target Size | gauge | None |
|
||||
| `windows_vmware_mem_used_bytes` | The estimated amount of physical host memory currently consumed for this virtual machine’s physical memory. | 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` | 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` | The number of CPU shares allocated to the virtual machine. | gauge | 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` | Current load of the VM’s virtual processor | counter | None |
|
||||
| `windows_vmware_cpu_effective_vm_speed_mhz` | The effective speed of the VM’s virtual CPU | gauge | None |
|
||||
| `windows_vmware_host_processor_speed_mhz` | Host Processor speed | gauge | None |
|
||||
|
||||
### Example metric
|
||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||
|
||||
16
exporter.go
16
exporter.go
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/httphandler"
|
||||
"github.com/prometheus-community/windows_exporter/internal/log"
|
||||
"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/utils"
|
||||
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
||||
@@ -96,6 +97,11 @@ func run() int {
|
||||
"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\"]",
|
||||
).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{}
|
||||
@@ -173,6 +179,12 @@ func run() int {
|
||||
|
||||
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 {
|
||||
printCollectorsToStdout()
|
||||
|
||||
@@ -215,10 +227,6 @@ func run() int {
|
||||
|
||||
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.Handle("GET /health", httphandler.NewHealthHandler())
|
||||
mux.Handle("GET /version", httphandler.NewVersionHandler())
|
||||
|
||||
2
go.mod
2
go.mod
@@ -14,7 +14,7 @@ require (
|
||||
github.com/prometheus/common v0.60.1
|
||||
github.com/prometheus/exporter-toolkit v0.13.1
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
4
go.sum
4
go.sum
@@ -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-20220715151400-c0bba94af5f8/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.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -63,7 +64,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -75,7 +76,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
requestsPerSecond,
|
||||
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 {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return c.collectPDH(ch)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -96,7 +96,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
adLoginConnectionFailures,
|
||||
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 {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return c.collectPDH(ch)
|
||||
}
|
||||
|
||||
|
||||
8
internal/collector/cache/cache.go
vendored
8
internal/collector/cache/cache.go
vendored
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
"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/toggle"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -81,7 +81,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
asyncCopyReadsTotal,
|
||||
asyncDataMapsTotal,
|
||||
@@ -314,7 +314,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
|
||||
// Collect implements the Collector interface.
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -67,7 +68,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -79,7 +80,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
c1TimeSeconds,
|
||||
c2TimeSeconds,
|
||||
@@ -108,7 +109,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) 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 {
|
||||
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 {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return c.collectPDH(ch)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -148,7 +148,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
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.")
|
||||
|
||||
//nolint:nestif
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
var err error
|
||||
|
||||
if slices.Contains(c.config.CollectorsEnabled, "connection") {
|
||||
@@ -567,7 +567,7 @@ func (c *Collector) getDFSRChildCollectors(enabledCollectors []string) []dfsrCol
|
||||
// Collect implements the Collector interface.
|
||||
// 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 {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return c.collectPDH(ch)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
"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/toggle"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -77,7 +77,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
acksTotal,
|
||||
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 {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return c.collectPDH(ch)
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"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/toggle"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -185,7 +185,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
collectorFuncs := map[string]func() error{
|
||||
adAccessProcesses: c.buildADAccessProcesses,
|
||||
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.
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ const (
|
||||
percentDiskWriteTime = "% Disk Write Time"
|
||||
percentFreeSpace = "% Free Space"
|
||||
percentIdleTime = "% Idle Time"
|
||||
SplitIOPerSec = "Split IO/Sec"
|
||||
splitIOPerSec = "Split IO/Sec"
|
||||
)
|
||||
|
||||
// Win32_PerfRawData_PerfDisk_LogicalDisk docs:
|
||||
|
||||
@@ -4,7 +4,6 @@ package logical_disk
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
@@ -17,8 +16,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
"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/toggle"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
@@ -130,7 +129,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -142,7 +141,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
currentDiskQueueLength,
|
||||
avgDiskReadQueueLength,
|
||||
@@ -156,7 +155,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
percentFreeSpace,
|
||||
freeSpace,
|
||||
percentIdleTime,
|
||||
SplitIOPerSec,
|
||||
splitIOPerSec,
|
||||
avgDiskSecPerRead,
|
||||
avgDiskSecPerWrite,
|
||||
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 {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
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)
|
||||
}
|
||||
|
||||
if len(perfData) == 0 {
|
||||
return errors.New("perflib query for LogicalDisk returned empty result set")
|
||||
}
|
||||
|
||||
for name, volume := range perfData {
|
||||
if name == "_Total" ||
|
||||
c.config.VolumeExclude.MatchString(name) ||
|
||||
@@ -453,7 +448,7 @@ func (c *Collector) collectPDH(logger *slog.Logger, ch chan<- prometheus.Metric)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.splitIOs,
|
||||
prometheus.CounterValue,
|
||||
volume[SplitIOPerSec].FirstValue,
|
||||
volume[splitIOPerSec].FirstValue,
|
||||
name,
|
||||
)
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
"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/toggle"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus-community/windows_exporter/internal/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -94,7 +94,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
availableBytes,
|
||||
availableKBytes,
|
||||
@@ -386,7 +386,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
|
||||
errs := make([]error, 0, 2)
|
||||
|
||||
var err error
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
err = c.collectPDH(ch)
|
||||
} else {
|
||||
err = c.collectPerformanceData(ctx, logger, ch)
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/mi"
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
@@ -138,7 +138,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@ func (c *Collector) Close(_ *slog.Logger) error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
BytesReceivedPerSec,
|
||||
BytesSentPerSec,
|
||||
@@ -283,7 +283,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch ch
|
||||
if slices.Contains(c.config.CollectorsEnabled, "metrics") {
|
||||
var err error
|
||||
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
err = c.collectPDH(ch)
|
||||
} else {
|
||||
err = c.collect(ctx, logger, ch)
|
||||
|
||||
@@ -34,9 +34,14 @@ var ConfigDefaults = Config{}
|
||||
type Collector struct {
|
||||
config Config
|
||||
|
||||
hostname *prometheus.Desc
|
||||
osInformation *prometheus.Desc
|
||||
pagingFreeBytes *prometheus.Desc
|
||||
hostname *prometheus.Desc
|
||||
osInformation *prometheus.Desc
|
||||
|
||||
// pagingFreeBytes
|
||||
// Deprecated: Use windows_paging_free_bytes instead.
|
||||
pagingFreeBytes *prometheus.Desc
|
||||
// pagingLimitBytes
|
||||
// Deprecated: Use windows_paging_total_bytes instead.
|
||||
pagingLimitBytes *prometheus.Desc
|
||||
|
||||
// users
|
||||
@@ -151,13 +156,13 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
)
|
||||
c.pagingLimitBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "paging_limit_bytes"),
|
||||
"OperatingSystem.SizeStoredInPagingFiles",
|
||||
"Deprecated: Use windows_pagefile_limit_bytes instead.",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
c.pagingFreeBytes = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "paging_free_bytes"),
|
||||
"OperatingSystem.FreeSpaceInPagingFiles",
|
||||
"Deprecated: Use windows_pagefile_free_bytes instead.",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
|
||||
5
internal/collector/pagefile/const.go
Normal file
5
internal/collector/pagefile/const.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package pagefile
|
||||
|
||||
const (
|
||||
usage = "% Usage"
|
||||
)
|
||||
136
internal/collector/pagefile/pagefile.go
Normal file
136
internal/collector/pagefile/pagefile.go
Normal 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
|
||||
}
|
||||
16
internal/collector/pagefile/pagefile_test.go
Normal file
16
internal/collector/pagefile/pagefile_test.go
Normal 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)
|
||||
}
|
||||
16
internal/collector/physical_disk/const.go
Normal file
16
internal/collector/physical_disk/const.go
Normal 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"
|
||||
)
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"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"
|
||||
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
@@ -32,6 +32,8 @@ var ConfigDefaults = Config{
|
||||
type Collector struct {
|
||||
config Config
|
||||
|
||||
perfDataCollector perfdata.Collector
|
||||
|
||||
idleTime *prometheus.Desc
|
||||
readBytesTotal *prometheus.Desc
|
||||
readLatency *prometheus.Desc
|
||||
@@ -107,7 +109,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
return []string{"PhysicalDisk"}, nil
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
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(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "requests_queued"),
|
||||
"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
|
||||
// to the provided prometheus Metric channel.
|
||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
if err := c.collect(ctx, logger, ch); err != nil {
|
||||
logger.Error("failed collecting physical_disk metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
if err := c.collect(ch); err != nil {
|
||||
return fmt.Errorf("failed collecting physical_disk metrics: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PhysicalDisk
|
||||
// Win32_PerfRawData_PerfDisk_PhysicalDisk docs:
|
||||
// - https://docs.microsoft.com/en-us/previous-versions/aa394308(v=vs.85) - Win32_PerfRawData_PerfDisk_PhysicalDisk class.
|
||||
type PhysicalDisk struct {
|
||||
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
|
||||
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||
perfData, err := c.perfDataCollector.Collect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect PhysicalDisk metrics: %w", err)
|
||||
}
|
||||
|
||||
for _, disk := range dst {
|
||||
if disk.Name == "_Total" ||
|
||||
c.config.DiskExclude.MatchString(disk.Name) ||
|
||||
!c.config.DiskInclude.MatchString(disk.Name) {
|
||||
for name, disk := range perfData {
|
||||
if c.config.DiskExclude.MatchString(name) ||
|
||||
!c.config.DiskInclude.MatchString(name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Parse physical disk number from disk.Name. Mountpoint information is
|
||||
// sometimes included, e.g. "1 C:".
|
||||
disk_number, _, _ := strings.Cut(disk.Name, " ")
|
||||
disk_number, _, _ := strings.Cut(name, " ")
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.requestsQueued,
|
||||
prometheus.GaugeValue,
|
||||
disk.CurrentDiskQueueLength,
|
||||
disk[CurrentDiskQueueLength].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.readBytesTotal,
|
||||
prometheus.CounterValue,
|
||||
disk.DiskReadBytesPerSec,
|
||||
disk[DiskReadBytesPerSec].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.readsTotal,
|
||||
prometheus.CounterValue,
|
||||
disk.DiskReadsPerSec,
|
||||
disk[DiskReadsPerSec].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.writeBytesTotal,
|
||||
prometheus.CounterValue,
|
||||
disk.DiskWriteBytesPerSec,
|
||||
disk[DiskWriteBytesPerSec].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.writesTotal,
|
||||
prometheus.CounterValue,
|
||||
disk.DiskWritesPerSec,
|
||||
disk[DiskWritesPerSec].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.readTime,
|
||||
prometheus.CounterValue,
|
||||
disk.PercentDiskReadTime,
|
||||
disk[PercentDiskReadTime].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.writeTime,
|
||||
prometheus.CounterValue,
|
||||
disk.PercentDiskWriteTime,
|
||||
disk[PercentDiskWriteTime].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.idleTime,
|
||||
prometheus.CounterValue,
|
||||
disk.PercentIdleTime,
|
||||
disk[PercentIdleTime].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.splitIOs,
|
||||
prometheus.CounterValue,
|
||||
disk.SplitIOPerSec,
|
||||
disk[SplitIOPerSec].FirstValue,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.readLatency,
|
||||
prometheus.CounterValue,
|
||||
disk.AvgDiskSecPerRead*perftypes.TicksToSecondScaleFactor,
|
||||
disk[AvgDiskSecPerRead].FirstValue*perftypes.TicksToSecondScaleFactor,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.writeLatency,
|
||||
prometheus.CounterValue,
|
||||
disk.AvgDiskSecPerWrite*perftypes.TicksToSecondScaleFactor,
|
||||
disk[AvgDiskSecPerWrite].FirstValue*perftypes.TicksToSecondScaleFactor,
|
||||
disk_number,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.readWriteLatency,
|
||||
prometheus.CounterValue,
|
||||
disk.AvgDiskSecPerTransfer*perftypes.TicksToSecondScaleFactor,
|
||||
disk[AvgDiskSecPerTransfer].FirstValue*perftypes.TicksToSecondScaleFactor,
|
||||
disk_number,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
|
||||
"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/types"
|
||||
)
|
||||
|
||||
func BenchmarkCollector(b *testing.B) {
|
||||
@@ -12,7 +13,7 @@ func BenchmarkCollector(b *testing.B) {
|
||||
}
|
||||
|
||||
func TestCollector(t *testing.T) {
|
||||
t.Skip()
|
||||
|
||||
testutils.TestCollector(t, physical_disk.New, nil)
|
||||
testutils.TestCollector(t, physical_disk.New, &physical_disk.Config{
|
||||
DiskInclude: types.RegExpAny,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ import (
|
||||
"github.com/prometheus-community/windows_exporter/internal/perfdata"
|
||||
v1 "github.com/prometheus-community/windows_exporter/internal/perfdata/v1"
|
||||
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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
@@ -130,7 +130,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
|
||||
c.workerProcessMIQueryQuery = miQuery
|
||||
c.miSession = miSession
|
||||
|
||||
if utils.PDHEnabled() {
|
||||
if toggle.IsPDHEnabled() {
|
||||
counters := []string{
|
||||
processID,
|
||||
percentProcessorTime,
|
||||
@@ -315,7 +315,7 @@ type WorkerProcess struct {
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,3 +10,7 @@ import (
|
||||
func BenchmarkCollector(b *testing.B) {
|
||||
testutils.FuncBenchmarkCollector(b, service.Name, service.NewWithFlags)
|
||||
}
|
||||
|
||||
func TestCollector(t *testing.T) {
|
||||
testutils.TestCollector(t, service.New, nil)
|
||||
}
|
||||
|
||||
11
internal/collector/system/const.go
Normal file
11
internal/collector/system/const.go
Normal 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"
|
||||
)
|
||||
@@ -4,11 +4,13 @@ package system
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"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/client_golang/prometheus"
|
||||
)
|
||||
@@ -23,6 +25,8 @@ var ConfigDefaults = Config{}
|
||||
type Collector struct {
|
||||
config Config
|
||||
|
||||
perfDataCollector perfdata.Collector
|
||||
|
||||
contextSwitchesTotal *prometheus.Desc
|
||||
exceptionDispatchesTotal *prometheus.Desc
|
||||
processorQueueLength *prometheus.Desc
|
||||
@@ -54,7 +58,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
return []string{"System"}, nil
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
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 {
|
||||
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(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"),
|
||||
"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
|
||||
// to the provided prometheus Metric channel.
|
||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
if err := c.collect(ctx, logger, ch); err != nil {
|
||||
logger.Error("failed collecting system metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
if err := c.collect(ch); err != nil {
|
||||
return fmt.Errorf("failed collecting system metrics: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Win32_PerfRawData_PerfOS_System docs:
|
||||
// - https://web.archive.org/web/20050830140516/http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_perfrawdata_perfos_system.asp
|
||||
type system struct {
|
||||
ContextSwitchesPersec float64 `perflib:"Context Switches/sec"`
|
||||
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
|
||||
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||
perfData, err := c.perfDataCollector.Collect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect System metrics: %w", err)
|
||||
}
|
||||
|
||||
if len(dst) == 0 {
|
||||
return errors.New("no data returned from Performance Counter")
|
||||
data, ok := perfData[perftypes.EmptyInstance]
|
||||
if !ok {
|
||||
return errors.New("query for System returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.contextSwitchesTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].ContextSwitchesPersec,
|
||||
data[ContextSwitchesPersec].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.exceptionDispatchesTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].ExceptionDispatchesPersec,
|
||||
data[ExceptionDispatchesPersec].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.processorQueueLength,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].ProcessorQueueLength,
|
||||
data[ProcessorQueueLength].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.processes,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].Processes,
|
||||
data[Processes].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.systemCallsTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].SystemCallsPersec,
|
||||
data[SystemCallsPersec].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.systemUpTime,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].SystemUpTime,
|
||||
data[SystemUpTime].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.threads,
|
||||
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.
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
@@ -97,6 +98,11 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
}
|
||||
|
||||
func (c *Collector) Close(_ *slog.Logger) error {
|
||||
if slices.Contains(c.config.CollectorsEnabled, "metrics") {
|
||||
c.perfDataCollector4.Close()
|
||||
c.perfDataCollector6.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -115,12 +121,12 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) 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 {
|
||||
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 {
|
||||
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
|
||||
// to the provided prometheus Metric channel.
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
errs := make([]error, 0, 2)
|
||||
|
||||
if slices.Contains(c.config.CollectorsEnabled, "metrics") {
|
||||
if err := c.collect(ch); err != nil {
|
||||
logger.Error("failed collecting tcp metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
errs = append(errs, fmt.Errorf("failed collecting tcp metrics: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if slices.Contains(c.config.CollectorsEnabled, "connections_state") {
|
||||
if err := c.collectConnectionsState(ch); err != nil {
|
||||
logger.Error("failed collecting tcp connection state metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
errs = append(errs, fmt.Errorf("failed collecting tcp connection state metrics: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||
|
||||
23
internal/collector/terminal_services/const.go
Normal file
23
internal/collector/terminal_services/const.go
Normal 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"
|
||||
)
|
||||
@@ -12,7 +12,8 @@ import (
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"github.com/prometheus-community/windows_exporter/internal/headers/wtsapi32"
|
||||
"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/utils"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
@@ -32,7 +33,7 @@ type Win32_ServerFeature struct {
|
||||
ID uint32
|
||||
}
|
||||
|
||||
func isConnectionBrokerServer(logger *slog.Logger, miSession *mi.Session) bool {
|
||||
func isConnectionBrokerServer(miSession *mi.Session) bool {
|
||||
var dst []Win32_ServerFeature
|
||||
if err := miSession.Query(&dst, mi.NamespaceRootCIMv2, utils.Must(mi.NewQuery("SELECT * FROM Win32_ServerFeature"))); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -58,6 +57,9 @@ type Collector struct {
|
||||
|
||||
connectionBrokerEnabled bool
|
||||
|
||||
perfDataCollectorTerminalServicesSession perfdata.Collector
|
||||
perfDataCollectorBroker perfdata.Collector
|
||||
|
||||
hServer windows.Handle
|
||||
|
||||
sessionInfo *prometheus.Desc
|
||||
@@ -98,10 +100,7 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
return []string{
|
||||
"Terminal Services Session",
|
||||
"Remote Desktop Connection Broker Counterset",
|
||||
}, nil
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
c.perfDataCollectorTerminalServicesSession.Close()
|
||||
|
||||
if c.connectionBrokerEnabled {
|
||||
c.perfDataCollectorBroker.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -120,7 +125,49 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
|
||||
|
||||
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(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "session_info"),
|
||||
@@ -213,8 +260,6 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
|
||||
nil,
|
||||
)
|
||||
|
||||
var err error
|
||||
|
||||
c.hServer, err = wtsapi32.WTSOpenServer("")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open WTS server: %w", err)
|
||||
@@ -225,71 +270,40 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
|
||||
|
||||
// Collect sends the 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(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
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 {
|
||||
logger.Error("failed collecting terminal services session count metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
if err := c.collectTSSessionCounters(ch); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed collecting terminal services session count metrics: %w", err))
|
||||
}
|
||||
|
||||
// only collect CollectionBrokerPerformance if host is a Connection Broker
|
||||
if c.connectionBrokerEnabled {
|
||||
if err := c.collectCollectionBrokerPerformanceCounter(ctx, logger, ch); err != nil {
|
||||
logger.Error("failed collecting Connection Broker performance metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
if err := c.collectCollectionBrokerPerformanceCounter(ch); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed collecting Connection Broker performance metrics: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
type perflibTerminalServicesSession struct {
|
||||
Name string
|
||||
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)
|
||||
func (c *Collector) collectTSSessionCounters(ch chan<- prometheus.Metric) error {
|
||||
perfData, err := c.perfDataCollectorTerminalServicesSession.Collect()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to collect Terminal Services Session metrics: %w", err)
|
||||
}
|
||||
|
||||
names := make(map[string]bool)
|
||||
|
||||
for _, d := range dst {
|
||||
for name, data := range perfData {
|
||||
// only connect metrics for remote named sessions
|
||||
n := strings.ToLower(d.Name)
|
||||
n := strings.ToLower(name)
|
||||
if n == "" || n == "services" || n == "console" {
|
||||
continue
|
||||
}
|
||||
@@ -303,138 +317,130 @@ func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger *s
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.handleCount,
|
||||
prometheus.GaugeValue,
|
||||
d.HandleCount,
|
||||
d.Name,
|
||||
data[handleCount].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.pageFaultsPerSec,
|
||||
prometheus.CounterValue,
|
||||
d.PageFaultsPersec,
|
||||
d.Name,
|
||||
data[pageFaultsPersec].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.pageFileBytes,
|
||||
prometheus.GaugeValue,
|
||||
d.PageFileBytes,
|
||||
d.Name,
|
||||
data[pageFileBytes].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.pageFileBytesPeak,
|
||||
prometheus.GaugeValue,
|
||||
d.PageFileBytesPeak,
|
||||
d.Name,
|
||||
data[pageFileBytesPeak].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.percentCPUTime,
|
||||
prometheus.CounterValue,
|
||||
d.PercentPrivilegedTime,
|
||||
d.Name,
|
||||
data[percentPrivilegedTime].FirstValue,
|
||||
name,
|
||||
"privileged",
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.percentCPUTime,
|
||||
prometheus.CounterValue,
|
||||
d.PercentProcessorTime,
|
||||
d.Name,
|
||||
data[percentProcessorTime].FirstValue,
|
||||
name,
|
||||
"processor",
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.percentCPUTime,
|
||||
prometheus.CounterValue,
|
||||
d.PercentUserTime,
|
||||
d.Name,
|
||||
data[percentUserTime].FirstValue,
|
||||
name,
|
||||
"user",
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.poolNonPagedBytes,
|
||||
prometheus.GaugeValue,
|
||||
d.PoolNonpagedBytes,
|
||||
d.Name,
|
||||
data[poolNonpagedBytes].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.poolPagedBytes,
|
||||
prometheus.GaugeValue,
|
||||
d.PoolPagedBytes,
|
||||
d.Name,
|
||||
data[poolPagedBytes].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.privateBytes,
|
||||
prometheus.GaugeValue,
|
||||
d.PrivateBytes,
|
||||
d.Name,
|
||||
data[privateBytes].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.threadCount,
|
||||
prometheus.GaugeValue,
|
||||
d.ThreadCount,
|
||||
d.Name,
|
||||
data[threadCount].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.virtualBytes,
|
||||
prometheus.GaugeValue,
|
||||
d.VirtualBytes,
|
||||
d.Name,
|
||||
data[virtualBytes].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.virtualBytesPeak,
|
||||
prometheus.GaugeValue,
|
||||
d.VirtualBytesPeak,
|
||||
d.Name,
|
||||
data[virtualBytesPeak].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.workingSet,
|
||||
prometheus.GaugeValue,
|
||||
d.WorkingSet,
|
||||
d.Name,
|
||||
data[workingSet].FirstValue,
|
||||
name,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.workingSetPeak,
|
||||
prometheus.GaugeValue,
|
||||
d.WorkingSetPeak,
|
||||
d.Name,
|
||||
data[workingSetPeak].FirstValue,
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type perflibRemoteDesktopConnectionBrokerCounterset struct {
|
||||
SuccessfulConnections float64 `perflib:"Successful Connections"`
|
||||
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)
|
||||
func (c *Collector) collectCollectionBrokerPerformanceCounter(ch chan<- prometheus.Metric) error {
|
||||
perfData, err := c.perfDataCollectorBroker.Collect()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to collect Remote Desktop Connection Broker Counterset metrics: %w", err)
|
||||
}
|
||||
|
||||
if len(dst) == 0 {
|
||||
return errors.New("WMI query returned empty result set")
|
||||
data, ok := perfData[perftypes.EmptyInstance]
|
||||
if !ok {
|
||||
return errors.New("query for Remote Desktop Connection Broker Counterset returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.connectionBrokerPerformance,
|
||||
prometheus.CounterValue,
|
||||
dst[0].SuccessfulConnections,
|
||||
data[successfulConnections].FirstValue,
|
||||
"Successful",
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.connectionBrokerPerformance,
|
||||
prometheus.CounterValue,
|
||||
dst[0].PendingConnections,
|
||||
data[pendingConnections].FirstValue,
|
||||
"Pending",
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.connectionBrokerPerformance,
|
||||
prometheus.CounterValue,
|
||||
dst[0].FailedConnections,
|
||||
data[failedConnections].FirstValue,
|
||||
"Failed",
|
||||
)
|
||||
|
||||
@@ -448,6 +454,12 @@ func (c *Collector) collectWTSSessions(logger *slog.Logger, ch chan<- prometheus
|
||||
}
|
||||
|
||||
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
|
||||
if session.DomainName != "" {
|
||||
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 {
|
||||
isState = 1.0
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.sessionInfo,
|
||||
prometheus.GaugeValue,
|
||||
isState,
|
||||
strings.ReplaceAll(session.SessionName, "#", " "),
|
||||
n,
|
||||
userName,
|
||||
session.HostName,
|
||||
stateName,
|
||||
|
||||
10
internal/collector/time/const.go
Normal file
10
internal/collector/time/const.go
Normal 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"
|
||||
)
|
||||
@@ -4,28 +4,46 @@ package time
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"github.com/prometheus-community/windows_exporter/internal/headers/kernel32"
|
||||
"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/client_golang/prometheus"
|
||||
"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.
|
||||
type Collector struct {
|
||||
config Config
|
||||
|
||||
perfDataCollector perfdata.Collector
|
||||
|
||||
currentTime *prometheus.Desc
|
||||
timezone *prometheus.Desc
|
||||
clockFrequencyAdjustmentPPBTotal *prometheus.Desc
|
||||
@@ -41,6 +59,10 @@ func New(config *Config) *Collector {
|
||||
config = &ConfigDefaults
|
||||
}
|
||||
|
||||
if config.CollectorsEnabled == nil {
|
||||
config.CollectorsEnabled = ConfigDefaults.CollectorsEnabled
|
||||
}
|
||||
|
||||
c := &Collector{
|
||||
config: *config,
|
||||
}
|
||||
@@ -48,8 +70,26 @@ func New(config *Config) *Collector {
|
||||
return c
|
||||
}
|
||||
|
||||
func NewWithFlags(_ *kingpin.Application) *Collector {
|
||||
return &Collector{}
|
||||
func NewWithFlags(app *kingpin.Application) *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 {
|
||||
@@ -57,14 +97,40 @@ func (c *Collector) GetName() string {
|
||||
}
|
||||
|
||||
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
return []string{"Windows Time Service"}, nil
|
||||
return []string{}, nil
|
||||
}
|
||||
|
||||
func (c *Collector) Close(_ *slog.Logger) error {
|
||||
if slices.Contains(c.config.CollectorsEnabled, collectorNTP) {
|
||||
c.perfDataCollector.Close()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"),
|
||||
"OperatingSystem.LocalDateTime",
|
||||
@@ -119,40 +185,24 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
|
||||
// Collect sends the 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 {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
errs := make([]error, 0, 2)
|
||||
|
||||
if err := c.collectTime(ch); err != nil {
|
||||
logger.Error("failed collecting time metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
errs = append(errs, err)
|
||||
if slices.Contains(c.config.CollectorsEnabled, collectorSystemTime) {
|
||||
if err := c.collectTime(ch); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed collecting time metrics: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.collectNTP(ctx, logger, ch); err != nil {
|
||||
logger.Error("failed collecting time ntp metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
errs = append(errs, err)
|
||||
if slices.Contains(c.config.CollectorsEnabled, collectorNTP) {
|
||||
if err := c.collectNTP(ch); err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed collecting time ntp metrics: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.currentTime,
|
||||
@@ -178,48 +228,46 @@ func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Collector) collectNTP(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
|
||||
var dst []windowsTime // Single-instance class, array is required but will have single entry.
|
||||
|
||||
if err := v1.UnmarshalObject(ctx.PerfObjects["Windows Time Service"], &dst, logger); err != nil {
|
||||
return err
|
||||
func (c *Collector) collectNTP(ch chan<- prometheus.Metric) error {
|
||||
perfData, err := c.perfDataCollector.Collect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
|
||||
}
|
||||
|
||||
if len(dst) == 0 {
|
||||
return errors.New("no data returned for Windows Time Service")
|
||||
data, ok := perfData[perftypes.EmptyInstance]
|
||||
if !ok {
|
||||
return errors.New("query for Windows Time Service returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.clockFrequencyAdjustmentPPBTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].ClockFrequencyAdjustmentPPBTotal,
|
||||
data[ClockFrequencyAdjustmentPPBTotal].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.computedTimeOffset,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].ComputedTimeOffset/1000000, // microseconds -> seconds
|
||||
data[ComputedTimeOffset].FirstValue/1000000, // microseconds -> seconds
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.ntpClientTimeSourceCount,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].NTPClientTimeSourceCount,
|
||||
data[NTPClientTimeSourceCount].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.ntpRoundTripDelay,
|
||||
prometheus.GaugeValue,
|
||||
dst[0].NTPRoundTripDelay/1000000, // microseconds -> seconds
|
||||
data[NTPRoundTripDelay].FirstValue/1000000, // microseconds -> seconds
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.ntpServerIncomingRequestsTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].NTPServerIncomingRequestsTotal,
|
||||
data[NTPServerIncomingRequestsTotal].FirstValue,
|
||||
)
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.ntpServerOutgoingResponsesTotal,
|
||||
prometheus.CounterValue,
|
||||
dst[0].NTPServerOutgoingResponsesTotal,
|
||||
data[NTPServerOutgoingResponsesTotal].FirstValue,
|
||||
)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -10,3 +10,7 @@ import (
|
||||
func BenchmarkCollector(b *testing.B) {
|
||||
testutils.FuncBenchmarkCollector(b, time.Name, time.NewWithFlags)
|
||||
}
|
||||
|
||||
func TestCollector(t *testing.T) {
|
||||
testutils.TestCollector(t, time.New, nil)
|
||||
}
|
||||
|
||||
15
internal/collector/udp/const.go
Normal file
15
internal/collector/udp/const.go
Normal 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.
|
||||
168
internal/collector/udp/udp.go
Normal file
168
internal/collector/udp/udp.go
Normal 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...,
|
||||
)
|
||||
}
|
||||
16
internal/collector/udp/udp_test.go
Normal file
16
internal/collector/udp/udp_test.go
Normal 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)
|
||||
}
|
||||
24
internal/collector/vmware/const.go
Normal file
24
internal/collector/vmware/const.go
Normal 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
|
||||
)
|
||||
@@ -9,8 +9,10 @@ import (
|
||||
|
||||
"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-community/windows_exporter/internal/utils"
|
||||
"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.
|
||||
type Collector struct {
|
||||
config Config
|
||||
miSession *mi.Session
|
||||
miQueryCPU mi.Query
|
||||
miQueryMem mi.Query
|
||||
config Config
|
||||
perfDataCollectorCPU perfdata.Collector
|
||||
perfDataCollectorMemory perfdata.Collector
|
||||
|
||||
memActive *prometheus.Desc
|
||||
memBallooned *prometheus.Desc
|
||||
@@ -40,13 +41,13 @@ type Collector struct {
|
||||
memTargetSize *prometheus.Desc
|
||||
memUsed *prometheus.Desc
|
||||
|
||||
cpuLimitMHz *prometheus.Desc
|
||||
cpuReservationMHz *prometheus.Desc
|
||||
cpuShares *prometheus.Desc
|
||||
cpuStolenTotal *prometheus.Desc
|
||||
cpuTimeTotal *prometheus.Desc
|
||||
effectiveVMSpeedMHz *prometheus.Desc
|
||||
hostProcessorSpeedMHz *prometheus.Desc
|
||||
cpuLimitMHz *prometheus.Desc
|
||||
cpuReservationMHz *prometheus.Desc
|
||||
cpuShares *prometheus.Desc
|
||||
cpuStolenTotal *prometheus.Desc
|
||||
cpuTimeTotal *prometheus.Desc
|
||||
cpuEffectiveVMSpeedMHz *prometheus.Desc
|
||||
hostProcessorSpeedMHz *prometheus.Desc
|
||||
}
|
||||
|
||||
func New(config *Config) *Collector {
|
||||
@@ -74,141 +75,162 @@ func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||
}
|
||||
|
||||
func (c *Collector) Close(_ *slog.Logger) error {
|
||||
c.perfDataCollectorCPU.Close()
|
||||
c.perfDataCollectorMemory.Close()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
|
||||
if miSession == nil {
|
||||
return errors.New("miSession is nil")
|
||||
func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
|
||||
counters := []string{
|
||||
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 {
|
||||
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(
|
||||
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,
|
||||
)
|
||||
c.cpuReservationMHz = prometheus.NewDesc(
|
||||
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,
|
||||
)
|
||||
c.cpuShares = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "cpu_shares"),
|
||||
"(CpuShares)",
|
||||
"The number of CPU shares allocated to the virtual machine.",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
c.cpuStolenTotal = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "cpu_stolen_seconds_total"),
|
||||
"(CpuStolenMs)",
|
||||
"The time that the VM was runnable but not scheduled to run.",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
c.cpuTimeTotal = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "cpu_time_seconds_total"),
|
||||
"(CpuTimePercents)",
|
||||
"Current load of the VM’s virtual processor",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
c.effectiveVMSpeedMHz = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "effective_vm_speed_mhz"),
|
||||
"(EffectiveVMSpeedMHz)",
|
||||
c.cpuEffectiveVMSpeedMHz = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "cpu_effective_vm_speed_mhz_total"),
|
||||
"The effective speed of the VM’s virtual CPU",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
c.hostProcessorSpeedMHz = prometheus.NewDesc(
|
||||
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 machine’s physical memory.",
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
@@ -218,192 +240,157 @@ func (c *Collector) Build(_ *slog.Logger, miSession *mi.Session) error {
|
||||
|
||||
// Collect sends the metric values for each metric
|
||||
// to the provided prometheus Metric channel.
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
if err := c.collectMem(ch); err != nil {
|
||||
logger.Error("failed collecting vmware memory metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||
errs := make([]error, 0, 2)
|
||||
|
||||
if err := c.collectCpu(ch); err != nil {
|
||||
logger.Error("failed collecting vmware cpu metrics",
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
return err
|
||||
errs = append(errs, fmt.Errorf("failed collecting vmware cpu metrics: %w", 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 {
|
||||
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"`
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (c *Collector) collectMem(ch chan<- prometheus.Metric) error {
|
||||
var dst []Win32_PerfRawData_vmGuestLib_VMem
|
||||
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryMem); err != nil {
|
||||
return fmt.Errorf("WMI query failed: %w", err)
|
||||
perfData, err := c.perfDataCollectorMemory.Collect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
|
||||
}
|
||||
|
||||
if len(dst) == 0 {
|
||||
return errors.New("WMI query returned empty result set")
|
||||
data, ok := perfData[perftypes.EmptyInstance]
|
||||
if !ok {
|
||||
return errors.New("query for VM Memory returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memActive,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemActiveMB),
|
||||
utils.MBToBytes(data[memActiveMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memBallooned,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemBalloonedMB),
|
||||
utils.MBToBytes(data[memBalloonedMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memLimit,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemLimitMB),
|
||||
utils.MBToBytes(data[memLimitMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memMapped,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemMappedMB),
|
||||
utils.MBToBytes(data[memMappedMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memOverhead,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemOverheadMB),
|
||||
utils.MBToBytes(data[memOverheadMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memReservation,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemReservationMB),
|
||||
utils.MBToBytes(data[memReservationMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memShared,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemSharedMB),
|
||||
utils.MBToBytes(data[memSharedMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memSharedSaved,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemSharedSavedMB),
|
||||
utils.MBToBytes(data[memSharedSavedMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memShares,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].MemShares),
|
||||
data[memShares].FirstValue,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memSwapped,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemSwappedMB),
|
||||
utils.MBToBytes(data[memSwappedMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memTargetSize,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemTargetSizeMB),
|
||||
utils.MBToBytes(data[memTargetSizeMB].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.memUsed,
|
||||
prometheus.GaugeValue,
|
||||
mbToBytes(dst[0].MemUsedMB),
|
||||
utils.MBToBytes(data[memUsedMB].FirstValue),
|
||||
)
|
||||
|
||||
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 {
|
||||
var dst []Win32_PerfRawData_vmGuestLib_VCPU
|
||||
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, c.miQueryCPU); err != nil {
|
||||
return fmt.Errorf("WMI query failed: %w", err)
|
||||
perfData, err := c.perfDataCollectorCPU.Collect()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to collect VM Memory metrics: %w", err)
|
||||
}
|
||||
|
||||
if len(dst) == 0 {
|
||||
return errors.New("WMI query returned empty result set")
|
||||
data, ok := perfData["_Total"]
|
||||
if !ok {
|
||||
return errors.New("query for VM CPU returned empty result set")
|
||||
}
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.cpuLimitMHz,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].CpuLimitMHz),
|
||||
data[cpuLimitMHz].FirstValue,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.cpuReservationMHz,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].CpuReservationMHz),
|
||||
data[cpuReservationMHz].FirstValue,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.cpuShares,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].CpuShares),
|
||||
data[cpuShares].FirstValue,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.cpuStolenTotal,
|
||||
prometheus.CounterValue,
|
||||
float64(dst[0].CpuStolenMs)*perftypes.TicksToSecondScaleFactor,
|
||||
utils.MilliSecToSec(data[cpuStolenMs].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.cpuTimeTotal,
|
||||
prometheus.CounterValue,
|
||||
float64(dst[0].CpuTimePercents)*perftypes.TicksToSecondScaleFactor,
|
||||
utils.MilliSecToSec(data[cpuTimePercents].FirstValue),
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.effectiveVMSpeedMHz,
|
||||
c.cpuEffectiveVMSpeedMHz,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].EffectiveVMSpeedMHz),
|
||||
data[couEffectiveVMSpeedMHz].FirstValue,
|
||||
)
|
||||
|
||||
ch <- prometheus.MustNewConstMetric(
|
||||
c.hostProcessorSpeedMHz,
|
||||
prometheus.GaugeValue,
|
||||
float64(dst[0].HostProcessorSpeedMHz),
|
||||
data[cpuHostProcessorSpeedMHz].FirstValue,
|
||||
)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package wtsapi32
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"unsafe"
|
||||
@@ -129,7 +130,7 @@ func WTSOpenServer(server string) (windows.Handle, error) {
|
||||
func WTSCloseServer(server windows.Handle) error {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -170,8 +171,7 @@ func WTSEnumerateSessionsEx(server windows.Handle, logger *slog.Logger) ([]WTSSe
|
||||
|
||||
if sessionInfoPointer != 0 {
|
||||
defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) {
|
||||
err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries)
|
||||
if err != nil {
|
||||
if err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries); err != nil {
|
||||
logger.Warn("failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err))
|
||||
}
|
||||
}(WTSTypeSessionInfoLevel1, sessionInfoPointer, count)
|
||||
|
||||
@@ -5,8 +5,10 @@ package mi
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sync"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"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.
|
||||
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(
|
||||
operation *Operation,
|
||||
callbacks *OperationUnmarshalCallbacks,
|
||||
|
||||
@@ -212,9 +212,16 @@ func (s *Session) QueryUnmarshal(dst any,
|
||||
|
||||
errs := make([]error, 0)
|
||||
|
||||
for err := range errCh {
|
||||
if err != nil {
|
||||
// We need an active go routine to prevent a
|
||||
// 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)
|
||||
} else if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
// Conversion factors.
|
||||
const (
|
||||
TicksToSecondScaleFactor = 1 / 1e7
|
||||
WindowsEpoch = 116444736000000000
|
||||
TicksToSecondScaleFactor = 1 / 1e7
|
||||
WindowsEpoch int64 = 116444736000000000
|
||||
)
|
||||
|
||||
// Based on https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go
|
||||
|
||||
@@ -4,6 +4,8 @@ import "github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
const EmptyInstance = "------"
|
||||
|
||||
var TotalInstance = []string{"_Total"}
|
||||
|
||||
type CounterValues struct {
|
||||
Type prometheus.ValueType
|
||||
FirstValue float64
|
||||
|
||||
@@ -5,6 +5,7 @@ package v2
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
@@ -14,9 +15,10 @@ import (
|
||||
)
|
||||
|
||||
type Collector struct {
|
||||
object string
|
||||
counters map[string]Counter
|
||||
handle pdhQueryHandle
|
||||
object string
|
||||
counters map[string]Counter
|
||||
handle pdhQueryHandle
|
||||
totalCounterRequested bool
|
||||
}
|
||||
|
||||
type Counter struct {
|
||||
@@ -24,7 +26,7 @@ type Counter struct {
|
||||
Desc string
|
||||
Instances map[string]pdhCounterHandle
|
||||
Type uint32
|
||||
Frequency float64
|
||||
Frequency int64
|
||||
}
|
||||
|
||||
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{
|
||||
object: object,
|
||||
counters: make(map[string]Counter, len(counters)),
|
||||
handle: handle,
|
||||
object: object,
|
||||
counters: make(map[string]Counter, len(counters)),
|
||||
handle: handle,
|
||||
totalCounterRequested: slices.Contains(instances, "_Total"),
|
||||
}
|
||||
|
||||
for _, counterName := range counters {
|
||||
@@ -67,30 +70,30 @@ func NewCollector(object string, instances []string, counters []string) (*Collec
|
||||
|
||||
counter.Instances[instance] = counterHandle
|
||||
|
||||
if counter.Type == 0 {
|
||||
// Get the info with the current buffer size
|
||||
bufLen := uint32(0)
|
||||
if counter.Type != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if ret := PdhGetCounterInfo(counterHandle, 1, &bufLen, nil); ret != PdhMoreData {
|
||||
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
|
||||
}
|
||||
// Get the info with the current buffer size
|
||||
bufLen := uint32(0)
|
||||
|
||||
buf := make([]byte, bufLen)
|
||||
if ret := PdhGetCounterInfo(counterHandle, 1, &bufLen, &buf[0]); ret != ErrorSuccess {
|
||||
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
|
||||
}
|
||||
if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, nil); ret != PdhMoreData {
|
||||
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
|
||||
}
|
||||
|
||||
ci := (*PdhCounterInfo)(unsafe.Pointer(&buf[0]))
|
||||
counter.Type = ci.DwType
|
||||
counter.Desc = windows.UTF16PtrToString(ci.SzExplainText)
|
||||
buf := make([]byte, bufLen)
|
||||
if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, &buf[0]); ret != ErrorSuccess {
|
||||
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))
|
||||
}
|
||||
|
||||
counter.Frequency = frequency
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +156,7 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
|
||||
continue
|
||||
}
|
||||
|
||||
items := (*[1 << 20]PdhRawCounterItem)(unsafe.Pointer(&buf[0]))[:itemCount]
|
||||
items := unsafe.Slice((*PdhRawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
|
||||
|
||||
if data == nil {
|
||||
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 {
|
||||
if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData {
|
||||
instanceName := windows.UTF16PtrToString(item.SzName)
|
||||
if strings.HasSuffix(instanceName, "_Total") {
|
||||
if strings.HasSuffix(instanceName, "_Total") && !c.totalCounterRequested {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -191,14 +194,14 @@ func (c *Collector) Collect() (map[string]map[string]perftypes.CounterValues, er
|
||||
|
||||
switch counter.Type {
|
||||
case perftypes.PERF_ELAPSED_TIME:
|
||||
values.FirstValue = float64(item.RawValue.FirstValue-perftypes.WindowsEpoch) / counter.Frequency
|
||||
values.SecondValue = float64(item.RawValue.SecondValue-perftypes.WindowsEpoch) / counter.Frequency
|
||||
values.FirstValue = float64((item.RawValue.FirstValue - perftypes.WindowsEpoch) / counter.Frequency)
|
||||
case perftypes.PERF_100NSEC_TIMER, perftypes.PERF_PRECISION_100NS_TIMER:
|
||||
values.FirstValue = float64(item.RawValue.FirstValue) * perftypes.TicksToSecondScaleFactor
|
||||
values.SecondValue = float64(item.RawValue.SecondValue) * perftypes.TicksToSecondScaleFactor
|
||||
default:
|
||||
case perftypes.PERF_AVERAGE_BULK:
|
||||
values.FirstValue = float64(item.RawValue.FirstValue)
|
||||
values.SecondValue = float64(item.RawValue.SecondValue)
|
||||
default:
|
||||
values.FirstValue = float64(item.RawValue.FirstValue)
|
||||
}
|
||||
|
||||
data[instanceName][counter.Name] = values
|
||||
|
||||
@@ -622,7 +622,7 @@ func PdhGetRawCounterArray(hCounter pdhCounterHandle, lpdwBufferSize *uint32, lp
|
||||
//
|
||||
// lpdwItemCount
|
||||
// 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(
|
||||
uintptr(hCounter),
|
||||
uintptr(unsafe.Pointer(pTimeBase)))
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
"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/client_golang/prometheus"
|
||||
"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) {
|
||||
t.Helper()
|
||||
t.Setenv("WINDOWS_EXPORTER_PERF_COUNTERS_ENGINE", "pdh")
|
||||
|
||||
toggle.PHDEnabled = true
|
||||
|
||||
var (
|
||||
metrics []prometheus.Metric
|
||||
|
||||
7
internal/toggle/main.go
Normal file
7
internal/toggle/main.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package toggle
|
||||
|
||||
var PHDEnabled bool
|
||||
|
||||
func IsPDHEnabled() bool {
|
||||
return PHDEnabled
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus-community/windows_exporter/internal/types"
|
||||
@@ -27,19 +26,3 @@ func ExpandEnabledCollectors(enabled string) []string {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ func MilliSecToSec(t float64) float64 {
|
||||
return t / 1000
|
||||
}
|
||||
|
||||
func MBToBytes(mb float64) float64 {
|
||||
return mb * 1024 * 1024
|
||||
}
|
||||
|
||||
func BoolToFloat(b bool) float64 {
|
||||
if b {
|
||||
return 1.0
|
||||
|
||||
@@ -39,6 +39,7 @@ import (
|
||||
"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/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/physical_disk"
|
||||
"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/thermalzone"
|
||||
"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/vmware"
|
||||
"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[nps.Name] = nps.New(&config.Nps)
|
||||
collectors[os.Name] = os.New(&config.OS)
|
||||
collectors[pagefile.Name] = pagefile.New(&config.Paging)
|
||||
collectors[perfdata.Name] = perfdata.New(&config.PerfData)
|
||||
collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk)
|
||||
collectors[printer.Name] = printer.New(&config.Printer)
|
||||
@@ -122,6 +125,7 @@ func NewWithConfig(config Config) *MetricCollectors {
|
||||
collectors[textfile.Name] = textfile.New(&config.Textfile)
|
||||
collectors[thermalzone.Name] = thermalzone.New(&config.ThermalZone)
|
||||
collectors[time.Name] = time.New(&config.Time)
|
||||
collectors[udp.Name] = udp.New(&config.UDP)
|
||||
collectors[update.Name] = update.New(&config.Update)
|
||||
collectors[vmware.Name] = vmware.New(&config.Vmware)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
"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/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/physical_disk"
|
||||
"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/thermalzone"
|
||||
"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/vmware"
|
||||
)
|
||||
@@ -78,6 +80,7 @@ type Config struct {
|
||||
NetFramework netframework.Config `yaml:"net_framework"`
|
||||
Nps nps.Config `yaml:"nps"`
|
||||
OS os.Config `yaml:"os"`
|
||||
Paging pagefile.Config `yaml:"paging"`
|
||||
PerfData perfdata.Config `yaml:"perf_data"`
|
||||
PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
|
||||
Printer printer.Config `yaml:"printer"`
|
||||
@@ -94,6 +97,7 @@ type Config struct {
|
||||
Textfile textfile.Config `yaml:"textfile"`
|
||||
ThermalZone thermalzone.Config `yaml:"thermal_zone"`
|
||||
Time time.Config `yaml:"time"`
|
||||
UDP udp.Config `yaml:"udp"`
|
||||
Update update.Config `yaml:"update"`
|
||||
Vmware vmware.Config `yaml:"vmware"`
|
||||
}
|
||||
@@ -130,6 +134,7 @@ var ConfigDefaults = Config{
|
||||
NetFramework: netframework.ConfigDefaults,
|
||||
Nps: nps.ConfigDefaults,
|
||||
OS: os.ConfigDefaults,
|
||||
Paging: pagefile.ConfigDefaults,
|
||||
PerfData: perfdata.ConfigDefaults,
|
||||
PhysicalDisk: physical_disk.ConfigDefaults,
|
||||
Printer: printer.ConfigDefaults,
|
||||
@@ -146,6 +151,7 @@ var ConfigDefaults = Config{
|
||||
Textfile: textfile.ConfigDefaults,
|
||||
ThermalZone: thermalzone.ConfigDefaults,
|
||||
Time: time.ConfigDefaults,
|
||||
UDP: udp.ConfigDefaults,
|
||||
Update: update.ConfigDefaults,
|
||||
Vmware: vmware.ConfigDefaults,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import (
|
||||
"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/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/physical_disk"
|
||||
"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/thermalzone"
|
||||
"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/vmware"
|
||||
)
|
||||
@@ -88,6 +90,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
|
||||
netframework.Name: NewBuilderWithFlags(netframework.NewWithFlags),
|
||||
nps.Name: NewBuilderWithFlags(nps.NewWithFlags),
|
||||
os.Name: NewBuilderWithFlags(os.NewWithFlags),
|
||||
pagefile.Name: NewBuilderWithFlags(pagefile.NewWithFlags),
|
||||
perfdata.Name: NewBuilderWithFlags(perfdata.NewWithFlags),
|
||||
physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags),
|
||||
printer.Name: NewBuilderWithFlags(printer.NewWithFlags),
|
||||
@@ -104,6 +107,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
|
||||
textfile.Name: NewBuilderWithFlags(textfile.NewWithFlags),
|
||||
thermalzone.Name: NewBuilderWithFlags(thermalzone.NewWithFlags),
|
||||
time.Name: NewBuilderWithFlags(time.NewWithFlags),
|
||||
udp.Name: NewBuilderWithFlags(udp.NewWithFlags),
|
||||
update.Name: NewBuilderWithFlags(update.NewWithFlags),
|
||||
vmware.Name: NewBuilderWithFlags(vmware.NewWithFlags),
|
||||
}
|
||||
|
||||
@@ -87,8 +87,6 @@ test_alpha_total 42
|
||||
# TYPE windows_cpu_interrupts_total counter
|
||||
# HELP windows_cpu_logical_processor Total number of logical processors
|
||||
# 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
|
||||
# TYPE windows_cpu_parking_status gauge
|
||||
# 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="cs"} 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="net"} 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="physical_disk"} 1
|
||||
windows_exporter_collector_success{collector="printer"} 1
|
||||
windows_exporter_collector_success{collector="process"} 1
|
||||
windows_exporter_collector_success{collector="scheduled_task"} 1
|
||||
windows_exporter_collector_success{collector="service"} 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="time"} 1
|
||||
windows_exporter_collector_success{collector="udp"} 1
|
||||
# HELP windows_exporter_collector_timeout windows_exporter: Whether the collector timed out.
|
||||
# TYPE windows_exporter_collector_timeout gauge
|
||||
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="cs"} 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="net"} 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="physical_disk"} 0
|
||||
windows_exporter_collector_timeout{collector="printer"} 0
|
||||
windows_exporter_collector_timeout{collector="process"} 0
|
||||
windows_exporter_collector_timeout{collector="scheduled_task"} 0
|
||||
windows_exporter_collector_timeout{collector="service"} 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="time"} 0
|
||||
windows_exporter_collector_timeout{collector="udp"} 0
|
||||
# HELP windows_exporter_perflib_snapshot_duration_seconds Duration of perflib snapshot capture
|
||||
# TYPE windows_exporter_perflib_snapshot_duration_seconds gauge
|
||||
# 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
|
||||
# HELP windows_logical_disk_writes_total The number of write operations on the disk (LogicalDisk.DiskWritesPerSec)
|
||||
# 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)
|
||||
# TYPE windows_memory_available_bytes gauge
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
@@ -249,11 +261,11 @@ windows_exporter_collector_timeout{collector="textfile"} 0
|
||||
# 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)
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# HELP windows_net_bytes_received_total (Network.BytesReceivedPerSec)
|
||||
# TYPE windows_net_bytes_received_total counter
|
||||
@@ -263,6 +275,8 @@ windows_exporter_collector_timeout{collector="textfile"} 0
|
||||
# TYPE windows_net_bytes_total counter
|
||||
# HELP windows_net_current_bandwidth_bytes (Network.CurrentBandwidth)
|
||||
# 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)
|
||||
# TYPE windows_net_output_queue_length_packets gauge
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# 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
|
||||
# HELP windows_os_physical_memory_free_bytes Deprecated: Use `windows_memory_physical_free_bytes` instead.
|
||||
# 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
|
||||
# HELP windows_os_visible_memory_bytes Deprecated: Use `windows_memory_physical_total_bytes` instead.
|
||||
# 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
|
||||
# TYPE windows_perfdata_memory_cache_faults_sec counter
|
||||
# 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
|
||||
# HELP windows_physical_disk_writes_total The number of write operations on the disk (PhysicalDisk.DiskWritesPerSec)
|
||||
# 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
|
||||
# TYPE windows_scheduled_task_state gauge
|
||||
windows_scheduled_task_state{state="disabled",task="/Microsoft/Windows/Maintenance/WinSAT"} 1
|
||||
windows_scheduled_task_state{state="queued",task="/Microsoft/Windows/Maintenance/WinSAT"} 0
|
||||
windows_scheduled_task_state{state="ready",task="/Microsoft/Windows/Maintenance/WinSAT"} 0
|
||||
windows_scheduled_task_state{state="running",task="/Microsoft/Windows/Maintenance/WinSAT"} 0
|
||||
windows_scheduled_task_state{state="unknown",task="/Microsoft/Windows/Maintenance/WinSAT"} 0
|
||||
windows_scheduled_task_state{state="disabled",task="/Microsoft/Windows/PLA/GAEvents"} 0
|
||||
windows_scheduled_task_state{state="queued",task="/Microsoft/Windows/PLA/GAEvents"} 0
|
||||
windows_scheduled_task_state{state="ready",task="/Microsoft/Windows/PLA/GAEvents"} 0
|
||||
windows_scheduled_task_state{state="running",task="/Microsoft/Windows/PLA/GAEvents"} 1
|
||||
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
|
||||
# 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.
|
||||
# TYPE windows_service_process gauge
|
||||
# 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
|
||||
# HELP windows_system_threads Current number of threads (WMI source: PerfOS_System.Threads)
|
||||
# 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.
|
||||
# TYPE windows_textfile_mtime_seconds gauge
|
||||
# HELP windows_textfile_scrape_error 1 if there was an error opening or reading a file, 0 otherwise
|
||||
# TYPE windows_textfile_scrape_error gauge
|
||||
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
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ if (-not (Test-Path -Path '..\windows_exporter.exe')) {
|
||||
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
|
||||
$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"
|
||||
|
||||
# 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.
|
||||
# Use default collectors, port and address: http://localhost:9182/metrics
|
||||
$exporter_proc = Start-Process `
|
||||
-PassThru `
|
||||
-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\"}}}]"
|
||||
"@ `
|
||||
-WindowStyle Hidden `
|
||||
|
||||
@@ -85,7 +85,7 @@ $script_path = $MyInvocation.MyCommand.Path
|
||||
$working_dir = Split-Path $script_path
|
||||
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.
|
||||
# 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.
|
||||
$skip_re = "^([#]?\s*(HELP|TYPE)?\s*go_|windows_memory_pool_nonpaged_allocs_total)"
|
||||
|
||||
# Need to remove carriage returns, as promtool expects 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"
|
||||
# Join the split lines back to a single String (with LF line endings!)
|
||||
$output = $output -Join "`n"
|
||||
Stop-Process -Id $exporter_proc.Id
|
||||
try {
|
||||
# Need to remove carriage returns, as promtool expects 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 = (((Invoke-WebRequest -UseBasicParsing -URI http://127.0.0.1:9183/metrics).Content) -Split "`r?`n" | Select-String -NotMatch $skip_re) -join "`n"
|
||||
# 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")
|
||||
if ($ExitCode -ne 0) {
|
||||
Write-Host "OUTPUT"
|
||||
|
||||
Write-Host $output
|
||||
|
||||
Write-Host "Promtool command returned exit code $($ExitCode). See output for details."
|
||||
EXIT 1
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user