mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-08 05:56:37 +00:00
chore: release 0.29.0.rc0 (#1600)
This commit is contained in:
@@ -1,6 +1,16 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*.wxs]
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
[*.{json,wxs,xml}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -12,6 +12,8 @@ on:
|
|||||||
- "tools/e2e-output.txt"
|
- "tools/e2e-output.txt"
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- next
|
||||||
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- "go.mod"
|
- "go.mod"
|
||||||
@@ -21,6 +23,8 @@ on:
|
|||||||
- "tools/e2e-output.txt"
|
- "tools/e2e-output.txt"
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
|
- next
|
||||||
|
- main
|
||||||
|
|
||||||
env:
|
env:
|
||||||
VERSION_PROMU: '0.14.0'
|
VERSION_PROMU: '0.14.0'
|
||||||
@@ -101,4 +105,4 @@ jobs:
|
|||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v6
|
||||||
with:
|
with:
|
||||||
version: v1.60
|
version: v1.60
|
||||||
args: "--timeout=5m --max-same-issues=0"
|
args: "--max-same-issues=0"
|
||||||
@@ -1,13 +1,11 @@
|
|||||||
linters:
|
linters:
|
||||||
enable-all: true
|
enable-all: true
|
||||||
disable:
|
disable:
|
||||||
- containedctx
|
|
||||||
- contextcheck
|
|
||||||
- cyclop
|
- cyclop
|
||||||
- depguard
|
- depguard
|
||||||
- dogsled
|
|
||||||
- dupl
|
- dupl
|
||||||
- err113
|
- err113
|
||||||
|
- execinquery
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exhaustruct
|
- exhaustruct
|
||||||
- exportloopref
|
- exportloopref
|
||||||
@@ -17,21 +15,16 @@ linters:
|
|||||||
- gocognit
|
- gocognit
|
||||||
- goconst
|
- goconst
|
||||||
- gocyclo
|
- gocyclo
|
||||||
- godox
|
- gomnd
|
||||||
- inamedparam
|
|
||||||
- ireturn
|
|
||||||
- lll
|
- lll
|
||||||
|
- maintidx
|
||||||
- mnd
|
- mnd
|
||||||
- nlreturn
|
|
||||||
- noctx
|
|
||||||
- testpackage
|
- testpackage
|
||||||
- varnamelen
|
- varnamelen
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
- wsl
|
|
||||||
- execinquery
|
run:
|
||||||
- gomnd
|
timeout: 5m
|
||||||
- stylecheck
|
|
||||||
- maintidx
|
|
||||||
|
|
||||||
linters-settings:
|
linters-settings:
|
||||||
gosec:
|
gosec:
|
||||||
@@ -52,7 +45,33 @@ linters-settings:
|
|||||||
# Support string case: `camel`, `pascal`, `kebab`, `snake`, `upperSnake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`, `header`
|
# Support string case: `camel`, `pascal`, `kebab`, `snake`, `upperSnake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`, `header`
|
||||||
json: camel
|
json: camel
|
||||||
yaml: snake
|
yaml: snake
|
||||||
|
gomoddirectives:
|
||||||
|
replace-allow-list:
|
||||||
|
- github.com/prometheus/common # https://github.com/prometheus/common/pull/694
|
||||||
|
forbidigo:
|
||||||
|
forbid:
|
||||||
|
- "^(fmt\\.Print(|f|ln)|print|println)$"
|
||||||
|
- p: "^syscall\\..*$"
|
||||||
|
msg: use golang.org/x/sys/windows instead of syscall
|
||||||
|
- p: "^windows\\.NewLazyDLL$"
|
||||||
|
msg: use NewLazySystemDLL instead NewLazyDLL
|
||||||
|
sloglint:
|
||||||
|
no-mixed-args: true
|
||||||
|
kv-only: false
|
||||||
|
attr-only: true
|
||||||
|
no-global: "all"
|
||||||
|
context: "scope"
|
||||||
|
static-msg: false
|
||||||
|
no-raw-keys: false
|
||||||
|
key-naming-case: snake
|
||||||
|
forbidden-keys:
|
||||||
|
- time
|
||||||
|
- level
|
||||||
|
- msg
|
||||||
|
- source
|
||||||
|
args-on-sep-lines: true
|
||||||
|
stylecheck:
|
||||||
|
checks: ["all", "-ST1003"]
|
||||||
issues:
|
issues:
|
||||||
exclude:
|
exclude:
|
||||||
- don't use underscores in Go names
|
- don't use underscores in Go names
|
||||||
@@ -66,3 +85,7 @@ issues:
|
|||||||
- text: "don't use ALL_CAPS in Go names; use CamelCase"
|
- text: "don't use ALL_CAPS in Go names; use CamelCase"
|
||||||
linters:
|
linters:
|
||||||
- revive
|
- revive
|
||||||
|
- path: pkg/perflib/
|
||||||
|
linters:
|
||||||
|
- godox
|
||||||
|
- stylecheck
|
||||||
|
|||||||
33
.promu.yml
33
.promu.yml
@@ -1,19 +1,24 @@
|
|||||||
go:
|
go:
|
||||||
version: 1.20
|
# Whenever the Go version is updated here,
|
||||||
|
# .github/workflows should also be updated.
|
||||||
|
version: 1.23
|
||||||
repository:
|
repository:
|
||||||
path: github.com/prometheus-community/windows_exporter
|
path: github.com/prometheus-community/windows_exporter
|
||||||
build:
|
build:
|
||||||
binaries:
|
binaries:
|
||||||
- name: windows_exporter
|
- name: windows_exporter
|
||||||
ldflags: |
|
tags:
|
||||||
-X github.com/prometheus/common/version.Version={{.Version}}
|
all:
|
||||||
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
- trimpath
|
||||||
-X github.com/prometheus/common/version.Branch={{.Branch}}
|
ldflags: |
|
||||||
-X github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
|
-X github.com/prometheus/common/version.Version={{.Version}}
|
||||||
-X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
|
-X github.com/prometheus/common/version.Revision={{.Revision}}
|
||||||
|
-X github.com/prometheus/common/version.Branch={{.Branch}}
|
||||||
|
-X github.com/prometheus/common/version.BuildUser={{user}}@{{host}}
|
||||||
|
-X github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}}
|
||||||
tarball:
|
tarball:
|
||||||
files:
|
files:
|
||||||
- LICENSE
|
- LICENSE
|
||||||
crossbuild:
|
crossbuild:
|
||||||
platforms:
|
platforms:
|
||||||
- windows
|
- windows
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Name | Description | Enabled by default
|
|||||||
[license](docs/collector.license.md) | Windows license status |
|
[license](docs/collector.license.md) | Windows license status |
|
||||||
[logical_disk](docs/collector.logical_disk.md) | Logical disks, disk I/O | ✓
|
[logical_disk](docs/collector.logical_disk.md) | Logical disks, disk I/O | ✓
|
||||||
[logon](docs/collector.logon.md) | User logon sessions |
|
[logon](docs/collector.logon.md) | User logon sessions |
|
||||||
[memory](docs/collector.memory.md) | Memory usage metrics |
|
[memory](docs/collector.memory.md) | Memory usage metrics | ✓
|
||||||
[mscluster](docs/collector.mscluster.md) | MSCluster metrics |
|
[mscluster](docs/collector.mscluster.md) | MSCluster metrics |
|
||||||
[msmq](docs/collector.msmq.md) | MSMQ queues |
|
[msmq](docs/collector.msmq.md) | MSMQ queues |
|
||||||
[mssql](docs/collector.mssql.md) | [SQL Server Performance Objects](https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/use-sql-server-objects#SQLServerPOs) metrics |
|
[mssql](docs/collector.mssql.md) | [SQL Server Performance Objects](https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/use-sql-server-objects#SQLServerPOs) metrics |
|
||||||
@@ -218,7 +218,7 @@ If you need to skip TLS verification, you can use the `--config.file.insecure-sk
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
collectors:
|
collectors:
|
||||||
enabled: cpu,cs,net,service
|
enabled: cpu,net,service
|
||||||
collector:
|
collector:
|
||||||
service:
|
service:
|
||||||
services-where: "Name='windows_exporter'"
|
services-where: "Name='windows_exporter'"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
collectors:
|
collectors:
|
||||||
enabled: cpu,cpu_info,cs,exchange,iis,logical_disk,logon,memory,net,os,process,remote_fx,service,system,tcp,time,terminal_services,textfile
|
enabled: cpu,cpu_info,exchange,iis,logical_disk,logon,memory,net,os,process,remote_fx,service,system,tcp,time,terminal_services,textfile
|
||||||
collector:
|
collector:
|
||||||
service:
|
service:
|
||||||
services-where: "Name='windows_exporter'"
|
services-where: "Name='windows_exporter'"
|
||||||
|
|||||||
@@ -16,26 +16,22 @@ None
|
|||||||
## Metrics
|
## Metrics
|
||||||
These metrics are available on all versions of Windows:
|
These metrics are available on all versions of Windows:
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
| Name | Description | Type | Labels |
|
||||||
-----|-------------|------|-------
|
|--------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|-----------------|
|
||||||
`windows_cpu_cstate_seconds_total` | Time spent in low-power idle states | counter | `core`, `state`
|
| `windows_cpu_logical_processor` | Number of installed logical processors | counter | `core`, `state` |
|
||||||
`windows_cpu_time_total` | Time that processor spent in different modes (dpc, idle, interrupt, privileged, user) | counter | `core`, `mode`
|
| `windows_cpu_cstate_seconds_total` | Time spent in low-power idle states | counter | `core`, `state` |
|
||||||
`windows_cpu_interrupts_total` | Total number of received and serviced hardware interrupts | counter | `core`
|
| `windows_cpu_time_total` | Time that processor spent in different modes (dpc, idle, interrupt, privileged, user) | counter | `core`, `mode` |
|
||||||
`windows_cpu_dpcs_total` | Total number of received and serviced deferred procedure calls (DPCs) | counter | `core`
|
| `windows_cpu_interrupts_total` | Total number of received and serviced hardware interrupts | counter | `core` |
|
||||||
|
| `windows_cpu_dpcs_total` | Total number of received and serviced deferred procedure calls (DPCs) | counter | `core` |
|
||||||
These metrics are only exposed on Windows Server 2008R2 and later:
|
| `windows_cpu_clock_interrupts_total` | Total number of received and serviced clock tick interrupts | counter | `core` |
|
||||||
|
| `windows_cpu_idle_break_events_total` | Total number of time processor was woken from idle | counter | `core` |
|
||||||
Name | Description | Type | Labels
|
| `windows_cpu_parking_status` | Parking Status represents whether a processor is parked or not | gauge | `core` |
|
||||||
-----|-------------|------|-------
|
| `windows_cpu_core_frequency_mhz` | Core frequency in megahertz | gauge | `core` |
|
||||||
`windows_cpu_clock_interrupts_total` | Total number of received and serviced clock tick interrupts | counter | `core`
|
| `windows_cpu_processor_performance_total` | Processor Performance is the number of CPU cycles executing instructions by each core; it is believed to be similar to the value that the APERF MSR would show, were it exposed | counter | `core` |
|
||||||
`windows_cpu_idle_break_events_total` | Total number of time processor was woken from idle | counter | `core`
|
| `windows_cpu_processor_mperf_total` | Processor MPerf Total is proportioanl to the number of TSC ticks each core has accumulated while executing instructions. Due to the manner in which it is presented, it should be scaled by 1e2 to properly line up with Processor Performance Total. As above, it is believed to be closely related to the MPERF MSR. | counter | `core` |
|
||||||
`windows_cpu_parking_status` | Parking Status represents whether a processor is parked or not | gauge | `core`
|
| `windows_cpu_processor_rtc_total` | RTC total is assumed to represent the 64Hz tick rate in Windows. It is not by itself useful, but can be used with `windows_cpu_processor_utility_total` to more accurately measure CPU utilisation than with `windows_cpu_time_total` | counter | `core` |
|
||||||
`windows_cpu_core_frequency_mhz` | Core frequency in megahertz | gauge | `core`
|
| `windows_cpu_processor_utility_total` | Processor Utility Total is a newer, more accurate measure of CPU utilization, in particular handling modern CPUs with variant CPU frequencies. The rate of this counter divided by the rate of `windows_cpu_processor_rtc_total` should provide an accurate view of CPU utilisation on modern systems, as observed in Task Manager. | counter | `core` |
|
||||||
`windows_cpu_processor_performance_total` | Processor Performance is the number of CPU cycles executing instructions by each core; it is believed to be similar to the value that the APERF MSR would show, were it exposed | counter | `core`
|
| `windows_cpu_processor_privileged_utility_total` | Processor Privileged Utility Total, when used in a similar fashion to `windows_cpu_processor_utility_total` will show the portion of CPU utilization which is happening in privileged mode. | counter | `core` |
|
||||||
`windows_cpu_processor_mperf_total` | Processor MPerf Total is proportioanl to the number of TSC ticks each core has accumulated while executing instructions. Due to the manner in which it is presented, it should be scaled by 1e2 to properly line up with Processor Performance Total. As above, it is believed to be closely related to the MPERF MSR. | counter | `core`
|
|
||||||
`windows_cpu_processor_rtc_total` | RTC total is assumed to represent the 64Hz tick rate in Windows. It is not by itself useful, but can be used with `windows_cpu_processor_utility_total` to more accurately measure CPU utilisation than with `windows_cpu_time_total` | counter | `core`
|
|
||||||
`windows_cpu_processor_utility_total` | Processor Utility Total is a newer, more accurate measure of CPU utilization, in particular handling modern CPUs with variant CPU frequencies. The rate of this counter divided by the rate of `windows_cpu_processor_rtc_total` should provide an accurate view of CPU utilisation on modern systems, as observed in Task Manager. | counter | `core`
|
|
||||||
`windows_cpu_processor_privileged_utility_total` | Processor Privileged Utility Total, when used in a similar fashion to `windows_cpu_processor_utility_total` will show the portion of CPU utilization which is happening in privileged mode. | counter | `core`
|
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
Show frequency of host CPU cores
|
Show frequency of host CPU cores
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# cs collector
|
# cs collector
|
||||||
|
|
||||||
|
> [!CAUTION]
|
||||||
|
> This collector is deprecated and will be removed in a future release.
|
||||||
|
> See https://github.com/prometheus-community/windows_exporter/pull/1596 for more information.
|
||||||
|
|
||||||
The cs collector exposes metrics detailing the hardware of the computer system
|
The cs collector exposes metrics detailing the hardware of the computer system
|
||||||
|
|
||||||
|||
|
|||
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ The memory collector exposes metrics about system memory usage
|
|||||||
|||
|
|||
|
||||||
-|-
|
-|-
|
||||||
Metric name prefix | `memory`
|
Metric name prefix | `memory`
|
||||||
Data source | Perflib
|
Data source | Performance Counters
|
||||||
Classes | `Win32_PerfRawData_PerfOS_Memory`
|
Classes | -
|
||||||
Enabled by default? | No
|
Enabled by default? | Yes
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
|
|
||||||
@@ -15,46 +15,73 @@ None
|
|||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
| Name | Description | Type | Labels |
|
||||||
-----|-------------|------|-------
|
|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
|
||||||
`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 | gauge | None
|
| `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 | gauge | None |
|
||||||
`windows_memory_cache_bytes` | Number of bytes currently being used by the file system cache | gauge | None
|
| `windows_memory_cache_bytes` | Number of bytes currently being used by the file system cache | gauge | None |
|
||||||
`windows_memory_cache_bytes_peak` | Maximum number of CacheBytes after the system was last restarted | gauge | None
|
| `windows_memory_cache_bytes_peak` | Maximum number of CacheBytes after the system was last restarted | gauge | None |
|
||||||
`windows_memory_cache_faults_total` | Number of faults which occur when a page sought in the file system cache is not found there and must be retrieved from elsewhere in memory (soft fault) or from disk (hard fault) | counter | None
|
| `windows_memory_cache_faults_total` | Number of faults which occur when a page sought in the file system cache is not found there and must be retrieved from elsewhere in memory (soft fault) or from disk (hard fault) | counter | None |
|
||||||
`windows_memory_commit_limit` | Amount of virtual memory, in bytes, that can be committed without having to extend the paging file(s) | gauge | None
|
| `windows_memory_commit_limit` | Amount of virtual memory, in bytes, that can be committed without having to extend the paging file(s) | gauge | None |
|
||||||
`windows_memory_committed_bytes` | Amount of committed virtual memory, in bytes | gauge | None
|
| `windows_memory_committed_bytes` | Amount of committed virtual memory, in bytes | gauge | None |
|
||||||
`windows_memory_demand_zero_faults_total` | The number of zeroed pages required to satisfy faults. Zeroed pages, pages emptied of previously stored data and filled with zeros, are a security feature of Windows that prevent processes from seeing data stored by earlier processes that used the memory space | counter | None
|
| `windows_memory_demand_zero_faults_total` | The number of zeroed pages required to satisfy faults. Zeroed pages, pages emptied of previously stored data and filled with zeros, are a security feature of Windows that prevent processes from seeing data stored by earlier processes that used the memory space | counter | None |
|
||||||
`windows_memory_free_and_zero_page_list_bytes` | The amount of physical memory, in bytes, that is assigned to the free and zero page lists. This memory does not contain cached data. It is immediately available for allocation to a process or for system use | gauge | None
|
| `windows_memory_free_and_zero_page_list_bytes` | The amount of physical memory, in bytes, that is assigned to the free and zero page lists. This memory does not contain cached data. It is immediately available for allocation to a process or for system use | gauge | None |
|
||||||
`windows_memory_free_system_page_table_entries` | Number of page table entries not being used by the system | gauge | None
|
| `windows_memory_free_system_page_table_entries` | Number of page table entries not being used by the system | gauge | None |
|
||||||
`windows_memory_modified_page_list_bytes` | The amount of physical memory, in bytes, that is assigned to the modified page list. This memory contains cached data and code that is not actively in use by processes, the system and the system cache. This memory needs to be written out before it will be available for allocation to a process or for system use | gauge | None
|
| `windows_memory_modified_page_list_bytes` | The amount of physical memory, in bytes, that is assigned to the modified page list. This memory contains cached data and code that is not actively in use by processes, the system and the system cache. This memory needs to be written out before it will be available for allocation to a process or for system use | gauge | None |
|
||||||
`windows_memory_page_faults_total` | Overall rate at which faulted pages are handled by the processor | counter | None
|
| `windows_memory_page_faults_total` | Overall rate at which faulted pages are handled by the processor | counter | None |
|
||||||
`windows_memory_swap_page_reads_total` | Number of disk page reads (a single read operation reading several pages is still only counted once) | counter | None
|
| `windows_memory_swap_page_reads_total` | Number of disk page reads (a single read operation reading several pages is still only counted once) | counter | None |
|
||||||
`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) | counter | None
|
| `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) | counter | None |
|
||||||
`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) | counter | None
|
| `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) | counter | None |
|
||||||
`windows_memory_swap_page_operations_total` | Total number of swap page read and writes (PagesPersec) | counter | None
|
| `windows_memory_swap_page_operations_total` | Total number of swap page read and writes (PagesPersec) | counter | None |
|
||||||
`windows_memory_swap_page_writes_total` | Number of disk page writes (a single write operation writing several pages is still only counted once) | counter | None
|
| `windows_memory_swap_page_writes_total` | Number of disk page writes (a single write operation writing several pages is still only counted once) | counter | None |
|
||||||
`windows_memory_pool_nonpaged_allocs_total` | The number of calls to allocate space in the nonpaged pool. The nonpaged pool is an area of system memory area for objects that cannot be written to disk, and must remain in physical memory as long as they are allocated | counter | None
|
| `windows_memory_physical_free_bytes` | Bytes of physical memory currently unused and available | gauge | None |
|
||||||
`windows_memory_pool_nonpaged_bytes` | Number of bytes in the non-paged pool, an area of the system virtual memory that is used for objects that cannot be written to disk, but must remain in physical memory as long as they are allocated | gauge | None
|
| `windows_memory_physical_total_bytes` | Total bytes of physical memory available to the operating system. This value does not necessarily indicate the true amount of physical memory, but what is reported to the operating system as available to it | gauge | None |
|
||||||
`windows_memory_pool_paged_allocs_total` | Number of calls to allocate space in the paged pool, regardless of the amount of space allocated in each call | counter | None
|
| `windows_memory_pool_nonpaged_allocs_total` | The number of calls to allocate space in the nonpaged pool. The nonpaged pool is an area of system memory area for objects that cannot be written to disk, and must remain in physical memory as long as they are allocated | counter | None |
|
||||||
`windows_memory_pool_paged_bytes` | Number of bytes in the paged pool | gauge | None
|
| `windows_memory_pool_nonpaged_bytes` | Number of bytes in the non-paged pool, an area of the system virtual memory that is used for objects that cannot be written to disk, but must remain in physical memory as long as they are allocated | gauge | None |
|
||||||
`windows_memory_pool_paged_resident_bytes` | The size, in bytes, of the portion of the paged pool that is currently resident and active in physical memory. The paged pool is an area of the system virtual memory that is used for objects that can be written to disk when they are not being used | gauge | None
|
| `windows_memory_pool_paged_allocs_total` | Number of calls to allocate space in the paged pool, regardless of the amount of space allocated in each call | counter | None |
|
||||||
`windows_memory_standby_cache_core_bytes` | The amount of physical memory, in bytes, that is assigned to the core 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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None
|
| `windows_memory_pool_paged_bytes` | Number of bytes in the paged pool | gauge | None |
|
||||||
`windows_memory_standby_cache_normal_priority_bytes` | The amount of physical memory, in bytes, that is assigned to the normal priority 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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None
|
| `windows_memory_pool_paged_resident_bytes` | The size, in bytes, of the portion of the paged pool that is currently resident and active in physical memory. The paged pool is an area of the system virtual memory that is used for objects that can be written to disk when they are not being used | gauge | None |
|
||||||
`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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None
|
| `windows_memory_process_memory_limit_bytes` | Maximum number of bytes of memory that can be allocated to a process | gauge | None |
|
||||||
`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 | gauge | None
|
| `windows_memory_standby_cache_core_bytes` | The amount of physical memory, in bytes, that is assigned to the core 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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None |
|
||||||
`windows_memory_system_code_resident_bytes` | The size, in bytes, of the pageable operating system code that is currently resident and active in physical memory. This value is a component of Memory\\System Code Total Bytes. Memory\\System Code Resident Bytes (and Memory\\System Code Total Bytes) does not include code that must remain in physical memory and cannot be written to disk | gauge | None
|
| `windows_memory_standby_cache_normal_priority_bytes` | The amount of physical memory, in bytes, that is assigned to the normal priority 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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None |
|
||||||
`windows_memory_system_code_total_bytes` | The size, in bytes, of the pageable operating system code currently mapped into the system virtual address space. This value is calculated by summing the bytes in Ntoskrnl.exe, Hal.dll, the boot drivers, and file systems loaded by Ntldr/osloader. This counter does not include code that must remain in physical memory and cannot be written to disk | gauge | None
|
| `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. It is immediately available for allocation to a process or for system use. If the system runs out of available free and zero memory, memory on lower priority standby cache page lists will be repurposed before memory on higher priority standby cache page lists | gauge | None |
|
||||||
`windows_memory_system_driver_resident_bytes` | The size, in bytes, of the pageable physical memory being used by device drivers. It is the working set (physical memory area) of the drivers. This value is a component of Memory\\System Driver Total Bytes, which also includes driver memory that has been written to disk. Neither Memory\\System Driver Resident Bytes nor Memory\\System Driver Total Bytes includes memory that cannot be written to disk | gauge | None
|
| `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 | gauge | None |
|
||||||
`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. It includes both physical memory (Memory\\System Driver Resident Bytes) and code and data paged to disk. It is a component of Memory\\System Code Total Bytes | gauge | None
|
| `windows_memory_system_code_resident_bytes` | The size, in bytes, of the pageable operating system code that is currently resident and active in physical memory. This value is a component of Memory\\System Code Total Bytes. Memory\\System Code Resident Bytes (and Memory\\System Code Total Bytes) does not include code that must remain in physical memory and cannot be written to disk | gauge | None |
|
||||||
`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. The pages were recovered without additional disk activity. Transition faults are counted in numbers of faults; because only one page is faulted in each operation, it is also equal to the number of pages faulted | counter | None
|
| `windows_memory_system_code_total_bytes` | The size, in bytes, of the pageable operating system code currently mapped into the system virtual address space. This value is calculated by summing the bytes in Ntoskrnl.exe, Hal.dll, the boot drivers, and file systems loaded by Ntldr/osloader. This counter does not include code that must remain in physical memory and cannot be written to disk | gauge | None |
|
||||||
`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. These pages would have otherwise remained in the page cache to provide a (fast) soft fault (instead of retrieving it from backing store) in the event the page was accessed in the future | counter | None
|
| `windows_memory_system_driver_resident_bytes` | The size, in bytes, of the pageable physical memory being used by device drivers. It is the working set (physical memory area) of the drivers. This value is a component of Memory\\System Driver Total Bytes, which also includes driver memory that has been written to disk. Neither Memory\\System Driver Resident Bytes nor Memory\\System Driver Total Bytes includes memory that cannot be written to disk | gauge | None |
|
||||||
`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 | counter | None
|
| `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. It includes both physical memory (Memory\\System Driver Resident Bytes) and code and data paged to disk. It is a component of Memory\\System Code Total Bytes | gauge | None |
|
||||||
|
| `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. The pages were recovered without additional disk activity. Transition faults are counted in numbers of faults; because only one page is faulted in each operation, it is also equal to the number of pages faulted | counter | None |
|
||||||
|
| `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. These pages would have otherwise remained in the page cache to provide a (fast) soft fault (instead of retrieving it from backing store) in the event the page was accessed in the future | counter | None |
|
||||||
|
| `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 | counter | None |
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||||
|
|
||||||
## Useful queries
|
## Useful queries
|
||||||
_This collector does not yet have any useful queries added, we would appreciate your help adding them!_
|
|
||||||
|
|
||||||
|
Show memory usage for instance (%)
|
||||||
|
```
|
||||||
|
100 - 100 * windows_memory_physical_free_bytes{instance="localhost"} / windows_memory_physical_total_bytes
|
||||||
|
```
|
||||||
## Alerting examples
|
## Alerting examples
|
||||||
_This collector does not yet have alerting examples, we would appreciate your help adding them!_
|
|
||||||
|
**prometheus.rules**
|
||||||
|
```yaml
|
||||||
|
# Alert on hosts that have exhausted all available physical memory
|
||||||
|
- alert: MemoryExhausted
|
||||||
|
expr: windows_os_physical_memory_free_bytes == 0
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: high
|
||||||
|
annotations:
|
||||||
|
summary: "Host {{ $labels.instance }} is out of memory"
|
||||||
|
description: "{{ $labels.instance }} has exhausted all available physical memory"
|
||||||
|
|
||||||
|
# Alert on hosts with greater than 90% memory usage
|
||||||
|
- alert: MemoryLow
|
||||||
|
expr: 100 - 100 * windows_memory_physical_free_bytes{instance="localhost"} / windows_memory_physical_total_bytes > 90
|
||||||
|
for: 10m
|
||||||
|
labels:
|
||||||
|
severity: warning
|
||||||
|
annotations:
|
||||||
|
summary: "Memory usage for host {{ $labels.instance }} is greater than 90%"
|
||||||
|
```
|
||||||
|
|||||||
@@ -14,58 +14,26 @@ None
|
|||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
| Name | Description | Type | Labels |
|
||||||
-----|-------------|------|-------
|
|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
|
||||||
`windows_os_info` | Contains full product name & version in labels. Note that the `major_version` for Windows 11 is "10"; a build number greater than 22000 represents Windows 11. | gauge | `product`, `version`, `major_version`, `minor_version`, `build_number`
|
| `windows_os_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_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
|
| `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 |
|
||||||
`windows_os_physical_memory_free_bytes` | Bytes of physical memory currently unused and available | gauge | None
|
|
||||||
`windows_os_time` | Current time as reported by the operating system, in [Unix time](https://en.wikipedia.org/wiki/Unix_time). See [time.Unix()](https://golang.org/pkg/time/#Unix) for details | gauge | None
|
|
||||||
`windows_os_timezone` | Current timezone as reported by the operating system. See [time.Zone()](https://golang.org/pkg/time/#Time.Zone) for details | gauge | `timezone`
|
|
||||||
`windows_os_processes` | Number of process contexts currently loaded or running on the operating system | gauge | None
|
|
||||||
`windows_os_processes_limit` | Maximum number of process contexts the operating system can support. The default value set by the provider is 4294967295 (0xFFFFFFFF) | gauge | None
|
|
||||||
`windows_os_process_memory_limit_bytes` | Maximum number of bytes of memory that can be allocated to a process | gauge | None
|
|
||||||
`windows_os_users` | Number of user sessions for which the operating system is storing state information currently. For a list of current active logon sessions, see [`logon`](collector.logon.md) | gauge | None
|
|
||||||
`windows_os_virtual_memory_bytes` | Bytes of virtual memory | gauge | None
|
|
||||||
`windows_os_visible_memory_bytes` | Total bytes of physical memory available to the operating system. This value does not necessarily indicate the true amount of physical memory, but what is reported to the operating system as available to it | gauge | None
|
|
||||||
`windows_os_virtual_memory_free_bytes` | Bytes of virtual memory currently unused and available | gauge | None
|
|
||||||
|
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
Show current number of processes
|
|
||||||
```
|
```
|
||||||
windows_os_processes{instance="localhost"}
|
# HELP windows_os_hostname Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain
|
||||||
|
# TYPE windows_os_hostname gauge
|
||||||
|
windows_os_hostname{domain="",fqdn="PC",hostname="PC"} 1
|
||||||
|
# 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
|
||||||
|
windows_os_info{build_number="19045",major_version="10",minor_version="0",product="Windows 10 Pro",revision="4842",version="10.0.19045"} 1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Useful queries
|
## Useful queries
|
||||||
Find all devices not set to UTC timezone
|
_This collector does not yet have useful queries, we would appreciate your help adding them!_
|
||||||
```
|
|
||||||
windows_os_timezone{timezone != "UTC"}
|
|
||||||
```
|
|
||||||
|
|
||||||
Show memory usage for instance (%)
|
|
||||||
```
|
|
||||||
100 - 100 * windows_os_physical_memory_free_bytes{instance="localhost"} / windows_cs_physical_memory_bytes{instance="localhost"}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Alerting examples
|
## Alerting examples
|
||||||
**prometheus.rules**
|
_This collector does not yet have alerting examples, we would appreciate your help adding them!_
|
||||||
```yaml
|
|
||||||
# Alert on hosts that have exhausted all available physical memory
|
|
||||||
- alert: MemoryExhausted
|
|
||||||
expr: windows_os_physical_memory_free_bytes == 0
|
|
||||||
for: 10m
|
|
||||||
labels:
|
|
||||||
severity: high
|
|
||||||
annotations:
|
|
||||||
summary: "Host {{ $labels.instance }} is out of memory"
|
|
||||||
description: "{{ $labels.instance }} has exhausted all available physical memory"
|
|
||||||
|
|
||||||
# Alert on hosts with greater than 90% memory usage
|
|
||||||
- alert: MemoryLow
|
|
||||||
expr: 100 - 100 * windows_os_physical_memory_free_bytes / windows_cs_physical_memory_bytes > 90
|
|
||||||
for: 10m
|
|
||||||
labels:
|
|
||||||
severity: warning
|
|
||||||
annotations:
|
|
||||||
summary: "Memory usage for host {{ $labels.instance }} is greater than 90%"
|
|
||||||
```
|
|
||||||
114
docs/collector.perfdata.md
Normal file
114
docs/collector.perfdata.md
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
# Perfdata collector
|
||||||
|
|
||||||
|
The perfdata collector exposes any configured metric.
|
||||||
|
|
||||||
|
| | |
|
||||||
|
|---------------------|-------------------------|
|
||||||
|
| Metric name prefix | `perfdata` |
|
||||||
|
| Data source | Performance Data Helper |
|
||||||
|
| Enabled by default? | No |
|
||||||
|
|
||||||
|
## Flags
|
||||||
|
|
||||||
|
|
||||||
|
### `--collector.perfdata.objects`
|
||||||
|
|
||||||
|
Objects is a list of objects to collect metrics from. The value takes the form of a JSON array of strings. YAML is also supported.
|
||||||
|
|
||||||
|
The collector supports only english named counter. Localized counter-names are not supported.
|
||||||
|
|
||||||
|
#### Schema
|
||||||
|
|
||||||
|
YAML:
|
||||||
|
```yaml
|
||||||
|
- object: "Processor Information"
|
||||||
|
instances: ["*"]
|
||||||
|
instance_label: "core"
|
||||||
|
counters:
|
||||||
|
"% Processor Time": {}
|
||||||
|
- object: "Memory"
|
||||||
|
counters:
|
||||||
|
"Cache Faults/sec":
|
||||||
|
type: "counter"
|
||||||
|
```
|
||||||
|
|
||||||
|
JSON:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{"object":"Processor Information","instance_label": "core","instances":["*"],"counters": {"% Processor Time": {}}},
|
||||||
|
{"object":"Memory","counters": {"Cache Faults/sec": {"type": "counter"}}}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### name
|
||||||
|
|
||||||
|
ObjectName is the Object to query for, like Processor, DirectoryServices, LogicalDisk or similar.
|
||||||
|
|
||||||
|
The collector supports only english named counter. Localized counter-names are not supported.
|
||||||
|
|
||||||
|
#### instances
|
||||||
|
|
||||||
|
The instances key (this is an array) declares the instances of a counter you would like returned, it can be one or more values.
|
||||||
|
|
||||||
|
Example: Instances = `["C:","D:","E:"]`
|
||||||
|
|
||||||
|
This will return only for the instances C:, D: and E: where relevant. To get all instances of a Counter, use `["*"]` only.
|
||||||
|
|
||||||
|
Some Objects like `Memory` do not have instances to select from at all. In this case, the `instances` key can be omitted.
|
||||||
|
|
||||||
|
#### counters
|
||||||
|
|
||||||
|
The Counters key (this is an object) declares the counters of the ObjectName you would like returned, it can also be one or more values.
|
||||||
|
|
||||||
|
Example: Counters = `{"% Idle Time": {}, "% Disk Read Time": {}, "% Disk Write Time": {}}`
|
||||||
|
|
||||||
|
This must be specified for every counter you want the results. Wildcards are not supported.
|
||||||
|
|
||||||
|
#### counters Sub-Schema
|
||||||
|
|
||||||
|
##### type
|
||||||
|
|
||||||
|
This key is optional. It indicates the type of the counter. The value can be `counter` or `gauge`.
|
||||||
|
If not specified, the windows_exporter will try to determine the type based on the counter type.
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
# HELP windows_perfdata_memory_cache_faults_sec
|
||||||
|
# TYPE windows_perfdata_memory_cache_faults_sec counter
|
||||||
|
windows_perfdata_memory_cache_faults_sec 2.369977e+07
|
||||||
|
# HELP windows_perfdata_processor_information__processor_time
|
||||||
|
# TYPE windows_perfdata_processor_information__processor_time gauge
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,0"} 1.7259640625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,1"} 1.7576796875e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,10"} 2.2704234375e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,11"} 2.3069296875e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,12"} 2.3302265625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,13"} 2.32851875e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,14"} 2.3282421875e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,15"} 2.3271234375e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,16"} 2.329590625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,17"} 2.32800625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,18"} 2.3194359375e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,19"} 2.32380625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,2"} 1.954765625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,20"} 2.3259765625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,21"} 2.3268515625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,22"} 2.3301765625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,23"} 2.3264328125e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,3"} 1.94745625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,4"} 2.2011453125e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,5"} 2.27244375e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,6"} 2.25501875e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,7"} 2.2995265625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,8"} 2.2929890625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,9"} 2.313540625e+11
|
||||||
|
windows_perfdata_processor_information__processor_time{instance="0,_Total"} 2.23009459635e+11
|
||||||
|
```
|
||||||
|
|
||||||
|
## Metrics
|
||||||
|
|
||||||
|
The perfdata collector returns metrics based on the user configuration.
|
||||||
|
The metrics are named based on the object name and the counter name.
|
||||||
|
The instance name is added as a label to the metric.
|
||||||
@@ -2,47 +2,24 @@
|
|||||||
|
|
||||||
The service collector exposes metrics about Windows Services
|
The service collector exposes metrics about Windows Services
|
||||||
|
|
||||||
The collector exists in 2 different version. Version 1 is using WMI to query all services and is able to provide additional
|
|
||||||
information. Version 2 is a more efficient solution by directly connecting to the service manager, but is not able to
|
|
||||||
provide additional information like `run_as` or start configuration
|
|
||||||
|
|
||||||
## Flags
|
|
||||||
|
|
||||||
### `--collector.service.services-where`
|
|
||||||
|
|
||||||
A WMI filter on which services to include. Recommended to keep down number of returned metrics.
|
|
||||||
|
|
||||||
Example: `--collector.service.services-where="Name='windows_exporter'"`
|
|
||||||
|
|
||||||
Example config win_exporter.yml for multiple services: `services-where: Name='SQLServer' OR Name='Couchbase' OR Name='Spooler' OR Name='ActiveMQ'`
|
|
||||||
|
|
||||||
### `--collector.service.use-api`
|
|
||||||
|
|
||||||
Uses API calls instead of WMI for performance optimization. **Note** the previous flag (`--collector.service.services-where`) won't have any effect on this mode.
|
|
||||||
|
|
||||||
### `--collector.service.v2`
|
|
||||||
|
|
||||||
Version 2 of the service collector. Is using API calls for performance optimization. **Note** the previous flag (`--collector.service.services-where`) won't have any effect on this mode.
|
|
||||||
For additional performance reasons, it doesn't provide any additional information like `run_as` or start configuration.
|
|
||||||
|
|
||||||
# collector V1
|
|
||||||
|
|
||||||
|||
|
|||
|
||||||
-|-
|
-|-
|
||||||
Metric name prefix | `service`
|
Metric name prefix | `service`
|
||||||
Classes | [`Win32_Service`](https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx)
|
Classes | none
|
||||||
Enabled by default? | Yes
|
Enabled by default? | Yes
|
||||||
|
|
||||||
|
## Flags
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
| Name | Description | Type | Labels |
|
||||||
-----|-------------|------|-------
|
|------------------------------|-----------------------------------------------------------------------------------------------|-------|---------------------------------------|
|
||||||
`windows_service_info` | Contains service information in labels, constant 1 | gauge | name, display_name, process_id, run_as
|
| `windows_service_info` | Contains service information run as user in labels, constant 1 | gauge | name, display_name, path_name, run_as |
|
||||||
`windows_service_state` | The state of the service, 1 if the current state, 0 otherwise | gauge | name, state
|
| `windows_service_start_mode` | The start mode of the service, 1 if the current start mode, 0 otherwise | gauge | name, start_mode |
|
||||||
`windows_service_start_mode` | The start mode of the service, 1 if the current start mode, 0 otherwise | gauge | name, start_mode
|
| `windows_service_state` | The state of the service, 1 if the current state, 0 otherwise | gauge | name, state |
|
||||||
`windows_service_status` | The status of the service, 1 if the current status, 0 otherwise | gauge | name, status
|
| `windows_service_process` | Process of started service. The value is the creation time of the process as a unix timestamp | gauge | name, process_id |
|
||||||
|
|
||||||
For the values of the `state`, `start_mode`, `status` and `run_as` labels, see below.
|
|
||||||
|
|
||||||
### States
|
### States
|
||||||
|
|
||||||
@@ -65,81 +42,50 @@ A service can have the following start modes:
|
|||||||
- `manual`
|
- `manual`
|
||||||
- `disabled`
|
- `disabled`
|
||||||
|
|
||||||
### Status (not available in API mode)
|
|
||||||
|
|
||||||
A service can have any of the following statuses:
|
|
||||||
- `ok`
|
|
||||||
- `error`
|
|
||||||
- `degraded`
|
|
||||||
- `unknown`
|
|
||||||
- `pred fail`
|
|
||||||
- `starting`
|
|
||||||
- `stopping`
|
|
||||||
- `service`
|
|
||||||
- `stressed`
|
|
||||||
- `nonrecover`
|
|
||||||
- `no contact`
|
|
||||||
- `lost comm`
|
|
||||||
|
|
||||||
Note that there is some overlap with service state.
|
Note that there is some overlap with service state.
|
||||||
|
|
||||||
### Run As
|
### Run As
|
||||||
|
|
||||||
Account name under which a service runs. Depending on the service type, the account name may be in the form of "DomainName\Username" or UPN format ("Username@DomainName").
|
Account name under which a service runs. Depending on the service type, the account name may be in the form of "DomainName\Username" or UPN format ("Username@DomainName").
|
||||||
|
|
||||||
It corresponds to the `StartName` attribute of the `Win32_Service` class.
|
|
||||||
`StartName` attribute can be NULL and in such case the label is reported as an empty string. Notice that if the attribute is NULL the service is logged on as the `LocalSystem` account or, for kernel or system-level drive, it runs with a default object name created by the I/O system based on the service name, for example, DWDOM\Admin.
|
|
||||||
|
|
||||||
### Example metric
|
|
||||||
Lists the services that have a 'disabled' start mode.
|
|
||||||
```
|
|
||||||
windows_service_start_mode{exported_name=~"(mssqlserver|sqlserveragent)",start_mode="disabled"}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Useful queries
|
|
||||||
Counts the number of Microsoft SQL Server/Agent Processes
|
|
||||||
```
|
|
||||||
count(windows_service_state{exported_name=~"(sqlserveragent|mssqlserver)",state="running"})
|
|
||||||
```
|
|
||||||
|
|
||||||
# collector V2
|
|
||||||
|
|
||||||
|
|
||||||
|||
|
|
||||||
-|-
|
|
||||||
Metric name prefix | `service`
|
|
||||||
Classes | none
|
|
||||||
Enabled by default? | No
|
|
||||||
|
|
||||||
|
|
||||||
## Metrics
|
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
|
||||||
-----|-------------|------|-------
|
|
||||||
`windows_service_state` | The state of the service, 1 if the current state, 0 otherwise | gauge | name, display_name, state
|
|
||||||
|
|
||||||
### States
|
|
||||||
|
|
||||||
A service can be in the following states:
|
|
||||||
- `stopped`
|
|
||||||
- `start pending`
|
|
||||||
- `stop pending`
|
|
||||||
- `running`
|
|
||||||
- `continue pending`
|
|
||||||
- `pause pending`
|
|
||||||
- `paused`
|
|
||||||
- `unknown`
|
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
|
|
||||||
```
|
```
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="continue pending"} 0
|
# HELP windows_service_info A metric with a constant '1' value labeled with service information
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="pause pending"} 0
|
# TYPE windows_service_info gauge
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="paused"} 0
|
windows_service_info{display_name="Declared Configuration(DC) service",name="dcsvc",path_name="C:\\WINDOWS\\system32\\svchost.exe -k netsvcs -p",run_as="LocalSystem"} 1
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="running"} 0
|
windows_service_info{display_name="Designs",name="Themes",path_name="C:\\WINDOWS\\System32\\svchost.exe -k netsvcs -p",run_as="LocalSystem"} 1
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="start pending"} 0
|
# HELP windows_service_process Process of started service. The value is the creation time of the process as a unix timestamp.
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="stop pending"} 0
|
# TYPE windows_service_process gauge
|
||||||
windows_service_state{display_name="Declared Configuration(DC) service",name="dcsvc",status="stopped"} 1
|
windows_service_process{name="Themes",process_id="2856"} 1.7244891e+09
|
||||||
|
# HELP windows_service_start_mode The start mode of the service (StartMode)
|
||||||
|
# TYPE windows_service_start_mode gauge
|
||||||
|
windows_service_start_mode{name="Themes",start_mode="auto"} 1
|
||||||
|
windows_service_start_mode{name="Themes",start_mode="boot"} 0
|
||||||
|
windows_service_start_mode{name="Themes",start_mode="disabled"} 0
|
||||||
|
windows_service_start_mode{name="Themes",start_mode="manual"} 0
|
||||||
|
windows_service_start_mode{name="Themes",start_mode="system"} 0
|
||||||
|
windows_service_start_mode{name="dcsvc",start_mode="auto"} 0
|
||||||
|
windows_service_start_mode{name="dcsvc",start_mode="boot"} 0
|
||||||
|
windows_service_start_mode{name="dcsvc",start_mode="disabled"} 0
|
||||||
|
windows_service_start_mode{name="dcsvc",start_mode="manual"} 1
|
||||||
|
windows_service_start_mode{name="dcsvc",start_mode="system"} 0
|
||||||
|
# HELP windows_service_state The state of the service (State)
|
||||||
|
# TYPE windows_service_state gauge
|
||||||
|
windows_service_state{name="Themes",status="continue pending"} 0
|
||||||
|
windows_service_state{name="Themes",status="pause pending"} 0
|
||||||
|
windows_service_state{name="Themes",status="paused"} 0
|
||||||
|
windows_service_state{name="Themes",status="running"} 1
|
||||||
|
windows_service_state{name="Themes",status="start pending"} 0
|
||||||
|
windows_service_state{name="Themes",status="stop pending"} 0
|
||||||
|
windows_service_state{name="Themes",status="stopped"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="continue pending"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="pause pending"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="paused"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="running"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="start pending"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="stop pending"} 0
|
||||||
|
windows_service_state{name="dcsvc",status="stopped"} 1
|
||||||
```
|
```
|
||||||
|
|
||||||
## Useful queries
|
## Useful queries
|
||||||
@@ -163,8 +109,8 @@ groups:
|
|||||||
labels:
|
labels:
|
||||||
severity: high
|
severity: high
|
||||||
annotations:
|
annotations:
|
||||||
summary: "Service {{ $labels.exported_name }} down"
|
summary: "Service {{ $labels.name }} down"
|
||||||
description: "Service {{ $labels.exported_name }} on instance {{ $labels.instance }} has been down for more than 3 minutes."
|
description: "Service {{ $labels.name }} on instance {{ $labels.instance }} has been down for more than 3 minutes."
|
||||||
|
|
||||||
# Sends an alert when the 'mssqlserver' service is not in the running state for 3 minutes.
|
# Sends an alert when the 'mssqlserver' service is not in the running state for 3 minutes.
|
||||||
- alert: SQL Server DOWN
|
- alert: SQL Server DOWN
|
||||||
@@ -173,7 +119,7 @@ groups:
|
|||||||
labels:
|
labels:
|
||||||
severity: high
|
severity: high
|
||||||
annotations:
|
annotations:
|
||||||
summary: "Service {{ $labels.exported_name }} down"
|
summary: "Service {{ $labels.name }} down"
|
||||||
description: "Service {{ $labels.exported_name }} on instance {{ $labels.instance }} has been down for more than 3 minutes."
|
description: "Service {{ $labels.name }} on instance {{ $labels.instance }} has been down for more than 3 minutes."
|
||||||
```
|
```
|
||||||
In this example, `instance` is the target label of the host. So each alert will be processed per host, which is then used in the alert description.
|
In this example, `instance` is the target label of the host. So each alert will be processed per host, which is then used in the alert description.
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ The system collector exposes metrics about ...
|
|||||||
|||
|
|||
|
||||||
-|-
|
-|-
|
||||||
Metric name prefix | `system`
|
Metric name prefix | `system`
|
||||||
Data source | Perflib
|
Data source | Performance Counters
|
||||||
Classes | [`Win32_PerfRawData_PerfOS_System`](https://web.archive.org/web/20050830140516/http://msdn.microsoft.com/library/en-us/wmisdk/wmi/win32_perfrawdata_perfos_system.asp)
|
|
||||||
Enabled by default? | Yes
|
Enabled by default? | Yes
|
||||||
|
|
||||||
## Flags
|
## Flags
|
||||||
@@ -15,14 +14,18 @@ None
|
|||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
Name | Description | Type | Labels
|
| Name | Description | Type | Labels |
|
||||||
-----|-------------|------|-------
|
|---------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
|
||||||
`windows_system_context_switches_total` | Total number of [context switches](https://en.wikipedia.org/wiki/Context_switch) | counter | None
|
| `windows_system_context_switches_total` | Total number of [context switches](https://en.wikipedia.org/wiki/Context_switch) | counter | None |
|
||||||
`windows_system_exception_dispatches_total` | Total exceptions dispatched by the system | counter | None
|
| `windows_system_exception_dispatches_total` | Total exceptions dispatched by the system | counter | None |
|
||||||
`windows_system_processor_queue_length` | Number of threads in the processor queue. There is a single queue for processor time even on computers with multiple processors. | gauge | None
|
| `windows_system_processes` | Number of process contexts currently loaded or running on the operating system | gauge | None |
|
||||||
`windows_system_system_calls_total` | Total combined calls to Windows NT system service routines by all processes running on the computer | counter | None
|
| `windows_system_process_limit` | The size of the user-mode portion of the virtual address space of the calling process, in bytes. This value depends on the type of process, the type of processor, and the configuration of the operating system. | gauge | None |
|
||||||
`windows_system_system_up_time` | Time of last boot of system | gauge | None
|
| `windows_system_processor_queue_length` | Number of threads in the processor queue. There is a single queue for processor time even on computers with multiple processors. | gauge | None |
|
||||||
`windows_system_threads` | Number of Windows system [threads](https://en.wikipedia.org/wiki/Thread_(computing)) | gauge | None
|
| `windows_system_system_calls_total` | Total combined calls to Windows NT system service routines by all processes running on the computer | counter | None |
|
||||||
|
| `windows_system_system_up_time` | Time of last boot of system | gauge | None |
|
||||||
|
| `windows_system_threads` | Number of Windows system [threads](https://en.wikipedia.org/wiki/Thread_(computing)) | gauge | None |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
Show current number of system threads
|
Show current number of system threads
|
||||||
@@ -30,6 +33,11 @@ Show current number of system threads
|
|||||||
windows_system_threads{instance="localhost"}
|
windows_system_threads{instance="localhost"}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Show current number of processes
|
||||||
|
```
|
||||||
|
windows_system_processes{instance="localhost"}
|
||||||
|
```
|
||||||
|
|
||||||
## Useful queries
|
## Useful queries
|
||||||
Find hosts that have rebooted in the last 24 hours
|
Find hosts that have rebooted in the last 24 hours
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -17,14 +17,16 @@ None
|
|||||||
|
|
||||||
## Metrics
|
## Metrics
|
||||||
|
|
||||||
| Name | Description | Type | Labels |
|
| Name | Description | Type | Labels |
|
||||||
|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|--------|
|
|-----------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|------------|
|
||||||
| `windows_time_clock_frequency_adjustment_ppb_total` | Total adjustment made to the local system clock frequency by W32Time in parts per billion (PPB) units. 1 PPB adjustment implies the system clock was adjusted at a rate of 1 nanosecond per second (1 ns/s). The smallest possible adjustment can vary and is expected to be in the order of 100's of PPB. | counter | None |
|
| `windows_time_clock_frequency_adjustment_ppb_total` | Total adjustment made to the local system clock frequency by W32Time in parts per billion (PPB) units. 1 PPB adjustment implies the system clock was adjusted at a rate of 1 nanosecond per second (1 ns/s). The smallest possible adjustment can vary and is expected to be in the order of 100's of PPB. | counter | None |
|
||||||
| `windows_time_computed_time_offset_seconds` | The absolute time offset between the system clock and the chosen time source, as computed by the W32Time service in microseconds. When a new valid sample is available, the computed time is updated with the time offset indicated by the sample. This time is the actual time offset of the local clock. W32Time initiates clock correction by using this offset and updates the computed time in between samples with the remaining time offset that needs to be applied to the local clock. Clock accuracy can be tracked by using this performance counter with a low polling interval (for example, 256 seconds or less) and looking for the counter value to be smaller than the desired clock accuracy limit. | gauge | None |
|
| `windows_time_computed_time_offset_seconds` | The absolute time offset between the system clock and the chosen time source, as computed by the W32Time service in microseconds. When a new valid sample is available, the computed time is updated with the time offset indicated by the sample. This time is the actual time offset of the local clock. W32Time initiates clock correction by using this offset and updates the computed time in between samples with the remaining time offset that needs to be applied to the local clock. Clock accuracy can be tracked by using this performance counter with a low polling interval (for example, 256 seconds or less) and looking for the counter value to be smaller than the desired clock accuracy limit. | gauge | None |
|
||||||
| `windows_time_ntp_client_time_sources` | Active number of NTP Time sources being used by the client. This is a count of active, distinct IP addresses of time servers that are responding to this client's requests. | gauge | None |
|
| `windows_time_ntp_client_time_sources` | Active number of NTP Time sources being used by the client. This is a count of active, distinct IP addresses of time servers that are responding to this client's requests. | gauge | None |
|
||||||
| `windows_time_ntp_round_trip_delay_seconds` | Total roundtrip delay experienced by the NTP client in receiving a response from the server for the most recent request, in seconds. This is the time elapsed on the NTP client between transmitting a request to the NTP server and receiving a valid response from the server. | gauge | None |
|
| `windows_time_ntp_round_trip_delay_seconds` | Total roundtrip delay experienced by the NTP client in receiving a response from the server for the most recent request, in seconds. This is the time elapsed on the NTP client between transmitting a request to the NTP server and receiving a valid response from the server. | gauge | None |
|
||||||
| `windows_time_ntp_server_outgoing_responses_total` | Total number of requests responded to by the NTP server. | counter | None |
|
| `windows_time_ntp_server_outgoing_responses_total` | Total number of requests responded to by the NTP server. | counter | None |
|
||||||
| `windows_time_ntp_server_incoming_requests_total` | Total number of requests received by the NTP server. | counter | None |
|
| `windows_time_ntp_server_incoming_requests_total` | Total number of requests received by the NTP server. | counter | None |
|
||||||
|
| `windows_time_current_timestamp_seconds` | Current time as reported by the operating system, in [Unix time](https://en.wikipedia.org/wiki/Unix_time). See [time.Unix()](https://golang.org/pkg/time/#Unix) for details | gauge | None |
|
||||||
|
| `windows_time_timezone` | Current timezone as reported by the operating system. | gauge | `timezone` |
|
||||||
|
|
||||||
### Example metric
|
### Example metric
|
||||||
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
_This collector does not yet have explained examples, we would appreciate your help adding them!_
|
||||||
|
|||||||
284
exporter.go
284
exporter.go
@@ -11,9 +11,9 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/initiate"
|
"github.com/prometheus-community/windows_exporter/pkg/initiate"
|
||||||
|
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/pprof"
|
"net/http/pprof"
|
||||||
"os"
|
"os"
|
||||||
@@ -25,9 +25,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/config"
|
"github.com/prometheus-community/windows_exporter/pkg/config"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/httphandler"
|
||||||
winlog "github.com/prometheus-community/windows_exporter/pkg/log"
|
winlog "github.com/prometheus-community/windows_exporter/pkg/log"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/log/flag"
|
"github.com/prometheus-community/windows_exporter/pkg/log/flag"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
@@ -38,17 +38,6 @@ import (
|
|||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Same struct prometheus uses for their /version endpoint.
|
|
||||||
// Separate copy to avoid pulling all of prometheus as a dependency.
|
|
||||||
type prometheusVersion struct {
|
|
||||||
Version string `json:"version"`
|
|
||||||
Revision string `json:"revision"`
|
|
||||||
Branch string `json:"branch"`
|
|
||||||
BuildUser string `json:"buildUser"`
|
|
||||||
BuildDate string `json:"buildDate"`
|
|
||||||
GoVersion string `json:"goVersion"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapping of priority names to uin32 values required by windows.SetPriorityClass.
|
// Mapping of priority names to uin32 values required by windows.SetPriorityClass.
|
||||||
var priorityStringToInt = map[string]uint32{
|
var priorityStringToInt = map[string]uint32{
|
||||||
"realtime": windows.REALTIME_PRIORITY_CLASS,
|
"realtime": windows.REALTIME_PRIORITY_CLASS,
|
||||||
@@ -59,29 +48,13 @@ var priorityStringToInt = map[string]uint32{
|
|||||||
"low": windows.IDLE_PRIORITY_CLASS,
|
"low": windows.IDLE_PRIORITY_CLASS,
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPriorityWindows(pid int, priority uint32) error {
|
func main() {
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
os.Exit(run())
|
||||||
handle, err := windows.OpenProcess(
|
|
||||||
windows.STANDARD_RIGHTS_REQUIRED|windows.SYNCHRONIZE|windows.SPECIFIC_RIGHTS_ALL,
|
|
||||||
false, uint32(pid),
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = windows.SetPriorityClass(handle, priority); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = windows.CloseHandle(handle); err != nil {
|
|
||||||
return fmt.Errorf("failed to close handle: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func run() int {
|
||||||
app := kingpin.New("windows_exporter", "A metrics collector for Windows.")
|
app := kingpin.New("windows_exporter", "A metrics collector for Windows.")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
configFile = app.Flag(
|
configFile = app.Flag(
|
||||||
"config.file",
|
"config.file",
|
||||||
@@ -137,25 +110,41 @@ func main() {
|
|||||||
|
|
||||||
// Load values from configuration file(s). Executable flags must first be parsed, in order
|
// Load values from configuration file(s). Executable flags must first be parsed, in order
|
||||||
// to load the specified file(s).
|
// to load the specified file(s).
|
||||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
if _, err := app.Parse(os.Args[1:]); err != nil {
|
||||||
logger, err := winlog.New(winlogConfig)
|
//nolint:sloglint // we do not have an logger yet
|
||||||
if err != nil {
|
slog.Error("Failed to parse CLI args",
|
||||||
_ = level.Error(logger).Log("err", err)
|
slog.Any("err", err),
|
||||||
os.Exit(1)
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Debug(logger).Log("msg", "Logging has Started")
|
logger, err := winlog.New(winlogConfig)
|
||||||
|
if err != nil {
|
||||||
|
//nolint:sloglint // we do not have an logger yet
|
||||||
|
slog.Error("failed to create logger",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
if *configFile != "" {
|
if *configFile != "" {
|
||||||
resolver, err := config.NewResolver(*configFile, logger, *insecureSkipVerify)
|
resolver, err := config.NewResolver(*configFile, logger, *insecureSkipVerify)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "could not load config file", "err", err)
|
logger.Error("could not load config file",
|
||||||
os.Exit(1)
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
err = resolver.Bind(app, os.Args[1:])
|
|
||||||
if err != nil {
|
if err = resolver.Bind(app, os.Args[1:]); err != nil {
|
||||||
_ = level.Error(logger).Log("err", err)
|
logger.Error("Failed to bind configuration",
|
||||||
os.Exit(1)
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is temporary fix for issue #1092, calling kingpin.Parse
|
// NOTE: This is temporary fix for issue #1092, calling kingpin.Parse
|
||||||
@@ -164,34 +153,43 @@ func main() {
|
|||||||
*webConfig.WebListenAddresses = (*webConfig.WebListenAddresses)[1:]
|
*webConfig.WebListenAddresses = (*webConfig.WebListenAddresses)[1:]
|
||||||
|
|
||||||
// Parse flags once more to include those discovered in configuration file(s).
|
// Parse flags once more to include those discovered in configuration file(s).
|
||||||
kingpin.MustParse(app.Parse(os.Args[1:]))
|
if _, err = app.Parse(os.Args[1:]); err != nil {
|
||||||
|
logger.Error("Failed to parse CLI args from YAML file",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
logger, err = winlog.New(winlogConfig)
|
logger, err = winlog.New(winlogConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("err", err)
|
//nolint:sloglint // we do not have an logger yet
|
||||||
os.Exit(1)
|
slog.Error("failed to create logger",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Debug("Logging has Started")
|
||||||
|
|
||||||
if *printCollectors {
|
if *printCollectors {
|
||||||
collectorNames := collector.Available()
|
printCollectorsToStdout()
|
||||||
sort.Strings(collectorNames)
|
|
||||||
|
|
||||||
fmt.Printf("Available collectors:\n") //nolint:forbidigo
|
return 0
|
||||||
for _, n := range collectorNames {
|
|
||||||
fmt.Printf(" - %s\n", n) //nolint:forbidigo
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only set process priority if a non-default and valid value has been set
|
// Only set process priority if a non-default and valid value has been set
|
||||||
if *processPriority != "normal" && priorityStringToInt[*processPriority] != 0 {
|
if priority, ok := priorityStringToInt[*processPriority]; ok && priority != windows.NORMAL_PRIORITY_CLASS {
|
||||||
_ = level.Debug(logger).Log("msg", "setting process priority to "+*processPriority)
|
logger.Debug("setting process priority to " + *processPriority)
|
||||||
err = setPriorityWindows(os.Getpid(), priorityStringToInt[*processPriority])
|
|
||||||
if err != nil {
|
if err = setPriorityWindows(os.Getpid(), priority); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed to set process priority", "err", err)
|
logger.Error("failed to set process priority",
|
||||||
os.Exit(1)
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,79 +197,68 @@ func main() {
|
|||||||
collectors.Enable(enabledCollectorList)
|
collectors.Enable(enabledCollectorList)
|
||||||
|
|
||||||
// Initialize collectors before loading
|
// Initialize collectors before loading
|
||||||
err = collectors.Build(logger)
|
if err = collectors.Build(logger); err != nil {
|
||||||
if err != nil {
|
logger.Error("Couldn't load collectors",
|
||||||
_ = level.Error(logger).Log("msg", "Couldn't load collectors", "err", err)
|
slog.Any("err", err),
|
||||||
os.Exit(1)
|
)
|
||||||
}
|
|
||||||
err = collectors.SetPerfCounterQuery(logger)
|
return 1
|
||||||
if err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "Couldn't set performance counter query", "err", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if u, err := user.Current(); err != nil {
|
if err = collectors.SetPerfCounterQuery(logger); err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Unable to determine which user is running this exporter. More info: https://github.com/golang/go/issues/37348")
|
logger.Error("Couldn't set performance counter query",
|
||||||
} else {
|
slog.Any("err", err),
|
||||||
_ = level.Info(logger).Log("msg", fmt.Sprintf("Running as %v", u.Username))
|
)
|
||||||
|
|
||||||
if strings.Contains(u.Username, "ContainerAdministrator") || strings.Contains(u.Username, "ContainerUser") {
|
return 1
|
||||||
_ = level.Warn(logger).Log("msg", "Running as a preconfigured Windows Container user. This may mean you do not have Windows HostProcess containers configured correctly and some functionality will not work as expected.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Info(logger).Log("msg", fmt.Sprintf("Enabled collectors: %v", strings.Join(enabledCollectorList, ", ")))
|
logCurrentUser(logger)
|
||||||
|
|
||||||
|
logger.Info("Enabled collectors: " + strings.Join(enabledCollectorList, ", "))
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
mux.HandleFunc(*metricsPath, withConcurrencyLimit(*maxRequests, collectors.BuildServeHTTP(logger, *disableExporterMetrics, *timeoutMargin)))
|
mux.Handle("GET /health", httphandler.NewHealthHandler())
|
||||||
mux.HandleFunc("/health", func(w http.ResponseWriter, _ *http.Request) {
|
mux.Handle("GET /version", httphandler.NewVersionHandler())
|
||||||
w.Header().Set("Content-Type", "application/json")
|
mux.Handle("GET "+*metricsPath, httphandler.New(logger, collectors, &httphandler.Options{
|
||||||
_, err := fmt.Fprintln(w, `{"status":"ok"}`)
|
DisableExporterMetrics: *disableExporterMetrics,
|
||||||
if err != nil {
|
TimeoutMargin: *timeoutMargin,
|
||||||
_ = level.Debug(logger).Log("msg", "Failed to write to stream", "err", err)
|
MaxRequests: *maxRequests,
|
||||||
}
|
}))
|
||||||
})
|
|
||||||
mux.HandleFunc("/version", func(w http.ResponseWriter, _ *http.Request) {
|
|
||||||
// we can't use "version" directly as it is a package, and not an object that
|
|
||||||
// can be serialized.
|
|
||||||
err := json.NewEncoder(w).Encode(prometheusVersion{
|
|
||||||
Version: version.Version,
|
|
||||||
Revision: version.Revision,
|
|
||||||
Branch: version.Branch,
|
|
||||||
BuildUser: version.BuildUser,
|
|
||||||
BuildDate: version.BuildDate,
|
|
||||||
GoVersion: version.GoVersion,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
http.Error(w, fmt.Sprintf("error encoding JSON: %s", err), http.StatusInternalServerError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if *debugEnabled {
|
if *debugEnabled {
|
||||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
mux.HandleFunc("GET /debug/pprof/", pprof.Index)
|
||||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
mux.HandleFunc("GET /debug/pprof/cmdline", pprof.Cmdline)
|
||||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
mux.HandleFunc("GET /debug/pprof/profile", pprof.Profile)
|
||||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
mux.HandleFunc("GET /debug/pprof/symbol", pprof.Symbol)
|
||||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
mux.HandleFunc("GET /debug/pprof/trace", pprof.Trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Info(logger).Log("msg", "Starting windows_exporter", "version", version.Info())
|
logger.Info("Starting windows_exporter",
|
||||||
_ = level.Info(logger).Log("msg", "Build context", "build_context", version.BuildContext())
|
slog.String("version", version.Version),
|
||||||
_ = level.Debug(logger).Log("msg", "Go MAXPROCS", "procs", runtime.GOMAXPROCS(0))
|
slog.String("branch", version.Branch),
|
||||||
|
slog.String("revision", version.GetRevision()),
|
||||||
|
slog.String("goversion", version.GoVersion),
|
||||||
|
slog.String("builddate", version.BuildDate),
|
||||||
|
slog.Int("maxprocs", runtime.GOMAXPROCS(0)),
|
||||||
|
)
|
||||||
|
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
ReadHeaderTimeout: 5 * time.Second,
|
ReadHeaderTimeout: 5 * time.Second,
|
||||||
IdleTimeout: 60 * time.Second,
|
IdleTimeout: 60 * time.Second,
|
||||||
ReadTimeout: 5 * time.Second,
|
ReadTimeout: 5 * time.Second,
|
||||||
WriteTimeout: 10 * time.Minute,
|
WriteTimeout: 5 * time.Minute,
|
||||||
Handler: mux,
|
Handler: mux,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errCh := make(chan error, 1)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if err := web.ListenAndServe(server, webConfig, logger); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
if err := web.ListenAndServe(server, webConfig, logger); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
_ = level.Error(logger).Log("msg", "cannot start windows_exporter", "err", err)
|
errCh <- err
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errCh <- nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
|
||||||
@@ -279,9 +266,17 @@ func main() {
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
_ = level.Info(logger).Log("msg", "Shutting down windows_exporter via kill signal")
|
logger.Info("Shutting down windows_exporter via kill signal")
|
||||||
case <-initiate.StopCh:
|
case <-initiate.StopCh:
|
||||||
_ = level.Info(logger).Log("msg", "Shutting down windows_exporter via service control")
|
logger.Info("Shutting down windows_exporter via service control")
|
||||||
|
case err := <-errCh:
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Failed to start windows_exporter",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||||
@@ -289,24 +284,53 @@ func main() {
|
|||||||
|
|
||||||
_ = server.Shutdown(ctx)
|
_ = server.Shutdown(ctx)
|
||||||
|
|
||||||
_ = level.Info(logger).Log("msg", "windows_exporter has shut down")
|
logger.Info("windows_exporter has shut down")
|
||||||
|
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func withConcurrencyLimit(n int, next http.HandlerFunc) http.HandlerFunc {
|
func printCollectorsToStdout() {
|
||||||
if n <= 0 {
|
collectorNames := collector.Available()
|
||||||
return next
|
sort.Strings(collectorNames)
|
||||||
}
|
|
||||||
|
|
||||||
sem := make(chan struct{}, n)
|
fmt.Println("Available collectors:") //nolint:forbidigo
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
select {
|
for _, n := range collectorNames {
|
||||||
case sem <- struct{}{}:
|
fmt.Printf(" - %s\n", n) //nolint:forbidigo
|
||||||
defer func() { <-sem }()
|
}
|
||||||
default:
|
}
|
||||||
w.WriteHeader(http.StatusServiceUnavailable)
|
|
||||||
_, _ = w.Write([]byte("Too many concurrent requests"))
|
func logCurrentUser(logger *slog.Logger) {
|
||||||
return
|
if u, err := user.Current(); err == nil {
|
||||||
|
logger.Info("Running as " + u.Username)
|
||||||
|
|
||||||
|
if strings.Contains(u.Username, "ContainerAdministrator") || strings.Contains(u.Username, "ContainerUser") {
|
||||||
|
logger.Warn("Running as a preconfigured Windows Container user. This may mean you do not have Windows HostProcess containers configured correctly and some functionality will not work as expected.")
|
||||||
}
|
}
|
||||||
next(w, r)
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Warn("Unable to determine which user is running this exporter. More info: https://github.com/golang/go/issues/37348")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setPriorityWindows(pid int, priority uint32) error {
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/procthread/process-security-and-access-rights
|
||||||
|
handle, err := windows.OpenProcess(
|
||||||
|
windows.STANDARD_RIGHTS_REQUIRED|windows.SYNCHRONIZE|windows.SPECIFIC_RIGHTS_ALL,
|
||||||
|
false, uint32(pid),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open own process: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = windows.SetPriorityClass(handle, priority); err != nil {
|
||||||
|
return fmt.Errorf("failed to set priority class: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = windows.CloseHandle(handle); err != nil {
|
||||||
|
return fmt.Errorf("failed to close handle: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
45
go.mod
45
go.mod
@@ -1,56 +1,55 @@
|
|||||||
module github.com/prometheus-community/windows_exporter
|
module github.com/prometheus-community/windows_exporter
|
||||||
|
|
||||||
go 1.22
|
go 1.23
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/hcsshim v0.12.6
|
github.com/Microsoft/hcsshim v0.12.6
|
||||||
github.com/alecthomas/kingpin/v2 v2.4.0
|
github.com/alecthomas/kingpin/v2 v2.4.0
|
||||||
github.com/dimchansky/utfbom v1.1.1
|
github.com/dimchansky/utfbom v1.1.1
|
||||||
github.com/go-kit/log v0.2.1
|
|
||||||
github.com/go-ole/go-ole v1.3.0
|
github.com/go-ole/go-ole v1.3.0
|
||||||
github.com/prometheus/client_golang v1.20.2
|
github.com/google/uuid v1.6.0
|
||||||
|
github.com/pkg/errors v0.9.1
|
||||||
|
github.com/prometheus/client_golang v1.20.3
|
||||||
github.com/prometheus/client_model v0.6.1
|
github.com/prometheus/client_model v0.6.1
|
||||||
github.com/prometheus/common v0.57.0
|
github.com/prometheus/common v0.59.1
|
||||||
github.com/prometheus/exporter-toolkit v0.11.0
|
github.com/prometheus/exporter-toolkit v0.13.0
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
github.com/yusufpapurcu/wmi v1.2.4
|
github.com/yusufpapurcu/wmi v1.2.4
|
||||||
go.opencensus.io v0.24.0 // indirect
|
golang.org/x/sys v0.25.0
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
|
||||||
golang.org/x/sys v0.24.0
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/google/uuid v1.6.0
|
|
||||||
github.com/pkg/errors v0.9.1
|
|
||||||
)
|
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
|
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
github.com/containerd/cgroups/v3 v3.0.3 // indirect
|
||||||
github.com/containerd/errdefs v0.1.0 // indirect
|
github.com/containerd/errdefs v0.1.0 // indirect
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/go-logfmt/logfmt v0.5.1 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/jpillora/backoff v1.0.0 // indirect
|
github.com/jpillora/backoff v1.0.0 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/mdlayher/socket v0.5.1 // indirect
|
||||||
|
github.com/mdlayher/vsock v1.2.1 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
github.com/xhit/go-str2duration/v2 v2.1.0 // indirect
|
||||||
golang.org/x/crypto v0.25.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
golang.org/x/net v0.27.0 // indirect
|
golang.org/x/crypto v0.27.0 // indirect
|
||||||
golang.org/x/oauth2 v0.21.0 // indirect
|
golang.org/x/net v0.29.0 // indirect
|
||||||
golang.org/x/sync v0.7.0 // indirect
|
golang.org/x/oauth2 v0.23.0 // indirect
|
||||||
golang.org/x/text v0.16.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect
|
golang.org/x/text v0.18.0 // indirect
|
||||||
google.golang.org/grpc v1.65.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
|
google.golang.org/grpc v1.66.0 // indirect
|
||||||
google.golang.org/protobuf v1.34.2 // indirect
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// https://github.com/prometheus/common/pull/694
|
||||||
|
replace github.com/prometheus/common v0.59.1 => github.com/jkroepke/prometheus-common v0.0.0-20240907211841-5f9af24b97ad
|
||||||
|
|||||||
62
go.sum
62
go.sum
@@ -6,8 +6,8 @@ github.com/Microsoft/hcsshim v0.12.6 h1:qEnZjoHXv+4/s0LmKZWE0/AiZmMWEIkFfWBSf1a0
|
|||||||
github.com/Microsoft/hcsshim v0.12.6/go.mod h1:ZABCLVcvLMjIkzr9rUGcQ1QA0p0P3Ps+d3N1g2DsFfk=
|
github.com/Microsoft/hcsshim v0.12.6/go.mod h1:ZABCLVcvLMjIkzr9rUGcQ1QA0p0P3Ps+d3N1g2DsFfk=
|
||||||
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
|
github.com/alecthomas/kingpin/v2 v2.4.0 h1:f48lwail6p8zpO1bC4TxtqACaGqHYA22qkHjHpqDjYY=
|
||||||
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
github.com/alecthomas/kingpin/v2 v2.4.0/go.mod h1:0gyi0zQnjuFk8xrkNKamJoyUo382HRL7ATRpFZCw6tE=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30 h1:t3eaIm0rUkzbrIewtiFmMK5RXHej2XnoXNhxVsAYUfg=
|
||||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
github.com/alecthomas/units v0.0.0-20240626203959-61d1e3462e30/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
@@ -30,10 +30,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
|
||||||
github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
|
||||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
|
||||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
|
||||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
@@ -63,6 +59,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
|||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jkroepke/prometheus-common v0.0.0-20240907211841-5f9af24b97ad h1:sFDfDs4nDXjES8PdrFPiXeYt8dtaxn10M/Ebxe4IuiI=
|
||||||
|
github.com/jkroepke/prometheus-common v0.0.0-20240907211841-5f9af24b97ad/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
|
||||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
@@ -73,6 +71,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos=
|
||||||
|
github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ=
|
||||||
|
github.com/mdlayher/vsock v1.2.1 h1:pC1mTJTvjo1r9n9fbm7S1j04rCgCzhCOS5DY0zqHlnQ=
|
||||||
|
github.com/mdlayher/vsock v1.2.1/go.mod h1:NRfCibel++DgeMD8z/hP+PPTjlNJsdPOmxcnENvE+SE=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||||
@@ -81,15 +83,13 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
|
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
|
||||||
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
github.com/prometheus/common v0.57.0 h1:Ro/rKjwdq9mZn1K5QPctzh+MA4Lp0BuYk5ZZEVhoNcY=
|
github.com/prometheus/exporter-toolkit v0.13.0 h1:lmA0Q+8IaXgmFRKw09RldZmZdnvu9wwcDLIXGmTPw1c=
|
||||||
github.com/prometheus/common v0.57.0/go.mod h1:7uRPFSUTbfZWsJ7MHY56sqt7hLQu3bxXHDnNhl8E9qI=
|
github.com/prometheus/exporter-toolkit v0.13.0/go.mod h1:2uop99EZl80KdXhv/MxVI2181fMcwlsumFOqBecGkG0=
|
||||||
github.com/prometheus/exporter-toolkit v0.11.0 h1:yNTsuZ0aNCNFQ3aFTD2uhPOvr4iD7fdBvKPAEGkNf+g=
|
|
||||||
github.com/prometheus/exporter-toolkit v0.11.0/go.mod h1:BVnENhnNecpwoTLiABx7mrPB/OLRIgN74qlQbV+FK1Q=
|
|
||||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
@@ -99,11 +99,12 @@ github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
|
|||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc=
|
||||||
@@ -114,11 +115,9 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
|||||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ=
|
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
@@ -128,16 +127,16 @@ golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73r
|
|||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
|
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||||
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
|
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
|
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
|
||||||
golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -145,12 +144,12 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@@ -162,15 +161,15 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
|
|||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||||
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
|
google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c=
|
||||||
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
|
google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
@@ -185,7 +184,6 @@ google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWn
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package ad
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -108,15 +107,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -502,12 +501,16 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting ad metrics", "err", err)
|
logger.Error("failed collecting ad metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -668,6 +671,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DirectoryServices_DirectoryServices", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DirectoryServices_DirectoryServices", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ package adcs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
||||||
@@ -60,15 +59,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Certification Authority"}, nil
|
return []string{"Certification Authority"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.requestsPerSecond = prometheus.NewDesc(
|
c.requestsPerSecond = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "requests_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "requests_total"),
|
||||||
"Total certificate requests processed",
|
"Total certificate requests processed",
|
||||||
@@ -151,12 +150,16 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectADCSCounters(ctx, logger, ch); err != nil {
|
if err := c.collectADCSCounters(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting ADCS metrics", "err", err)
|
logger.Error("failed collecting ADCS metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,15 +180,18 @@ type perflibADCS struct {
|
|||||||
SignedCertificateTimestampListProcessingTime float64 `perflib:"Signed Certificate Timestamp List processing time (ms)"`
|
SignedCertificateTimestampListProcessingTime float64 `perflib:"Signed Certificate Timestamp List processing time (ms)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectADCSCounters(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectADCSCounters(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
dst := make([]perflibADCS, 0)
|
dst := make([]perflibADCS, 0)
|
||||||
|
|
||||||
if _, ok := ctx.PerfObjects["Certification Authority"]; !ok {
|
if _, ok := ctx.PerfObjects["Certification Authority"]; !ok {
|
||||||
return errors.New("perflib did not contain an entry for Certification Authority")
|
return errors.New("perflib did not contain an entry for Certification Authority")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Certification Authority"], &dst, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["Certification Authority"], &dst, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("perflib query for Certification Authority (ADCS) returned empty result set")
|
return errors.New("perflib query for Certification Authority (ADCS) returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
package adfs
|
package adfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -87,15 +87,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"AD FS"}, nil
|
return []string{"AD FS"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.adLoginConnectionFailures = prometheus.NewDesc(
|
c.adLoginConnectionFailures = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "ad_login_connection_failures_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "ad_login_connection_failures_total"),
|
||||||
"Total number of connection failures to an Active Directory domain controller",
|
"Total number of connection failures to an Active Directory domain controller",
|
||||||
@@ -404,9 +404,11 @@ type perflibADFS struct {
|
|||||||
FederationMetadataRequests float64 `perflib:"Federation Metadata Requests"`
|
FederationMetadataRequests float64 `perflib:"Federation Metadata Requests"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var adfsData []perflibADFS
|
var adfsData []perflibADFS
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["AD FS"], &adfsData, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["AD FS"], &adfsData, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -669,5 +671,6 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
adfsData[0].FederationMetadataRequests,
|
adfsData[0].FederationMetadataRequests,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
25
pkg/collector/cache/cache.go
vendored
25
pkg/collector/cache/cache.go
vendored
@@ -3,9 +3,9 @@
|
|||||||
package cache
|
package cache
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
@@ -74,15 +74,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Cache"}, nil
|
return []string{"Cache"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.asyncCopyReadsTotal = prometheus.NewDesc(
|
c.asyncCopyReadsTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "async_copy_reads_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "async_copy_reads_total"),
|
||||||
"(AsyncCopyReadsTotal)",
|
"(AsyncCopyReadsTotal)",
|
||||||
@@ -257,14 +257,17 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect implements the Collector interface.
|
// Collect implements the Collector interface.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting cache metrics", "err", err)
|
logger.Error("failed collecting cache metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -306,9 +309,11 @@ type perflibCache struct {
|
|||||||
SyncPinReadsTotal float64 `perflib:"Sync Pin Reads/sec"`
|
SyncPinReadsTotal float64 `perflib:"Sync Pin Reads/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []perflibCache // Single-instance class, array is required but will have single entry.
|
var dst []perflibCache // Single-instance class, array is required but will have single entry.
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Cache"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Cache"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ package collector
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/ad"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/ad"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/adcs"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/adcs"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/adfs"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/adfs"
|
||||||
@@ -44,6 +44,7 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector/perfdata"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
||||||
@@ -68,7 +69,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse.
|
// NewWithFlags To be called by the exporter for collector initialization before running kingpin.Parse.
|
||||||
func NewWithFlags(app *kingpin.Application) *Collectors {
|
func NewWithFlags(app *kingpin.Application) *MetricCollectors {
|
||||||
collectors := map[string]Collector{}
|
collectors := map[string]Collector{}
|
||||||
|
|
||||||
for name, builder := range BuildersWithFlags {
|
for name, builder := range BuildersWithFlags {
|
||||||
@@ -81,8 +82,8 @@ func NewWithFlags(app *kingpin.Application) *Collectors {
|
|||||||
// NewWithConfig To be called by the external libraries for collector initialization without running kingpin.Parse
|
// NewWithConfig To be called by the external libraries for collector initialization without running kingpin.Parse
|
||||||
//
|
//
|
||||||
//goland:noinspection GoUnusedExportedFunction
|
//goland:noinspection GoUnusedExportedFunction
|
||||||
func NewWithConfig(config Config) *Collectors {
|
func NewWithConfig(config Config) *MetricCollectors {
|
||||||
collectors := map[string]Collector{}
|
collectors := Map{}
|
||||||
collectors[ad.Name] = ad.New(&config.AD)
|
collectors[ad.Name] = ad.New(&config.AD)
|
||||||
collectors[adcs.Name] = adcs.New(&config.ADCS)
|
collectors[adcs.Name] = adcs.New(&config.ADCS)
|
||||||
collectors[adfs.Name] = adfs.New(&config.ADFS)
|
collectors[adfs.Name] = adfs.New(&config.ADFS)
|
||||||
@@ -117,6 +118,7 @@ func NewWithConfig(config Config) *Collectors {
|
|||||||
collectors[netframework_clrsecurity.Name] = netframework_clrsecurity.New(&config.NetframeworkClrsecurity)
|
collectors[netframework_clrsecurity.Name] = netframework_clrsecurity.New(&config.NetframeworkClrsecurity)
|
||||||
collectors[nps.Name] = nps.New(&config.Nps)
|
collectors[nps.Name] = nps.New(&config.Nps)
|
||||||
collectors[os.Name] = os.New(&config.Os)
|
collectors[os.Name] = os.New(&config.Os)
|
||||||
|
collectors[perfdata.Name] = perfdata.New(&config.PerfData)
|
||||||
collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk)
|
collectors[physical_disk.Name] = physical_disk.New(&config.PhysicalDisk)
|
||||||
collectors[printer.Name] = printer.New(&config.Printer)
|
collectors[printer.Name] = printer.New(&config.Printer)
|
||||||
collectors[process.Name] = process.New(&config.Process)
|
collectors[process.Name] = process.New(&config.Process)
|
||||||
@@ -140,16 +142,16 @@ func NewWithConfig(config Config) *Collectors {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New To be called by the external libraries for collector initialization.
|
// New To be called by the external libraries for collector initialization.
|
||||||
func New(collectors Map) *Collectors {
|
func New(collectors Map) *MetricCollectors {
|
||||||
return &Collectors{
|
return &MetricCollectors{
|
||||||
collectors: collectors,
|
Collectors: collectors,
|
||||||
wmiClient: &wmi.Client{
|
WMIClient: &wmi.Client{
|
||||||
AllowMissingFields: true,
|
AllowMissingFields: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collectors) SetPerfCounterQuery(logger log.Logger) error {
|
func (c *MetricCollectors) SetPerfCounterQuery(logger *slog.Logger) error {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
|
|
||||||
@@ -157,9 +159,9 @@ func (c *Collectors) SetPerfCounterQuery(logger log.Logger) error {
|
|||||||
perfIndicies []string
|
perfIndicies []string
|
||||||
)
|
)
|
||||||
|
|
||||||
perfCounterDependencies := make([]string, 0, len(c.collectors))
|
perfCounterDependencies := make([]string, 0, len(c.Collectors))
|
||||||
|
|
||||||
for _, collector := range c.collectors {
|
for _, collector := range c.Collectors {
|
||||||
perfCounterNames, err = collector.GetPerfCounter(logger)
|
perfCounterNames, err = collector.GetPerfCounter(logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -173,31 +175,31 @@ func (c *Collectors) SetPerfCounterQuery(logger log.Logger) error {
|
|||||||
perfCounterDependencies = append(perfCounterDependencies, strings.Join(perfIndicies, " "))
|
perfCounterDependencies = append(perfCounterDependencies, strings.Join(perfIndicies, " "))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.perfCounterQuery = strings.Join(perfCounterDependencies, " ")
|
c.PerfCounterQuery = strings.Join(perfCounterDependencies, " ")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable removes all collectors that not enabledCollectors.
|
// Enable removes all collectors that not enabledCollectors.
|
||||||
func (c *Collectors) Enable(enabledCollectors []string) {
|
func (c *MetricCollectors) Enable(enabledCollectors []string) {
|
||||||
for name := range c.collectors {
|
for name := range c.Collectors {
|
||||||
if !slices.Contains(enabledCollectors, name) {
|
if !slices.Contains(enabledCollectors, name) {
|
||||||
delete(c.collectors, name)
|
delete(c.Collectors, name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build To be called by the exporter for collector initialization.
|
// Build To be called by the exporter for collector initialization.
|
||||||
func (c *Collectors) Build(logger log.Logger) error {
|
func (c *MetricCollectors) Build(logger *slog.Logger) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
c.wmiClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(c.wmiClient)
|
c.WMIClient.SWbemServicesClient, err = wmi.InitializeSWbemServices(c.WMIClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("initialize SWbemServices: %w", err)
|
return fmt.Errorf("initialize SWbemServices: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, collector := range c.collectors {
|
for _, collector := range c.Collectors {
|
||||||
if err = collector.Build(logger, c.wmiClient); err != nil {
|
if err = collector.Build(logger, c.WMIClient); err != nil {
|
||||||
return fmt.Errorf("error build collector %s: %w", collector.GetName(), err)
|
return fmt.Errorf("error build collector %s: %w", collector.GetName(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,12 +208,12 @@ func (c *Collectors) Build(logger log.Logger) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrepareScrapeContext creates a ScrapeContext to be used during a single scrape.
|
// PrepareScrapeContext creates a ScrapeContext to be used during a single scrape.
|
||||||
func (c *Collectors) PrepareScrapeContext() (*types.ScrapeContext, error) {
|
func (c *MetricCollectors) PrepareScrapeContext() (*types.ScrapeContext, error) {
|
||||||
if c.perfCounterQuery == "" { // if perfCounterQuery is empty, no perf counters are needed.
|
if c.PerfCounterQuery == "" { // if perfCounterQuery is empty, no perf counters are needed.
|
||||||
return &types.ScrapeContext{}, nil
|
return &types.ScrapeContext{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
objs, err := perflib.GetPerflibSnapshot(c.perfCounterQuery)
|
objs, err := perflib.GetPerflibSnapshot(c.PerfCounterQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -220,17 +222,17 @@ func (c *Collectors) PrepareScrapeContext() (*types.ScrapeContext, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close To be called by the exporter for collector cleanup.
|
// Close To be called by the exporter for collector cleanup.
|
||||||
func (c *Collectors) Close() error {
|
func (c *MetricCollectors) Close(logger *slog.Logger) error {
|
||||||
errs := make([]error, 0, len(c.collectors))
|
errs := make([]error, 0, len(c.Collectors))
|
||||||
|
|
||||||
for _, collector := range c.collectors {
|
for _, collector := range c.Collectors {
|
||||||
if err := collector.Close(); err != nil {
|
if err := collector.Close(logger); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.wmiClient != nil && c.wmiClient.SWbemServicesClient != nil {
|
if c.WMIClient != nil && c.WMIClient.SWbemServicesClient != nil {
|
||||||
if err := c.wmiClient.SWbemServicesClient.Close(); err != nil {
|
if err := c.WMIClient.SWbemServicesClient.Close(); err != nil {
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector/perfdata"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
||||||
@@ -90,6 +91,7 @@ type Config struct {
|
|||||||
NetframeworkClrsecurity netframework_clrsecurity.Config `yaml:"netframework_clrsecurity"`
|
NetframeworkClrsecurity netframework_clrsecurity.Config `yaml:"netframework_clrsecurity"`
|
||||||
Nps nps.Config `yaml:"nps"`
|
Nps nps.Config `yaml:"nps"`
|
||||||
Os os.Config `yaml:"os"`
|
Os os.Config `yaml:"os"`
|
||||||
|
PerfData perfdata.Config `yaml:"perf_data"`
|
||||||
PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
|
PhysicalDisk physical_disk.Config `yaml:"physical_disk"`
|
||||||
Printer printer.Config `yaml:"printer"`
|
Printer printer.Config `yaml:"printer"`
|
||||||
Process process.Config `yaml:"process"`
|
Process process.Config `yaml:"process"`
|
||||||
@@ -148,6 +150,7 @@ var ConfigDefaults = Config{
|
|||||||
NetframeworkClrsecurity: netframework_clrsecurity.ConfigDefaults,
|
NetframeworkClrsecurity: netframework_clrsecurity.ConfigDefaults,
|
||||||
Nps: nps.ConfigDefaults,
|
Nps: nps.ConfigDefaults,
|
||||||
Os: os.ConfigDefaults,
|
Os: os.ConfigDefaults,
|
||||||
|
PerfData: perfdata.ConfigDefaults,
|
||||||
PhysicalDisk: physical_disk.ConfigDefaults,
|
PhysicalDisk: physical_disk.ConfigDefaults,
|
||||||
Printer: printer.ConfigDefaults,
|
Printer: printer.ConfigDefaults,
|
||||||
Process: process.ConfigDefaults,
|
Process: process.ConfigDefaults,
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ package container
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Microsoft/hcsshim"
|
"github.com/Microsoft/hcsshim"
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -79,15 +78,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.containerAvailable = prometheus.NewDesc(
|
c.containerAvailable = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "available"),
|
prometheus.BuildFQName(types.Namespace, Name, "available"),
|
||||||
"Available",
|
"Available",
|
||||||
@@ -202,21 +201,27 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(logger, ch); err != nil {
|
if err := c.collect(logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting collector metrics", "err", err)
|
logger.Error("failed collecting collector metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
// Types Container is passed to get the containers compute systems only
|
// Types Container is passed to get the containers compute systems only
|
||||||
containers, err := hcsshim.GetContainers(hcsshim.ComputeSystemQuery{Types: []string{"Container"}})
|
containers, err := hcsshim.GetContainers(hcsshim.ComputeSystemQuery{Types: []string{"Container"}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "Err in Getting containers", "err", err)
|
logger.Error("Err in Getting containers",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,9 +245,16 @@ func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) erro
|
|||||||
|
|
||||||
if err = c.collectContainer(logger, ch, containerDetails, containerIdWithPrefix); err != nil {
|
if err = c.collectContainer(logger, ch, containerDetails, containerIdWithPrefix); err != nil {
|
||||||
if hcsshim.IsNotExist(err) {
|
if hcsshim.IsNotExist(err) {
|
||||||
_ = level.Debug(logger).Log("msg", "err in fetching container statistics", "containerId", containerDetails.ID, "err", err)
|
logger.Debug("err in fetching container statistics",
|
||||||
|
slog.String("container_id", containerDetails.ID),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
_ = level.Error(logger).Log("msg", "err in fetching container statistics", "containerId", containerDetails.ID, "err", err)
|
logger.Error("err in fetching container statistics",
|
||||||
|
slog.String("container_id", containerDetails.ID),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
collectErrors = append(collectErrors, err)
|
collectErrors = append(collectErrors, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,7 +275,7 @@ func (c *Collector) collect(logger log.Logger, ch chan<- prometheus.Metric) erro
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectContainer(logger log.Logger, ch chan<- prometheus.Metric, containerDetails hcsshim.ContainerProperties, containerIdWithPrefix string) error {
|
func (c *Collector) collectContainer(logger *slog.Logger, ch chan<- prometheus.Metric, containerDetails hcsshim.ContainerProperties, containerIdWithPrefix string) error {
|
||||||
container, err := hcsshim.OpenContainer(containerDetails.ID)
|
container, err := hcsshim.OpenContainer(containerDetails.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error in opening container: %w", err)
|
return fmt.Errorf("error in opening container: %w", err)
|
||||||
@@ -275,7 +287,9 @@ func (c *Collector) collectContainer(logger log.Logger, ch chan<- prometheus.Met
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := container.Close(); err != nil {
|
if err := container.Close(); err != nil {
|
||||||
_ = level.Error(logger).Log("err", fmt.Errorf("error in closing container: %w", err))
|
logger.Error("error in closing container",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -358,22 +372,27 @@ func (c *Collector) collectContainer(logger log.Logger, ch chan<- prometheus.Met
|
|||||||
// With HNSv2, the network stats must be collected from hcsshim.HNSListEndpointRequest.
|
// With HNSv2, the network stats must be collected from hcsshim.HNSListEndpointRequest.
|
||||||
// Network statistics from the container.Statistics() are providing data only, if HNSv1 is used.
|
// Network statistics from the container.Statistics() are providing data only, if HNSv1 is used.
|
||||||
// Ref: https://github.com/prometheus-community/windows_exporter/pull/1218
|
// Ref: https://github.com/prometheus-community/windows_exporter/pull/1218
|
||||||
func (c *Collector) collectNetworkMetrics(logger log.Logger, ch chan<- prometheus.Metric, containerPrefixes map[string]string) error {
|
func (c *Collector) collectNetworkMetrics(logger *slog.Logger, ch chan<- prometheus.Metric, containerPrefixes map[string]string) error {
|
||||||
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
|
hnsEndpoints, err := hcsshim.HNSListEndpointRequest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to collect network stats for containers")
|
logger.Warn("Failed to collect network stats for containers")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(hnsEndpoints) == 0 {
|
if len(hnsEndpoints) == 0 {
|
||||||
_ = level.Info(logger).Log("msg", "No network stats for containers to collect")
|
logger.Info("No network stats for containers to collect")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, endpoint := range hnsEndpoints {
|
for _, endpoint := range hnsEndpoints {
|
||||||
endpointStats, err := hcsshim.GetHNSEndpointStats(endpoint.Id)
|
endpointStats, err := hcsshim.GetHNSEndpointStats(endpoint.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to collect network stats for interface "+endpoint.Id, "err", err)
|
logger.Warn("Failed to collect network stats for interface "+endpoint.Id,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +400,8 @@ func (c *Collector) collectNetworkMetrics(logger log.Logger, ch chan<- prometheu
|
|||||||
containerIdWithPrefix, ok := containerPrefixes[containerId]
|
containerIdWithPrefix, ok := containerPrefixes[containerId]
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
_ = level.Debug(logger).Log("msg", "Failed to collect network stats for container "+containerId)
|
logger.Debug("Failed to collect network stats for container " + containerId)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
package cpu
|
package cpu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/winversion"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
)
|
)
|
||||||
@@ -23,6 +22,7 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
logicalProcessors *prometheus.Desc
|
||||||
cStateSecondsTotal *prometheus.Desc
|
cStateSecondsTotal *prometheus.Desc
|
||||||
timeTotal *prometheus.Desc
|
timeTotal *prometheus.Desc
|
||||||
interruptsTotal *prometheus.Desc
|
interruptsTotal *prometheus.Desc
|
||||||
@@ -58,18 +58,22 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
if winversion.WindowsVersionFloat() > 6.05 {
|
return []string{"Processor Information"}, nil
|
||||||
return []string{"Processor Information"}, nil
|
|
||||||
}
|
|
||||||
return []string{"Processor"}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
|
c.logicalProcessors = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "logical_processor"),
|
||||||
|
"Total number of logical processors",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
c.cStateSecondsTotal = prometheus.NewDesc(
|
c.cStateSecondsTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"),
|
||||||
"Time spent in low-power idle state",
|
"Time spent in low-power idle state",
|
||||||
@@ -95,16 +99,6 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
// For Windows 2008 (version 6.0) or earlier we only have the "Processor"
|
|
||||||
// class. As of Windows 2008 R2 (version 6.1) the more detailed
|
|
||||||
// "Processor Information" set is available (although some of the counters
|
|
||||||
// are added in later versions, so we aren't guaranteed to get all of
|
|
||||||
// them).
|
|
||||||
// Value 6.05 was selected to split between Windows versions.
|
|
||||||
if winversion.WindowsVersionFloat() < 6.05 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
c.cStateSecondsTotal = prometheus.NewDesc(
|
c.cStateSecondsTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "cstate_seconds_total"),
|
||||||
"Time spent in low-power idle state",
|
"Time spent in low-power idle state",
|
||||||
@@ -187,113 +181,10 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if winversion.WindowsVersionFloat() > 6.05 {
|
|
||||||
return c.CollectFull(ctx, logger, ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.CollectBasic(ctx, logger, ch)
|
return c.CollectFull(ctx, logger, ch)
|
||||||
}
|
|
||||||
|
|
||||||
type perflibProcessor struct {
|
|
||||||
Name string
|
|
||||||
C1Transitions float64 `perflib:"C1 Transitions/sec"`
|
|
||||||
C2Transitions float64 `perflib:"C2 Transitions/sec"`
|
|
||||||
C3Transitions float64 `perflib:"C3 Transitions/sec"`
|
|
||||||
DPCRate float64 `perflib:"DPC Rate"`
|
|
||||||
DPCsQueued float64 `perflib:"DPCs Queued/sec"`
|
|
||||||
Interrupts float64 `perflib:"Interrupts/sec"`
|
|
||||||
PercentC1Time float64 `perflib:"% C1 Time"`
|
|
||||||
PercentC2Time float64 `perflib:"% C2 Time"`
|
|
||||||
PercentC3Time float64 `perflib:"% C3 Time"`
|
|
||||||
PercentDPCTime float64 `perflib:"% DPC Time"`
|
|
||||||
PercentIdleTime float64 `perflib:"% Idle Time"`
|
|
||||||
PercentInterruptTime float64 `perflib:"% Interrupt Time"`
|
|
||||||
PercentPrivilegedTime float64 `perflib:"% Privileged Time"`
|
|
||||||
PercentProcessorTime float64 `perflib:"% Processor Time"`
|
|
||||||
PercentUserTime float64 `perflib:"% User Time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) CollectBasic(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
logger = log.With(logger, "collector", Name)
|
|
||||||
data := make([]perflibProcessor, 0)
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Processor"], &data, logger)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, cpu := range data {
|
|
||||||
if strings.Contains(strings.ToLower(cpu.Name), "_total") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
core := cpu.Name
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.cStateSecondsTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentC1Time,
|
|
||||||
core, "c1",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.cStateSecondsTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentC2Time,
|
|
||||||
core, "c2",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.cStateSecondsTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentC3Time,
|
|
||||||
core, "c3",
|
|
||||||
)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timeTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentIdleTime,
|
|
||||||
core, "idle",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timeTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentInterruptTime,
|
|
||||||
core, "interrupt",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timeTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentDPCTime,
|
|
||||||
core, "dpc",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timeTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentPrivilegedTime,
|
|
||||||
core, "privileged",
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timeTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.PercentUserTime,
|
|
||||||
core, "user",
|
|
||||||
)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.interruptsTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.Interrupts,
|
|
||||||
core,
|
|
||||||
)
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.dpcsTotal,
|
|
||||||
prometheus.CounterValue,
|
|
||||||
cpu.DPCsQueued,
|
|
||||||
core,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type perflibProcessorInformation struct {
|
type perflibProcessorInformation struct {
|
||||||
@@ -325,20 +216,26 @@ type perflibProcessorInformation struct {
|
|||||||
UserTimeSeconds float64 `perflib:"% User Time"`
|
UserTimeSeconds float64 `perflib:"% User Time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) CollectFull(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) CollectFull(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
data := make([]perflibProcessorInformation, 0)
|
data := make([]perflibProcessorInformation, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Processor Information"], &data, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["Processor Information"], &data, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var coreCount float64
|
||||||
|
|
||||||
for _, cpu := range data {
|
for _, cpu := range data {
|
||||||
if strings.Contains(strings.ToLower(cpu.Name), "_total") {
|
if strings.Contains(strings.ToLower(cpu.Name), "_total") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
core := cpu.Name
|
core := cpu.Name
|
||||||
|
|
||||||
|
coreCount++
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.cStateSecondsTotal,
|
c.cStateSecondsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
@@ -459,5 +356,11 @@ func (c *Collector) CollectFull(ctx *types.ScrapeContext, logger log.Logger, ch
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.logicalProcessors,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
coreCount,
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ package cpu_info
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -58,15 +57,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -152,12 +151,16 @@ type win32Processor struct {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting cpu_info metrics", "err", err)
|
logger.Error("failed collecting cpu_info metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +172,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT Architecture, DeviceId, Description, Family, L2CacheSize, L3CacheSize, Name, ThreadCount, NumberOfCores, NumberOfEnabledCore, NumberOfLogicalProcessors FROM Win32_Processor", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT Architecture, DeviceId, Description, Family, L2CacheSize, L3CacheSize, Name, ThreadCount, NumberOfCores, NumberOfEnabledCore, NumberOfLogicalProcessors FROM Win32_Processor", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
package cs
|
package cs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/sysinfoapi"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/sysinfoapi"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -22,9 +22,15 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
// physicalMemoryBytes
|
||||||
|
// Deprecated: Use windows_cpu_logical_processor instead
|
||||||
physicalMemoryBytes *prometheus.Desc
|
physicalMemoryBytes *prometheus.Desc
|
||||||
logicalProcessors *prometheus.Desc
|
// logicalProcessors
|
||||||
hostname *prometheus.Desc
|
// Deprecated: Use windows_physical_memory_total_bytes instead
|
||||||
|
logicalProcessors *prometheus.Desc
|
||||||
|
// hostname
|
||||||
|
// Deprecated: Use windows_os_hostname instead
|
||||||
|
hostname *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *Config) *Collector {
|
func New(config *Config) *Collector {
|
||||||
@@ -47,30 +53,35 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
|
logger.Warn("The cs collector is deprecated and will be removed in a future release. " +
|
||||||
|
"Logical processors has been moved to cpu_info collector. " +
|
||||||
|
"Physical memory has been moved to memory collector. " +
|
||||||
|
"Hostname has been moved to os collector.")
|
||||||
|
|
||||||
c.logicalProcessors = prometheus.NewDesc(
|
c.logicalProcessors = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "logical_processors"),
|
prometheus.BuildFQName(types.Namespace, Name, "logical_processors"),
|
||||||
"ComputerSystem.NumberOfLogicalProcessors",
|
"Deprecated: Use windows_cpu_logical_processor instead",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.physicalMemoryBytes = prometheus.NewDesc(
|
c.physicalMemoryBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "physical_memory_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "physical_memory_bytes"),
|
||||||
"ComputerSystem.TotalPhysicalMemory",
|
"Deprecated: Use windows_physical_memory_total_bytes instead",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.hostname = prometheus.NewDesc(
|
c.hostname = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "hostname"),
|
prometheus.BuildFQName(types.Namespace, Name, "hostname"),
|
||||||
"Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain",
|
"Deprecated: Use windows_os_hostname instead",
|
||||||
[]string{
|
[]string{
|
||||||
"hostname",
|
"hostname",
|
||||||
"domain",
|
"domain",
|
||||||
@@ -78,17 +89,22 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting cs metrics", "err", err)
|
logger.Error("failed collecting cs metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,10 +134,12 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
domain, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSDomain)
|
domain, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSDomain)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fqdn, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSFullyQualified)
|
fqdn, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSFullyQualified)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
package dfsr
|
package dfsr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -80,13 +79,14 @@ type Collector struct {
|
|||||||
dfsrChildCollectors []dfsrCollectorFunc
|
dfsrChildCollectors []dfsrCollectorFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
type dfsrCollectorFunc func(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error
|
type dfsrCollectorFunc func(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error
|
||||||
|
|
||||||
// Map Perflib sources to DFSR Collector names
|
// Map Perflib sources to DFSR Collector names
|
||||||
// e.g, volume -> DFS Replication Service Volumes.
|
// e.g, volume -> DFS Replication Service Volumes.
|
||||||
func dfsrGetPerfObjectName(collector string) string {
|
func dfsrGetPerfObjectName(collector string) string {
|
||||||
prefix := "DFS "
|
prefix := "DFS "
|
||||||
suffix := ""
|
suffix := ""
|
||||||
|
|
||||||
switch collector {
|
switch collector {
|
||||||
case "connection":
|
case "connection":
|
||||||
suffix = "Replication Connections"
|
suffix = "Replication Connections"
|
||||||
@@ -95,6 +95,7 @@ func dfsrGetPerfObjectName(collector string) string {
|
|||||||
case "volume":
|
case "volume":
|
||||||
suffix = "Replication Service Volumes"
|
suffix = "Replication Service Volumes"
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix + suffix
|
return prefix + suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +138,7 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
// Perflib sources are dynamic, depending on the enabled child collectors
|
// Perflib sources are dynamic, depending on the enabled child collectors
|
||||||
expandedChildCollectors := slices.Compact(c.config.CollectorsEnabled)
|
expandedChildCollectors := slices.Compact(c.config.CollectorsEnabled)
|
||||||
perflibDependencies := make([]string, 0, len(expandedChildCollectors))
|
perflibDependencies := make([]string, 0, len(expandedChildCollectors))
|
||||||
@@ -149,14 +150,14 @@ func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
|||||||
return perflibDependencies, nil
|
return perflibDependencies, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
_ = level.Info(logger).Log("msg", "dfsr collector is in an experimental state! Metrics for this collector have not been tested.")
|
logger.Info("dfsr collector is in an experimental state! Metrics for this collector have not been tested.")
|
||||||
|
|
||||||
// connection
|
// connection
|
||||||
c.connectionBandwidthSavingsUsingDFSReplicationTotal = prometheus.NewDesc(
|
c.connectionBandwidthSavingsUsingDFSReplicationTotal = prometheus.NewDesc(
|
||||||
@@ -459,6 +460,7 @@ func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
|||||||
// for use in Collector.Collect().
|
// for use in Collector.Collect().
|
||||||
func (c *Collector) getDFSRChildCollectors(enabledCollectors []string) []dfsrCollectorFunc {
|
func (c *Collector) getDFSRChildCollectors(enabledCollectors []string) []dfsrCollectorFunc {
|
||||||
var dfsrCollectors []dfsrCollectorFunc
|
var dfsrCollectors []dfsrCollectorFunc
|
||||||
|
|
||||||
for _, collector := range enabledCollectors {
|
for _, collector := range enabledCollectors {
|
||||||
switch collector {
|
switch collector {
|
||||||
case "connection":
|
case "connection":
|
||||||
@@ -475,14 +477,15 @@ func (c *Collector) getDFSRChildCollectors(enabledCollectors []string) []dfsrCol
|
|||||||
|
|
||||||
// Collect implements the Collector interface.
|
// Collect implements the Collector interface.
|
||||||
// Sends metric values for each metric to the provided prometheus Metric channel.
|
// Sends metric values for each metric to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
for _, fn := range c.dfsrChildCollectors {
|
for _, fn := range c.dfsrChildCollectors {
|
||||||
err := fn(ctx, logger, ch)
|
err := fn(ctx, logger, ch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,9 +504,11 @@ type PerflibDFSRConnection struct {
|
|||||||
SizeOfFilesReceivedTotal float64 `perflib:"Size of Files Received"`
|
SizeOfFilesReceivedTotal float64 `perflib:"Size of Files Received"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectConnection(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectConnection(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []PerflibDFSRConnection
|
var dst []PerflibDFSRConnection
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replication Connections"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replication Connections"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -572,6 +577,7 @@ func (c *Collector) collectConnection(ctx *types.ScrapeContext, logger log.Logge
|
|||||||
connection.Name,
|
connection.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,9 +614,11 @@ type perflibDFSRFolder struct {
|
|||||||
UpdatesDroppedTotal float64 `perflib:"Updates Dropped"`
|
UpdatesDroppedTotal float64 `perflib:"Updates Dropped"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectFolder(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectFolder(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []perflibDFSRFolder
|
var dst []perflibDFSRFolder
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replicated Folders"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replicated Folders"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -805,6 +813,7 @@ func (c *Collector) collectFolder(ctx *types.ScrapeContext, logger log.Logger, c
|
|||||||
folder.Name,
|
folder.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,9 +828,11 @@ type perflibDFSRVolume struct {
|
|||||||
USNJournalUnreadPercentage float64 `perflib:"USN Journal Records Unread Percentage"`
|
USNJournalUnreadPercentage float64 `perflib:"USN Journal Records Unread Percentage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectVolume(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectVolume(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []perflibDFSRVolume
|
var dst []perflibDFSRVolume
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replication Service Volumes"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["DFS Replication Service Volumes"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -862,5 +873,6 @@ func (c *Collector) collectVolume(ctx *types.ScrapeContext, logger log.Logger, c
|
|||||||
volume.Name,
|
volume.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
package dhcp
|
package dhcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -68,15 +69,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"DHCP Server"}, nil
|
return []string{"DHCP Server"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.packetsReceivedTotal = prometheus.NewDesc(
|
c.packetsReceivedTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "packets_received_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "packets_received_total"),
|
||||||
"Total number of packets received by the DHCP server (PacketsReceivedTotal)",
|
"Total number of packets received by the DHCP server (PacketsReceivedTotal)",
|
||||||
@@ -227,6 +228,7 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,9 +263,11 @@ type dhcpPerf struct {
|
|||||||
FailoverBndupdDropped float64 `perflib:"Failover: BndUpd Dropped."`
|
FailoverBndupdDropped float64 `perflib:"Failover: BndUpd Dropped."`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dhcpPerfs []dhcpPerf
|
var dhcpPerfs []dhcpPerf
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["DHCP Server"], &dhcpPerfs, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["DHCP Server"], &dhcpPerfs, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ package diskdrive
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -55,15 +54,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -161,12 +160,16 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Collect sends the metric values for each metric to the provided prometheus Metric channel.
|
// Collect sends the metric values for each metric to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting disk_drive_info metrics", "err", err)
|
logger.Error("failed collecting disk_drive_info metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +179,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query(win32DiskQuery, &dst); err != nil {
|
if err := c.wmiClient.Query(win32DiskQuery, &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -68,15 +67,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -215,17 +214,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting dns metrics", "err", err)
|
logger.Error("failed collecting dns metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +284,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DNS_DNS", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_DNS_DNS", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,11 @@ package exchange
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -103,6 +102,7 @@ func NewWithFlags(app *kingpin.Application) *Collector {
|
|||||||
c.config.CollectorsEnabled = make([]string, 0)
|
c.config.CollectorsEnabled = make([]string, 0)
|
||||||
|
|
||||||
var listAllCollectors bool
|
var listAllCollectors bool
|
||||||
|
|
||||||
var collectorsEnabled string
|
var collectorsEnabled string
|
||||||
|
|
||||||
app.Flag(
|
app.Flag(
|
||||||
@@ -158,7 +158,7 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
"MSExchange ADAccess Processes",
|
"MSExchange ADAccess Processes",
|
||||||
"MSExchangeTransport Queues",
|
"MSExchangeTransport Queues",
|
||||||
@@ -173,11 +173,11 @@ func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
// desc creates a new prometheus description
|
// desc creates a new prometheus description
|
||||||
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(
|
return prometheus.NewDesc(
|
||||||
@@ -231,9 +231,9 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect collects exchange metrics and sends them to prometheus.
|
// Collect collects exchange metrics and sends them to prometheus.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
collectorFuncs := map[string]func(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error{
|
collectorFuncs := map[string]func(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error{
|
||||||
"ADAccessProcesses": c.collectADAccessProcesses,
|
"ADAccessProcesses": c.collectADAccessProcesses,
|
||||||
"TransportQueues": c.collectTransportQueues,
|
"TransportQueues": c.collectTransportQueues,
|
||||||
"HttpProxy": c.collectHTTPProxy,
|
"HttpProxy": c.collectHTTPProxy,
|
||||||
@@ -248,10 +248,14 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
|
|
||||||
for _, collectorName := range c.config.CollectorsEnabled {
|
for _, collectorName := range c.config.CollectorsEnabled {
|
||||||
if err := collectorFuncs[collectorName](ctx, logger, ch); err != nil {
|
if err := collectorFuncs[collectorName](ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "Error in "+collectorName, "err", err)
|
logger.Error("Error in "+collectorName,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,14 +270,17 @@ type perflibADAccessProcesses struct {
|
|||||||
LongRunningLDAPOperationsPerMin float64 `perflib:"Long Running LDAP Operations/min"`
|
LongRunningLDAPOperationsPerMin float64 `perflib:"Long Running LDAP Operations/min"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectADAccessProcesses(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectADAccessProcesses(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibADAccessProcesses
|
var data []perflibADAccessProcesses
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange ADAccess Processes"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange ADAccess Processes"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
labelUseCount := make(map[string]int)
|
labelUseCount := make(map[string]int)
|
||||||
|
|
||||||
for _, proc := range data {
|
for _, proc := range data {
|
||||||
labelName := c.toLabelName(proc.Name)
|
labelName := c.toLabelName(proc.Name)
|
||||||
if strings.HasSuffix(labelName, "_total") {
|
if strings.HasSuffix(labelName, "_total") {
|
||||||
@@ -317,6 +324,7 @@ func (c *Collector) collectADAccessProcesses(ctx *types.ScrapeContext, logger lo
|
|||||||
labelName,
|
labelName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,9 +333,11 @@ type perflibAvailabilityService struct {
|
|||||||
RequestsSec float64 `perflib:"Availability Requests (sec)"`
|
RequestsSec float64 `perflib:"Availability Requests (sec)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAvailabilityService(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectAvailabilityService(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibAvailabilityService
|
var data []perflibAvailabilityService
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange Availability Service"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange Availability Service"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -339,6 +349,7 @@ func (c *Collector) collectAvailabilityService(ctx *types.ScrapeContext, logger
|
|||||||
availservice.RequestsSec,
|
availservice.RequestsSec,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,9 +365,11 @@ type perflibHTTPProxy struct {
|
|||||||
ProxyRequestsPerSec float64 `perflib:"Proxy Requests/Sec"`
|
ProxyRequestsPerSec float64 `perflib:"Proxy Requests/Sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectHTTPProxy(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectHTTPProxy(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibHTTPProxy
|
var data []perflibHTTPProxy
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange HttpProxy"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange HttpProxy"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -400,6 +413,7 @@ func (c *Collector) collectHTTPProxy(ctx *types.ScrapeContext, logger log.Logger
|
|||||||
labelName,
|
labelName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,9 +423,11 @@ type perflibOWA struct {
|
|||||||
RequestsPerSec float64 `perflib:"Requests/sec"`
|
RequestsPerSec float64 `perflib:"Requests/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectOWA(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectOWA(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibOWA
|
var data []perflibOWA
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange OWA"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange OWA"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -428,6 +444,7 @@ func (c *Collector) collectOWA(ctx *types.ScrapeContext, logger log.Logger, ch c
|
|||||||
owa.RequestsPerSec,
|
owa.RequestsPerSec,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,9 +455,11 @@ type perflibActiveSync struct {
|
|||||||
SyncCommandsPerSec float64 `perflib:"Sync Commands/sec"`
|
SyncCommandsPerSec float64 `perflib:"Sync Commands/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectActiveSync(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectActiveSync(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibActiveSync
|
var data []perflibActiveSync
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange ActiveSync"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange ActiveSync"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -462,6 +481,7 @@ func (c *Collector) collectActiveSync(ctx *types.ScrapeContext, logger log.Logge
|
|||||||
instance.SyncCommandsPerSec,
|
instance.SyncCommandsPerSec,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,9 +495,11 @@ type perflibRPCClientAccess struct {
|
|||||||
UserCount float64 `perflib:"User Count"`
|
UserCount float64 `perflib:"User Count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectRPC(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectRPC(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibRPCClientAccess
|
var data []perflibRPCClientAccess
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange RpcClientAccess"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange RpcClientAccess"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -532,9 +554,11 @@ type perflibTransportQueues struct {
|
|||||||
PoisonQueueLength float64 `perflib:"Poison Queue Length"`
|
PoisonQueueLength float64 `perflib:"Poison Queue Length"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectTransportQueues(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectTransportQueues(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibTransportQueues
|
var data []perflibTransportQueues
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchangeTransport Queues"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchangeTransport Queues"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -593,6 +617,7 @@ func (c *Collector) collectTransportQueues(ctx *types.ScrapeContext, logger log.
|
|||||||
labelName,
|
labelName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -607,9 +632,11 @@ type perflibWorkloadManagementWorkloads struct {
|
|||||||
IsActive float64 `perflib:"Active"`
|
IsActive float64 `perflib:"Active"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectWorkloadManagementWorkloads(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectWorkloadManagementWorkloads(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibWorkloadManagementWorkloads
|
var data []perflibWorkloadManagementWorkloads
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange WorkloadManagement Workloads"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange WorkloadManagement Workloads"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -659,12 +686,15 @@ type perflibAutodiscover struct {
|
|||||||
RequestsPerSec float64 `perflib:"Requests/sec"`
|
RequestsPerSec float64 `perflib:"Requests/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAutoDiscover(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectAutoDiscover(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibAutodiscover
|
var data []perflibAutodiscover
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchangeAutodiscover"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchangeAutodiscover"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, autodisc := range data {
|
for _, autodisc := range data {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.autoDiscoverRequestsPerSec,
|
c.autoDiscoverRequestsPerSec,
|
||||||
@@ -672,6 +702,7 @@ func (c *Collector) collectAutoDiscover(ctx *types.ScrapeContext, logger log.Log
|
|||||||
autodisc.RequestsPerSec,
|
autodisc.RequestsPerSec,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -680,9 +711,11 @@ type perflibMapiHttpEmsmdb struct {
|
|||||||
ActiveUserCount float64 `perflib:"Active User Count"`
|
ActiveUserCount float64 `perflib:"Active User Count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectMapiHttpEmsmdb(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectMapiHttpEmsmdb(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibMapiHttpEmsmdb
|
var data []perflibMapiHttpEmsmdb
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange MapiHttp Emsmdb"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["MSExchange MapiHttp Emsmdb"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -702,6 +735,7 @@ func (c *Collector) collectMapiHttpEmsmdb(ctx *types.ScrapeContext, logger log.L
|
|||||||
func (c *Collector) toLabelName(name string) string {
|
func (c *Collector) toLabelName(name string) string {
|
||||||
s := strings.ReplaceAll(strings.Join(strings.Fields(strings.ToLower(name)), "_"), ".", "_")
|
s := strings.ReplaceAll(strings.Join(strings.Fields(strings.ToLower(name)), "_"), ".", "_")
|
||||||
s = strings.ReplaceAll(s, "__", "_")
|
s = strings.ReplaceAll(s, "__", "_")
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package fsrmquota
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -56,15 +55,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -125,17 +124,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"path", "template"},
|
[]string{"path", "template"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting fsrmquota metrics", "err", err)
|
logger.Error("failed collecting fsrmquota metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +162,7 @@ type MSFT_FSRMQuota struct {
|
|||||||
|
|
||||||
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||||
var dst []MSFT_FSRMQuota
|
var dst []MSFT_FSRMQuota
|
||||||
|
|
||||||
var count int
|
var count int
|
||||||
|
|
||||||
if err := c.wmiClient.Query("SELECT * FROM MSFT_FSRMQuota", &dst, nil, "root/microsoft/windows/fsrm"); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM MSFT_FSRMQuota", &dst, nil, "root/microsoft/windows/fsrm"); err != nil {
|
||||||
@@ -225,5 +230,6 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(count),
|
float64(count),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
//go:build windows
|
|
||||||
|
|
||||||
package collector
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
stdlog "log"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/collectors/version"
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Collectors) BuildServeHTTP(logger log.Logger, disableExporterMetrics bool, timeoutMargin float64) http.HandlerFunc {
|
|
||||||
collectorFactory := func(timeout time.Duration, requestedCollectors []string) (error, *Prometheus) {
|
|
||||||
filteredCollectors := make(map[string]Collector)
|
|
||||||
// scrape all enabled collectors if no collector is requested
|
|
||||||
if len(requestedCollectors) == 0 {
|
|
||||||
filteredCollectors = c.collectors
|
|
||||||
}
|
|
||||||
for _, name := range requestedCollectors {
|
|
||||||
col, exists := c.collectors[name]
|
|
||||||
if !exists {
|
|
||||||
return fmt.Errorf("unavailable collector: %s", name), nil
|
|
||||||
}
|
|
||||||
filteredCollectors[name] = col
|
|
||||||
}
|
|
||||||
|
|
||||||
filtered := Collectors{
|
|
||||||
collectors: filteredCollectors,
|
|
||||||
perfCounterQuery: c.perfCounterQuery,
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, NewPrometheus(timeout, &filtered, logger)
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
logger := log.With(logger, "remote", r.RemoteAddr, "correlation_id", uuid.New().String())
|
|
||||||
|
|
||||||
const defaultTimeout = 10.0
|
|
||||||
|
|
||||||
var timeoutSeconds float64
|
|
||||||
if v := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds"); v != "" {
|
|
||||||
var err error
|
|
||||||
timeoutSeconds, err = strconv.ParseFloat(v, 64)
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Couldn't parse X-Prometheus-Scrape-Timeout-Seconds: %q. Defaulting timeout to %f", v, defaultTimeout))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if timeoutSeconds == 0 {
|
|
||||||
timeoutSeconds = defaultTimeout
|
|
||||||
}
|
|
||||||
timeoutSeconds -= timeoutMargin
|
|
||||||
|
|
||||||
reg := prometheus.NewRegistry()
|
|
||||||
err, wc := collectorFactory(time.Duration(timeoutSeconds*float64(time.Second)), r.URL.Query()["collect[]"])
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", "Couldn't create filtered metrics handler", "err", err)
|
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
reg.MustRegister(wc)
|
|
||||||
if !disableExporterMetrics {
|
|
||||||
reg.MustRegister(
|
|
||||||
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
|
||||||
collectors.NewGoCollector(),
|
|
||||||
version.NewCollector("windows_exporter"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
h := promhttp.HandlerFor(reg, promhttp.HandlerOpts{
|
|
||||||
ErrorLog: stdlog.New(log.NewStdlibAdapter(level.Error(logger)), "", stdlog.Lshortfile),
|
|
||||||
})
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,11 +5,10 @@ package hyperv
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -161,15 +160,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -750,70 +749,107 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"vm"},
|
[]string{"vm"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectVmHealth(ch); err != nil {
|
if err := c.collectVmHealth(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV health status metrics", "err", err)
|
logger.Error("failed collecting hyperV health status metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmVid(ch); err != nil {
|
if err := c.collectVmVid(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV pages metrics", "err", err)
|
logger.Error("failed collecting hyperV pages metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmHv(ch); err != nil {
|
if err := c.collectVmHv(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV hv status metrics", "err", err)
|
logger.Error("failed collecting hyperV hv status metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmProcessor(ch); err != nil {
|
if err := c.collectVmProcessor(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV processor metrics", "err", err)
|
logger.Error("failed collecting hyperV processor metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectHostLPUsage(logger, ch); err != nil {
|
if err := c.collectHostLPUsage(logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV host logical processors metrics", "err", err)
|
logger.Error("failed collecting hyperV host logical processors metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectHostCpuUsage(logger, ch); err != nil {
|
if err := c.collectHostCpuUsage(logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV host CPU metrics", "err", err)
|
logger.Error("failed collecting hyperV host CPU metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmCpuUsage(logger, ch); err != nil {
|
if err := c.collectVmCpuUsage(logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV VM CPU metrics", "err", err)
|
logger.Error("failed collecting hyperV VM CPU metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmSwitch(ch); err != nil {
|
if err := c.collectVmSwitch(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV switch metrics", "err", err)
|
logger.Error("failed collecting hyperV switch metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmEthernet(ch); err != nil {
|
if err := c.collectVmEthernet(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV ethernet metrics", "err", err)
|
logger.Error("failed collecting hyperV ethernet metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmStorage(ch); err != nil {
|
if err := c.collectVmStorage(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV virtual storage metrics", "err", err)
|
logger.Error("failed collecting hyperV virtual storage metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmNetwork(ch); err != nil {
|
if err := c.collectVmNetwork(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV virtual network metrics", "err", err)
|
logger.Error("failed collecting hyperV virtual network metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectVmMemory(ch); err != nil {
|
if err := c.collectVmMemory(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting hyperV virtual memory metrics", "err", err)
|
logger.Error("failed collecting hyperV virtual memory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,7 +1122,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor struct {
|
|||||||
PercentTotalRunTime uint
|
PercentTotalRunTime uint
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectHostLPUsage(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectHostLPUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor
|
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor
|
||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorLogicalProcessor", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1096,12 +1132,15 @@ func (c *Collector) collectHostLPUsage(logger log.Logger, ch chan<- prometheus.M
|
|||||||
if strings.Contains(obj.Name, "_Total") {
|
if strings.Contains(obj.Name, "_Total") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// The name format is Hv LP <core id>
|
// The name format is Hv LP <core id>
|
||||||
parts := strings.Split(obj.Name, " ")
|
parts := strings.Split(obj.Name, " ")
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Unexpected format of Name in collectHostLPUsage: %q", obj.Name))
|
logger.Warn(fmt.Sprintf("Unexpected format of Name in collectHostLPUsage: %q", obj.Name))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
coreId := parts[2]
|
coreId := parts[2]
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -1139,7 +1178,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor struct {
|
|||||||
CPUWaitTimePerDispatch uint64
|
CPUWaitTimePerDispatch uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectHostCpuUsage(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectHostCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor
|
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor
|
||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorRootVirtualProcessor", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1149,12 +1188,15 @@ func (c *Collector) collectHostCpuUsage(logger log.Logger, ch chan<- prometheus.
|
|||||||
if strings.Contains(obj.Name, "_Total") {
|
if strings.Contains(obj.Name, "_Total") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// The name format is Root VP <core id>
|
// The name format is Root VP <core id>
|
||||||
parts := strings.Split(obj.Name, " ")
|
parts := strings.Split(obj.Name, " ")
|
||||||
if len(parts) != 3 {
|
if len(parts) != 3 {
|
||||||
_ = level.Warn(logger).Log("msg", "Unexpected format of Name in collectHostCpuUsage: "+obj.Name)
|
logger.Warn("Unexpected format of Name in collectHostCpuUsage: " + obj.Name)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
coreId := parts[2]
|
coreId := parts[2]
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -1206,7 +1248,7 @@ type Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor struct {
|
|||||||
CPUWaitTimePerDispatch uint64
|
CPUWaitTimePerDispatch uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectVmCpuUsage(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectVmCpuUsage(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
|
var dst []Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor
|
||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_HvStats_HyperVHypervisorVirtualProcessor", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1216,17 +1258,22 @@ func (c *Collector) collectVmCpuUsage(logger log.Logger, ch chan<- prometheus.Me
|
|||||||
if strings.Contains(obj.Name, "_Total") {
|
if strings.Contains(obj.Name, "_Total") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// The name format is <VM Name>:Hv VP <vcore id>
|
// The name format is <VM Name>:Hv VP <vcore id>
|
||||||
parts := strings.Split(obj.Name, ":")
|
parts := strings.Split(obj.Name, ":")
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Unexpected format of Name in collectVmCpuUsage: %q, expected %q. Skipping.", obj.Name, "<VM Name>:Hv VP <vcore id>"))
|
logger.Warn(fmt.Sprintf("Unexpected format of Name in collectVmCpuUsage: %q, expected %q. Skipping.", obj.Name, "<VM Name>:Hv VP <vcore id>"))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
coreParts := strings.Split(parts[1], " ")
|
coreParts := strings.Split(parts[1], " ")
|
||||||
if len(coreParts) != 3 {
|
if len(coreParts) != 3 {
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Unexpected format of core identifier in collectVmCpuUsage: %q, expected %q. Skipping.", parts[1], "Hv VP <vcore id>"))
|
logger.Warn(fmt.Sprintf("Unexpected format of core identifier in collectVmCpuUsage: %q, expected %q. Skipping.", parts[1], "Hv VP <vcore id>"))
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
vmName := parts[0]
|
vmName := parts[0]
|
||||||
coreId := coreParts[2]
|
coreId := coreParts[2]
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ package iis
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -250,7 +249,7 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
"Web Service",
|
"Web Service",
|
||||||
"APP_POOL_WAS",
|
"APP_POOL_WAS",
|
||||||
@@ -259,12 +258,12 @@ func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
c.iisVersion = getIISVersion(logger)
|
c.iisVersion = getIISVersion(logger)
|
||||||
|
|
||||||
@@ -894,31 +893,44 @@ type simpleVersion struct {
|
|||||||
minor uint64
|
minor uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func getIISVersion(logger log.Logger) simpleVersion {
|
func getIISVersion(logger *slog.Logger) simpleVersion {
|
||||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\InetStp\`, registry.QUERY_VALUE)
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\InetStp\`, registry.QUERY_VALUE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Couldn't open registry to determine IIS version", "err", err)
|
logger.Warn("Couldn't open registry to determine IIS version",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return simpleVersion{}
|
return simpleVersion{}
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = k.Close()
|
err = k.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to close registry key", "err", err)
|
logger.Warn("Failed to close registry key",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
major, _, err := k.GetIntegerValue("MajorVersion")
|
major, _, err := k.GetIntegerValue("MajorVersion")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Couldn't open registry to determine IIS version", "err", err)
|
logger.Warn("Couldn't open registry to determine IIS version",
|
||||||
return simpleVersion{}
|
slog.Any("err", err),
|
||||||
}
|
)
|
||||||
minor, _, err := k.GetIntegerValue("MinorVersion")
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", "Couldn't open registry to determine IIS version", "err", err)
|
|
||||||
return simpleVersion{}
|
return simpleVersion{}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("Detected IIS %d.%d\n", major, minor))
|
minor, _, err := k.GetIntegerValue("MinorVersion")
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("Couldn't open registry to determine IIS version",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return simpleVersion{}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug(fmt.Sprintf("Detected IIS %d.%d\n", major, minor))
|
||||||
|
|
||||||
return simpleVersion{
|
return simpleVersion{
|
||||||
major: major,
|
major: major,
|
||||||
@@ -928,25 +940,37 @@ func getIISVersion(logger log.Logger) simpleVersion {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectWebService(ctx, logger, ch); err != nil {
|
if err := c.collectWebService(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting iis metrics", "err", err)
|
logger.Error("failed collecting iis metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectAPP_POOL_WAS(ctx, logger, ch); err != nil {
|
if err := c.collectAPP_POOL_WAS(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting iis metrics", "err", err)
|
logger.Error("failed collecting iis metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectW3SVC_W3WP(ctx, logger, ch); err != nil {
|
if err := c.collectW3SVC_W3WP(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting iis metrics", "err", err)
|
logger.Error("failed collecting iis metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectWebServiceCache(ctx, logger, ch); err != nil {
|
if err := c.collectWebServiceCache(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting iis metrics", "err", err)
|
logger.Error("failed collecting iis metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,12 +1064,15 @@ func dedupIISNames[V hasGetIISName](services []V) map[string]V {
|
|||||||
name := strings.Split(entry.getIISName(), "#")[0]
|
name := strings.Split(entry.getIISName(), "#")[0]
|
||||||
webServiceDeDuplicated[name] = entry
|
webServiceDeDuplicated[name] = entry
|
||||||
}
|
}
|
||||||
|
|
||||||
return webServiceDeDuplicated
|
return webServiceDeDuplicated
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectWebService(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectWebService(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var webService []perflibWebService
|
var webService []perflibWebService
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Web Service"], &webService, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Web Service"], &webService, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1336,9 +1363,11 @@ var applicationStates = map[uint32]string{
|
|||||||
7: "Delete Pending",
|
7: "Delete Pending",
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAPP_POOL_WAS(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectAPP_POOL_WAS(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var APP_POOL_WAS []perflibAPP_POOL_WAS
|
var APP_POOL_WAS []perflibAPP_POOL_WAS
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["APP_POOL_WAS"], &APP_POOL_WAS, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["APP_POOL_WAS"], &APP_POOL_WAS, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1514,9 +1543,11 @@ type perflibW3SVC_W3WP_IIS8 struct {
|
|||||||
WebSocketConnectionsRejected float64 `perflib:"WebSocket Connections Rejected / Sec"`
|
WebSocketConnectionsRejected float64 `perflib:"WebSocket Connections Rejected / Sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectW3SVC_W3WP(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectW3SVC_W3WP(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var W3SVC_W3WP []perflibW3SVC_W3WP
|
var W3SVC_W3WP []perflibW3SVC_W3WP
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["W3SVC_W3WP"], &W3SVC_W3WP, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["W3SVC_W3WP"], &W3SVC_W3WP, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -1526,6 +1557,7 @@ func (c *Collector) collectW3SVC_W3WP(ctx *types.ScrapeContext, logger log.Logge
|
|||||||
for w3Name, app := range w3svcW3WPDeduplicated {
|
for w3Name, app := range w3svcW3WPDeduplicated {
|
||||||
// Extract the apppool name from the format <PID>_<NAME>
|
// Extract the apppool name from the format <PID>_<NAME>
|
||||||
pid := workerProcessNameExtractor.ReplaceAllString(w3Name, "$1")
|
pid := workerProcessNameExtractor.ReplaceAllString(w3Name, "$1")
|
||||||
|
|
||||||
name := workerProcessNameExtractor.ReplaceAllString(w3Name, "$2")
|
name := workerProcessNameExtractor.ReplaceAllString(w3Name, "$2")
|
||||||
if name == "" || name == "_Total" ||
|
if name == "" || name == "_Total" ||
|
||||||
c.config.AppExclude.MatchString(name) ||
|
c.config.AppExclude.MatchString(name) ||
|
||||||
@@ -1784,6 +1816,7 @@ func (c *Collector) collectW3SVC_W3WP(ctx *types.ScrapeContext, logger log.Logge
|
|||||||
for w3Name, app := range w3svcW3WPIIS8Deduplicated {
|
for w3Name, app := range w3svcW3WPIIS8Deduplicated {
|
||||||
// Extract the apppool name from the format <PID>_<NAME>
|
// Extract the apppool name from the format <PID>_<NAME>
|
||||||
pid := workerProcessNameExtractor.ReplaceAllString(w3Name, "$1")
|
pid := workerProcessNameExtractor.ReplaceAllString(w3Name, "$1")
|
||||||
|
|
||||||
name := workerProcessNameExtractor.ReplaceAllString(w3Name, "$2")
|
name := workerProcessNameExtractor.ReplaceAllString(w3Name, "$2")
|
||||||
if name == "" || name == "_Total" ||
|
if name == "" || name == "_Total" ||
|
||||||
c.config.AppExclude.MatchString(name) ||
|
c.config.AppExclude.MatchString(name) ||
|
||||||
@@ -1912,9 +1945,11 @@ type perflibWebServiceCache struct {
|
|||||||
ServiceCache_OutputCacheQueriesTotal float64
|
ServiceCache_OutputCacheQueriesTotal float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectWebServiceCache(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectWebServiceCache(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var WebServiceCache []perflibWebServiceCache
|
var WebServiceCache []perflibWebServiceCache
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Web Service Cache"], &WebServiceCache, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Web Service Cache"], &WebServiceCache, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
package license
|
package license
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/slc"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/slc"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -53,15 +53,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.licenseStatus = prometheus.NewDesc(
|
c.licenseStatus = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "status"),
|
prometheus.BuildFQName(types.Namespace, Name, "status"),
|
||||||
"Status of windows license",
|
"Status of windows license",
|
||||||
@@ -74,12 +74,16 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting license metrics", "err", err)
|
logger.Error("failed collecting license metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ package logical_disk
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -124,15 +123,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"LogicalDisk"}, nil
|
return []string{"LogicalDisk"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.information = prometheus.NewDesc(
|
c.information = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
||||||
"A metric with a constant '1' value labeled with logical disk information",
|
"A metric with a constant '1' value labeled with logical disk information",
|
||||||
@@ -262,12 +261,16 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting logical_disk metrics", "err", err)
|
logger.Error("failed collecting logical_disk metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,8 +297,9 @@ type logicalDisk struct {
|
|||||||
AvgDiskSecPerTransfer float64 `perflib:"Avg. Disk sec/Transfer"`
|
AvgDiskSecPerTransfer float64 `perflib:"Avg. Disk sec/Transfer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
diskID string
|
diskID string
|
||||||
@@ -316,12 +320,16 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
|
|
||||||
diskID, err = getDiskIDByVolume(volume.Name)
|
diskID, err = getDiskIDByVolume(volume.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "failed to get disk ID for "+volume.Name, "err", err)
|
logger.Warn("failed to get disk ID for "+volume.Name,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err = getVolumeInfo(volume.Name)
|
info, err = getVolumeInfo(volume.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "failed to get volume information for %s"+volume.Name, "err", err)
|
logger.Warn("failed to get volume information for %s"+volume.Name,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -480,11 +488,13 @@ const diskExtentSize = 24
|
|||||||
func getDiskIDByVolume(rootDrive string) (string, error) {
|
func getDiskIDByVolume(rootDrive string) (string, error) {
|
||||||
// Open a volume handle to the Disk Root.
|
// Open a volume handle to the Disk Root.
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
var f windows.Handle
|
var f windows.Handle
|
||||||
|
|
||||||
// mode has to include FILE_SHARE permission to allow concurrent access to the disk.
|
// mode has to include FILE_SHARE permission to allow concurrent access to the disk.
|
||||||
// use 0 as access mode to avoid admin permission.
|
// use 0 as access mode to avoid admin permission.
|
||||||
mode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE)
|
mode := uint32(windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE | windows.FILE_SHARE_DELETE)
|
||||||
|
|
||||||
f, err = windows.CreateFile(
|
f, err = windows.CreateFile(
|
||||||
windows.StringToUTF16Ptr(`\\.\`+rootDrive),
|
windows.StringToUTF16Ptr(`\\.\`+rootDrive),
|
||||||
0, mode, nil, windows.OPEN_EXISTING, uint32(windows.FILE_ATTRIBUTE_READONLY), 0)
|
0, mode, nil, windows.OPEN_EXISTING, uint32(windows.FILE_ATTRIBUTE_READONLY), 0)
|
||||||
@@ -498,6 +508,7 @@ func getDiskIDByVolume(rootDrive string) (string, error) {
|
|||||||
volumeDiskExtents := make([]byte, 16*1024)
|
volumeDiskExtents := make([]byte, 16*1024)
|
||||||
|
|
||||||
var bytesReturned uint32
|
var bytesReturned uint32
|
||||||
|
|
||||||
err = windows.DeviceIoControl(f, controlCode, nil, 0, &volumeDiskExtents[0], uint32(len(volumeDiskExtents)), &bytesReturned, nil)
|
err = windows.DeviceIoControl(f, controlCode, nil, 0, &volumeDiskExtents[0], uint32(len(volumeDiskExtents)), &bytesReturned, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("could not identify physical drive for %s: %w", rootDrive, err)
|
return "", fmt.Errorf("could not identify physical drive for %s: %w", rootDrive, err)
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package logon
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -47,15 +46,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -67,17 +66,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"status"},
|
[]string{"status"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting user metrics", "err", err)
|
logger.Error("failed collecting user metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +96,7 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_LogonSession", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_LogonSession", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -232,5 +237,6 @@ func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
|||||||
float64(cachedunlock),
|
float64(cachedunlock),
|
||||||
"cached_unlock",
|
"cached_unlock",
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/ad"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/ad"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/adcs"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/adcs"
|
||||||
@@ -36,6 +39,7 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/netframework_clrsecurity"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/nps"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/os"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector/perfdata"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/physical_disk"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/printer"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/process"
|
||||||
@@ -54,7 +58,6 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/time"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/time"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/vmware"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/vmware"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/vmware_blast"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/vmware_blast"
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBuilderWithFlags[C Collector](fn BuilderWithFlags[C]) BuilderWithFlags[Collector] {
|
func NewBuilderWithFlags[C Collector](fn BuilderWithFlags[C]) BuilderWithFlags[Collector] {
|
||||||
@@ -98,6 +101,7 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
|
|||||||
netframework_clrsecurity.Name: NewBuilderWithFlags(netframework_clrsecurity.NewWithFlags),
|
netframework_clrsecurity.Name: NewBuilderWithFlags(netframework_clrsecurity.NewWithFlags),
|
||||||
nps.Name: NewBuilderWithFlags(nps.NewWithFlags),
|
nps.Name: NewBuilderWithFlags(nps.NewWithFlags),
|
||||||
os.Name: NewBuilderWithFlags(os.NewWithFlags),
|
os.Name: NewBuilderWithFlags(os.NewWithFlags),
|
||||||
|
perfdata.Name: NewBuilderWithFlags(perfdata.NewWithFlags),
|
||||||
physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags),
|
physical_disk.Name: NewBuilderWithFlags(physical_disk.NewWithFlags),
|
||||||
printer.Name: NewBuilderWithFlags(printer.NewWithFlags),
|
printer.Name: NewBuilderWithFlags(printer.NewWithFlags),
|
||||||
process.Name: NewBuilderWithFlags(process.NewWithFlags),
|
process.Name: NewBuilderWithFlags(process.NewWithFlags),
|
||||||
@@ -119,5 +123,5 @@ var BuildersWithFlags = map[string]BuilderWithFlags[Collector]{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Available() []string {
|
func Available() []string {
|
||||||
return maps.Keys(BuildersWithFlags)
|
return slices.Sorted(maps.Keys(BuildersWithFlags))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,12 @@
|
|||||||
package memory
|
package memory
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/sysinfoapi"
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -25,6 +28,7 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
// Performance metrics
|
||||||
availableBytes *prometheus.Desc
|
availableBytes *prometheus.Desc
|
||||||
cacheBytes *prometheus.Desc
|
cacheBytes *prometheus.Desc
|
||||||
cacheBytesPeak *prometheus.Desc
|
cacheBytesPeak *prometheus.Desc
|
||||||
@@ -57,6 +61,11 @@ type Collector struct {
|
|||||||
transitionFaultsTotal *prometheus.Desc
|
transitionFaultsTotal *prometheus.Desc
|
||||||
transitionPagesRepurposedTotal *prometheus.Desc
|
transitionPagesRepurposedTotal *prometheus.Desc
|
||||||
writeCopiesTotal *prometheus.Desc
|
writeCopiesTotal *prometheus.Desc
|
||||||
|
|
||||||
|
// Global memory status
|
||||||
|
processMemoryLimitBytes *prometheus.Desc
|
||||||
|
physicalMemoryTotalBytes *prometheus.Desc
|
||||||
|
physicalMemoryFreeBytes *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *Config) *Collector {
|
func New(config *Config) *Collector {
|
||||||
@@ -79,15 +88,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Memory"}, nil
|
return []string{"Memory"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.availableBytes = prometheus.NewDesc(
|
c.availableBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "available_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "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 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"+
|
||||||
@@ -292,17 +301,78 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
c.processMemoryLimitBytes = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "process_memory_limit_bytes"),
|
||||||
|
"The size of the user-mode portion of the virtual address space of the calling process, in bytes. This value depends on the type of process, the type of processor, and the configuration of the operating system.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
c.physicalMemoryTotalBytes = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "physical_total_bytes"),
|
||||||
|
"The amount of actual physical memory, in bytes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
c.physicalMemoryFreeBytes = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "physical_free_bytes"),
|
||||||
|
"The amount of physical memory currently available, in bytes. This is the amount of physical memory that can be immediately reused without having to write its contents to disk first. It is the sum of the size of the standby, free, and zero lists.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting memory metrics", "err", err)
|
errs := make([]error, 0, 2)
|
||||||
return err
|
|
||||||
|
if err := c.collectPerformanceData(ctx, logger, ch); err != nil {
|
||||||
|
logger.Error("failed collecting memory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := c.collectGlobalMemoryStatus(ch); err != nil {
|
||||||
|
logger.Error("failed collecting memory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectGlobalMemoryStatus(ch chan<- prometheus.Metric) error {
|
||||||
|
memoryStatusEx, err := sysinfoapi.GlobalMemoryStatusEx()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get memory status: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.processMemoryLimitBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.TotalVirtual),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.physicalMemoryTotalBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.TotalPhys),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.physicalMemoryFreeBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.AvailPhys),
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,9 +413,11 @@ type memory struct {
|
|||||||
WriteCopiesPersec float64 `perflib:"Write Copies/sec"`
|
WriteCopiesPersec float64 `perflib:"Write Copies/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectPerformanceData(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []memory
|
var dst []memory
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Memory"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Memory"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package mscluster
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -213,15 +213,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Memory"}, nil
|
return []string{"Memory"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if len(c.config.CollectorsEnabled) == 0 {
|
if len(c.config.CollectorsEnabled) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, _ log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, _ *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
if len(c.config.CollectorsEnabled) == 0 {
|
if len(c.config.CollectorsEnabled) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ package msmq
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -68,16 +67,16 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
@@ -86,7 +85,7 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
c.wmiClient = wmiClient
|
c.wmiClient = wmiClient
|
||||||
|
|
||||||
if *c.config.QueryWhereClause == "" {
|
if *c.config.QueryWhereClause == "" {
|
||||||
_ = level.Warn(logger).Log("msg", "No where-clause specified for msmq collector. This will generate a very large number of metrics!")
|
logger.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.bytesInJournalQueue = prometheus.NewDesc(
|
c.bytesInJournalQueue = prometheus.NewDesc(
|
||||||
@@ -113,17 +112,22 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"name"},
|
[]string{"name"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting msmq metrics", "err", err)
|
logger.Error("failed collecting msmq metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package mssql
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -12,8 +13,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -46,7 +45,7 @@ var ConfigDefaults = Config{
|
|||||||
|
|
||||||
type mssqlInstancesType map[string]string
|
type mssqlInstancesType map[string]string
|
||||||
|
|
||||||
func getMSSQLInstances(logger log.Logger) mssqlInstancesType {
|
func getMSSQLInstances(logger *slog.Logger) mssqlInstancesType {
|
||||||
sqlInstances := make(mssqlInstancesType)
|
sqlInstances := make(mssqlInstancesType)
|
||||||
|
|
||||||
// in case querying the registry fails, return the default instance
|
// in case querying the registry fails, return the default instance
|
||||||
@@ -54,21 +53,31 @@ func getMSSQLInstances(logger log.Logger) mssqlInstancesType {
|
|||||||
sqlDefaultInstance["MSSQLSERVER"] = ""
|
sqlDefaultInstance["MSSQLSERVER"] = ""
|
||||||
|
|
||||||
regKey := `Software\Microsoft\Microsoft SQL Server\Instance Names\SQL`
|
regKey := `Software\Microsoft\Microsoft SQL Server\Instance Names\SQL`
|
||||||
|
|
||||||
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regKey, registry.QUERY_VALUE)
|
k, err := registry.OpenKey(registry.LOCAL_MACHINE, regKey, registry.QUERY_VALUE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Couldn't open registry to determine SQL instances", "err", err)
|
logger.Warn("Couldn't open registry to determine SQL instances",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return sqlDefaultInstance
|
return sqlDefaultInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
err = k.Close()
|
err = k.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to close registry key", "err", err)
|
logger.Warn("Failed to close registry key",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
instanceNames, err := k.ReadValueNames(0)
|
instanceNames, err := k.ReadValueNames(0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Can't ReadSubKeyNames", "err", err)
|
logger.Warn("Can't ReadSubKeyNames",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return sqlDefaultInstance
|
return sqlDefaultInstance
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +87,7 @@ func getMSSQLInstances(logger log.Logger) mssqlInstancesType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("Detected MSSQL Instances: %#v\n", sqlInstances))
|
logger.Debug(fmt.Sprintf("Detected MSSQL Instances: %#v\n", sqlInstances))
|
||||||
|
|
||||||
return sqlInstances
|
return sqlInstances
|
||||||
}
|
}
|
||||||
@@ -110,7 +119,9 @@ func mssqlGetPerfObjectName(sqlInstance string, collector string) string {
|
|||||||
if sqlInstance != "MSSQLSERVER" {
|
if sqlInstance != "MSSQLSERVER" {
|
||||||
prefix = "MSSQL$" + sqlInstance + ":"
|
prefix = "MSSQL$" + sqlInstance + ":"
|
||||||
}
|
}
|
||||||
|
|
||||||
suffix := ""
|
suffix := ""
|
||||||
|
|
||||||
switch collector {
|
switch collector {
|
||||||
case "accessmethods":
|
case "accessmethods":
|
||||||
suffix = "Access Methods"
|
suffix = "Access Methods"
|
||||||
@@ -137,6 +148,7 @@ func mssqlGetPerfObjectName(sqlInstance string, collector string) string {
|
|||||||
case "waitstats":
|
case "waitstats":
|
||||||
suffix = "Wait Statistics"
|
suffix = "Wait Statistics"
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix + suffix
|
return prefix + suffix
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,6 +448,7 @@ func NewWithFlags(app *kingpin.Application) *Collector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var listAllCollectors bool
|
var listAllCollectors bool
|
||||||
|
|
||||||
var collectorsEnabled string
|
var collectorsEnabled string
|
||||||
|
|
||||||
app.Flag(
|
app.Flag(
|
||||||
@@ -478,7 +491,7 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(logger log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(logger *slog.Logger) ([]string, error) {
|
||||||
c.mssqlInstances = getMSSQLInstances(logger)
|
c.mssqlInstances = getMSSQLInstances(logger)
|
||||||
perfCounters := make([]string, 0, len(c.mssqlInstances)*len(c.config.CollectorsEnabled))
|
perfCounters := make([]string, 0, len(c.mssqlInstances)*len(c.config.CollectorsEnabled))
|
||||||
|
|
||||||
@@ -491,11 +504,11 @@ func (c *Collector) GetPerfCounter(logger log.Logger) ([]string, error) {
|
|||||||
return perfCounters, nil
|
return perfCounters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
// Result must order, to prevent test failures.
|
// Result must order, to prevent test failures.
|
||||||
sort.Strings(c.config.CollectorsEnabled)
|
sort.Strings(c.config.CollectorsEnabled)
|
||||||
|
|
||||||
@@ -1971,24 +1984,30 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type mssqlCollectorFunc func(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error
|
type mssqlCollectorFunc func(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error
|
||||||
|
|
||||||
func (c *Collector) execute(ctx *types.ScrapeContext, logger log.Logger, name string, fn mssqlCollectorFunc, ch chan<- prometheus.Metric, sqlInstance string, wg *sync.WaitGroup) {
|
func (c *Collector) execute(ctx *types.ScrapeContext, logger *slog.Logger, name string, fn mssqlCollectorFunc, ch chan<- prometheus.Metric, sqlInstance string, wg *sync.WaitGroup) {
|
||||||
// Reset failure counter on each scrape
|
// Reset failure counter on each scrape
|
||||||
c.mssqlChildCollectorFailure = 0
|
c.mssqlChildCollectorFailure = 0
|
||||||
|
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
|
||||||
begin := time.Now()
|
begin := time.Now()
|
||||||
err := fn(ctx, logger, ch, sqlInstance)
|
err := fn(ctx, logger, ch, sqlInstance)
|
||||||
duration := time.Since(begin)
|
duration := time.Since(begin)
|
||||||
|
|
||||||
var success float64
|
var success float64
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("mssql class collector %s failed after %fs", name, duration.Seconds()), "err", err)
|
logger.Error(fmt.Sprintf("mssql class collector %s failed after %fs", name, duration.Seconds()),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
success = 0
|
success = 0
|
||||||
c.mssqlChildCollectorFailure++
|
c.mssqlChildCollectorFailure++
|
||||||
} else {
|
} else {
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql class collector %s succeeded after %fs.", name, duration.Seconds()))
|
logger.Debug(fmt.Sprintf("mssql class collector %s succeeded after %fs.", name, duration.Seconds()))
|
||||||
|
|
||||||
success = 1
|
success = 1
|
||||||
}
|
}
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -2007,8 +2026,8 @@ func (c *Collector) execute(ctx *types.ScrapeContext, logger log.Logger, name st
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
|
|
||||||
for sqlInstance := range c.mssqlInstances {
|
for sqlInstance := range c.mssqlInstances {
|
||||||
@@ -2016,6 +2035,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
function := c.mssqlCollectors[name]
|
function := c.mssqlCollectors[name]
|
||||||
|
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
|
|
||||||
go c.execute(ctx, logger, name, function, ch, sqlInstance, &wg)
|
go c.execute(ctx, logger, name, function, ch, sqlInstance, &wg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2079,9 +2099,10 @@ type mssqlAccessMethods struct {
|
|||||||
WorktablesFromCacheRatioBase float64 `perflib:"Worktables From Cache Base_Base"`
|
WorktablesFromCacheRatioBase float64 `perflib:"Worktables From Cache Base_Base"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAccessMethods(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectAccessMethods(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlAccessMethods
|
var dst []mssqlAccessMethods
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_accessmethods collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_accessmethods collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "accessmethods")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "accessmethods")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2396,6 +2417,7 @@ func (c *Collector) collectAccessMethods(ctx *types.ScrapeContext, logger log.Lo
|
|||||||
sqlInstance,
|
sqlInstance,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2414,9 +2436,10 @@ type mssqlAvailabilityReplica struct {
|
|||||||
SendstoTransportPerSec float64 `perflib:"Sends to Transport/sec"`
|
SendstoTransportPerSec float64 `perflib:"Sends to Transport/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAvailabilityReplica(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectAvailabilityReplica(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlAvailabilityReplica
|
var dst []mssqlAvailabilityReplica
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_availreplica collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_availreplica collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "availreplica")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "availreplica")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2426,6 +2449,7 @@ func (c *Collector) collectAvailabilityReplica(ctx *types.ScrapeContext, logger
|
|||||||
if strings.ToLower(v.Name) == "_total" {
|
if strings.ToLower(v.Name) == "_total" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
replicaName := v.Name
|
replicaName := v.Name
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -2491,6 +2515,7 @@ func (c *Collector) collectAvailabilityReplica(ctx *types.ScrapeContext, logger
|
|||||||
sqlInstance, replicaName,
|
sqlInstance, replicaName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2522,9 +2547,10 @@ type mssqlBufferManager struct {
|
|||||||
TargetPages float64 `perflib:"Target pages"`
|
TargetPages float64 `perflib:"Target pages"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectBufferManager(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectBufferManager(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlBufferManager
|
var dst []mssqlBufferManager
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_bufman collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_bufman collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "bufman")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "bufman")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2726,9 +2752,10 @@ type mssqlDatabaseReplica struct {
|
|||||||
TransactionDelay float64 `perflib:"Transaction Delay"`
|
TransactionDelay float64 `perflib:"Transaction Delay"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectDatabaseReplica(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectDatabaseReplica(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlDatabaseReplica
|
var dst []mssqlDatabaseReplica
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_dbreplica collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_dbreplica collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "dbreplica")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "dbreplica")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2738,6 +2765,7 @@ func (c *Collector) collectDatabaseReplica(ctx *types.ScrapeContext, logger log.
|
|||||||
if strings.ToLower(v.Name) == "_total" {
|
if strings.ToLower(v.Name) == "_total" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
replicaName := v.Name
|
replicaName := v.Name
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -2908,6 +2936,7 @@ func (c *Collector) collectDatabaseReplica(ctx *types.ScrapeContext, logger log.
|
|||||||
sqlInstance, replicaName,
|
sqlInstance, replicaName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2965,9 +2994,10 @@ type mssqlDatabases struct {
|
|||||||
XTPMemoryUsedKB float64 `perflib:"XTP Memory Used (KB)"`
|
XTPMemoryUsedKB float64 `perflib:"XTP Memory Used (KB)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectDatabases(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectDatabases(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlDatabases
|
var dst []mssqlDatabases
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_databases collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_databases collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "databases")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "databases")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -2977,6 +3007,7 @@ func (c *Collector) collectDatabases(ctx *types.ScrapeContext, logger log.Logger
|
|||||||
if strings.ToLower(v.Name) == "_total" {
|
if strings.ToLower(v.Name) == "_total" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
dbName := v.Name
|
dbName := v.Name
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -3315,6 +3346,7 @@ func (c *Collector) collectDatabases(ctx *types.ScrapeContext, logger log.Logger
|
|||||||
sqlInstance, dbName,
|
sqlInstance, dbName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3347,9 +3379,10 @@ type mssqlGeneralStatistics struct {
|
|||||||
UserConnections float64 `perflib:"User Connections"`
|
UserConnections float64 `perflib:"User Connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectGeneralStatistics(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectGeneralStatistics(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlGeneralStatistics
|
var dst []mssqlGeneralStatistics
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_genstats collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_genstats collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "genstats")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "genstats")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -3542,9 +3575,10 @@ type mssqlLocks struct {
|
|||||||
NumberOfDeadlocksPerSec float64 `perflib:"Number of Deadlocks/sec"`
|
NumberOfDeadlocksPerSec float64 `perflib:"Number of Deadlocks/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectLocks(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectLocks(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlLocks
|
var dst []mssqlLocks
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_locks collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_locks collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "locks")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "locks")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -3554,6 +3588,7 @@ func (c *Collector) collectLocks(ctx *types.ScrapeContext, logger log.Logger, ch
|
|||||||
if strings.ToLower(v.Name) == "_total" {
|
if strings.ToLower(v.Name) == "_total" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
lockResourceName := v.Name
|
lockResourceName := v.Name
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -3612,6 +3647,7 @@ func (c *Collector) collectLocks(ctx *types.ScrapeContext, logger log.Logger, ch
|
|||||||
sqlInstance, lockResourceName,
|
sqlInstance, lockResourceName,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3640,9 +3676,10 @@ type mssqlMemoryManager struct {
|
|||||||
TotalServerMemoryKB float64 `perflib:"Total Server Memory (KB)"`
|
TotalServerMemoryKB float64 `perflib:"Total Server Memory (KB)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectMemoryManager(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectMemoryManager(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlMemoryManager
|
var dst []mssqlMemoryManager
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_memmgr collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_memmgr collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "memmgr")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "memmgr")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -3809,9 +3846,10 @@ type mssqlSQLStatistics struct {
|
|||||||
UnsafeAutoParamsPerSec float64 `perflib:"Unsafe Auto-Params/sec"`
|
UnsafeAutoParamsPerSec float64 `perflib:"Unsafe Auto-Params/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectSQLStats(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectSQLStats(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlSQLStatistics
|
var dst []mssqlSQLStatistics
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_sqlstats collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_sqlstats collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "sqlstats")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "sqlstats")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -3917,9 +3955,10 @@ type mssqlWaitStatistics struct {
|
|||||||
WaitStatsTransactionOwnershipWaits float64 `perflib:"Transaction ownership waits"`
|
WaitStatsTransactionOwnershipWaits float64 `perflib:"Transaction ownership waits"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectWaitStats(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectWaitStats(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlWaitStatistics
|
var dst []mssqlWaitStatistics
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_waitstats collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_waitstats collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "waitstats")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "waitstats")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -4023,9 +4062,10 @@ type mssqlSQLErrors struct {
|
|||||||
|
|
||||||
// Win32_PerfRawData_MSSQLSERVER_SQLServerErrors docs:
|
// Win32_PerfRawData_MSSQLSERVER_SQLServerErrors docs:
|
||||||
// - https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-errors-object
|
// - https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-sql-errors-object
|
||||||
func (c *Collector) collectSQLErrors(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectSQLErrors(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlSQLErrors
|
var dst []mssqlSQLErrors
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_sqlerrors collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_sqlerrors collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "sqlerrors")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "sqlerrors")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -4035,6 +4075,7 @@ func (c *Collector) collectSQLErrors(ctx *types.ScrapeContext, logger log.Logger
|
|||||||
if strings.ToLower(v.Name) == "_total" {
|
if strings.ToLower(v.Name) == "_total" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
resource := v.Name
|
resource := v.Name
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -4066,9 +4107,10 @@ type mssqlTransactions struct {
|
|||||||
|
|
||||||
// Win32_PerfRawData_MSSQLSERVER_Transactions docs:
|
// Win32_PerfRawData_MSSQLSERVER_Transactions docs:
|
||||||
// - https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-transactions-object
|
// - https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-transactions-object
|
||||||
func (c *Collector) collectTransactions(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
func (c *Collector) collectTransactions(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric, sqlInstance string) error {
|
||||||
var dst []mssqlTransactions
|
var dst []mssqlTransactions
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("mssql_transactions collector iterating sql instance %s.", sqlInstance))
|
|
||||||
|
logger.Debug(fmt.Sprintf("mssql_transactions collector iterating sql instance %s.", sqlInstance))
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "transactions")], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects[mssqlGetPerfObjectName(sqlInstance, "transactions")], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ package net
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -108,15 +107,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Network Interface"}, nil
|
return []string{"Network Interface"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.bytesReceivedTotal = prometheus.NewDesc(
|
c.bytesReceivedTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "bytes_received_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "bytes_received_total"),
|
||||||
"(Network.BytesReceivedPerSec)",
|
"(Network.BytesReceivedPerSec)",
|
||||||
@@ -201,12 +200,16 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting net metrics", "err", err)
|
logger.Error("failed collecting net metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,8 +238,9 @@ type networkInterface struct {
|
|||||||
CurrentBandwidth float64 `perflib:"Current Bandwidth"`
|
CurrentBandwidth float64 `perflib:"Current Bandwidth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []networkInterface
|
var dst []networkInterface
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Network Interface"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Network Interface"], &dst, logger); err != nil {
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrexceptions
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -50,15 +49,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -88,17 +87,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrexceptions metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrexceptions metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrinterop
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -49,15 +48,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -81,17 +80,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrinterop metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrinterop metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
package netframework_clrjit
|
package netframework_clrjit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -48,15 +48,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.numberOfMethodsJitted = prometheus.NewDesc(
|
c.numberOfMethodsJitted = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "jit_methods_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "jit_methods_total"),
|
||||||
"Displays the total number of methods JIT-compiled since the application started. This counter does not include pre-JIT-compiled methods.",
|
"Displays the total number of methods JIT-compiled since the application started. This counter does not include pre-JIT-compiled methods.",
|
||||||
@@ -81,17 +81,22 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrjit metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrjit metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrloading
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -55,15 +54,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -124,17 +123,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrloading metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrloading metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrlocksandthreads
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -53,15 +52,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -110,17 +109,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrlocksandthreads metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrlocksandthreads metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrmemory
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -58,15 +57,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -145,17 +144,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrmemory metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrmemory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrremoting
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -52,15 +51,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -103,17 +102,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrremoting metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrremoting metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package netframework_clrsecurity
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -50,15 +49,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -88,17 +87,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
[]string{"process"},
|
[]string{"process"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting win32_perfrawdata_netframework_netclrsecurity metrics", "err", err)
|
logger.Error("failed collecting win32_perfrawdata_netframework_netclrsecurity metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,9 @@ package nps
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -71,15 +70,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -236,21 +235,26 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.CollectAccept(ch); err != nil {
|
if err := c.CollectAccept(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("failed collecting NPS accept data: %s", err))
|
logger.Error(fmt.Sprintf("failed collecting NPS accept data: %s", err))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.CollectAccounting(ch); err != nil {
|
if err := c.CollectAccounting(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("failed collecting NPS accounting data: %s", err))
|
logger.Error(fmt.Sprintf("failed collecting NPS accounting data: %s", err))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,13 @@ package os
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/kernel32"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/kernel32"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/netapi32"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/netapi32"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/psapi"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/psapi"
|
||||||
@@ -22,6 +20,7 @@ import (
|
|||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
"golang.org/x/sys/windows/registry"
|
"golang.org/x/sys/windows/registry"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,19 +34,45 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
osInformation *prometheus.Desc
|
hostname *prometheus.Desc
|
||||||
pagingFreeBytes *prometheus.Desc
|
osInformation *prometheus.Desc
|
||||||
pagingLimitBytes *prometheus.Desc
|
pagingFreeBytes *prometheus.Desc
|
||||||
|
pagingLimitBytes *prometheus.Desc
|
||||||
|
|
||||||
|
// users
|
||||||
|
// Deprecated: Use windows_system_processes instead.
|
||||||
|
processes *prometheus.Desc
|
||||||
|
// users
|
||||||
|
// Deprecated: Use windows_system_process_limit instead.
|
||||||
|
processesLimit *prometheus.Desc
|
||||||
|
|
||||||
|
// users
|
||||||
|
// Deprecated: Use count(windows_logon_logon_type) instead.
|
||||||
|
users *prometheus.Desc
|
||||||
|
|
||||||
|
// physicalMemoryFreeBytes
|
||||||
|
// Deprecated: Use windows_memory_physical_free_bytes instead.
|
||||||
physicalMemoryFreeBytes *prometheus.Desc
|
physicalMemoryFreeBytes *prometheus.Desc
|
||||||
|
|
||||||
|
// processMemoryLimitBytes
|
||||||
|
// Deprecated: Use windows_memory_process_memory_limit_bytes instead.
|
||||||
processMemoryLimitBytes *prometheus.Desc
|
processMemoryLimitBytes *prometheus.Desc
|
||||||
processes *prometheus.Desc
|
|
||||||
processesLimit *prometheus.Desc
|
// time
|
||||||
time *prometheus.Desc
|
// Deprecated: Use windows_time_current_timestamp_seconds instead.
|
||||||
timezone *prometheus.Desc
|
time *prometheus.Desc
|
||||||
users *prometheus.Desc
|
// timezone
|
||||||
virtualMemoryBytes *prometheus.Desc
|
// Deprecated: Use windows_time_timezone instead.
|
||||||
virtualMemoryFreeBytes *prometheus.Desc
|
timezone *prometheus.Desc
|
||||||
visibleMemoryBytes *prometheus.Desc
|
// virtualMemoryBytes
|
||||||
|
// Deprecated: Use windows_memory_commit_limit instead.
|
||||||
|
virtualMemoryBytes *prometheus.Desc
|
||||||
|
// virtualMemoryFreeBytes
|
||||||
|
// Deprecated: Use windows_memory_commit_limit instead.
|
||||||
|
virtualMemoryFreeBytes *prometheus.Desc
|
||||||
|
// visibleMemoryBytes
|
||||||
|
// Deprecated: Use windows_memory_physical_total_bytes instead.
|
||||||
|
visibleMemoryBytes *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
type pagingFileCounter struct {
|
type pagingFileCounter struct {
|
||||||
@@ -76,19 +101,50 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Paging File"}, nil
|
return []string{"Paging File"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
|
logger.Warn("The os collect holds a number of deprecated metrics and will be removed mid 2025. " +
|
||||||
|
"See https://github.com/prometheus-community/windows_exporter/pull/1596 for more information.")
|
||||||
|
|
||||||
|
workstationInfo, err := netapi32.GetWorkstationInfo()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get workstation info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
productName, buildNumber, revision, err := c.getWindowsVersion()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get Windows version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
c.osInformation = prometheus.NewDesc(
|
c.osInformation = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
||||||
"OperatingSystem.Caption, OperatingSystem.Version",
|
`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.`,
|
||||||
[]string{"product", "version", "major_version", "minor_version", "build_number", "revision"},
|
nil,
|
||||||
|
prometheus.Labels{
|
||||||
|
"product": productName,
|
||||||
|
"version": fmt.Sprintf("%d.%d.%s", workstationInfo.VersionMajor, workstationInfo.VersionMinor, buildNumber),
|
||||||
|
"major_version": strconv.FormatUint(uint64(workstationInfo.VersionMajor), 10),
|
||||||
|
"minor_version": strconv.FormatUint(uint64(workstationInfo.VersionMinor), 10),
|
||||||
|
"build_number": buildNumber,
|
||||||
|
"revision": revision,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
c.hostname = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "hostname"),
|
||||||
|
"Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain",
|
||||||
|
[]string{
|
||||||
|
"hostname",
|
||||||
|
"domain",
|
||||||
|
"fqdn",
|
||||||
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.pagingLimitBytes = prometheus.NewDesc(
|
c.pagingLimitBytes = prometheus.NewDesc(
|
||||||
@@ -105,118 +161,228 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
)
|
)
|
||||||
c.physicalMemoryFreeBytes = prometheus.NewDesc(
|
c.physicalMemoryFreeBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "physical_memory_free_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "physical_memory_free_bytes"),
|
||||||
"OperatingSystem.FreePhysicalMemory",
|
"Deprecated: Use `windows_memory_physical_free_bytes` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.time = prometheus.NewDesc(
|
c.time = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "time"),
|
prometheus.BuildFQName(types.Namespace, Name, "time"),
|
||||||
"OperatingSystem.LocalDateTime",
|
"Deprecated: Use windows_time_current_timestamp_seconds instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.timezone = prometheus.NewDesc(
|
c.timezone = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "timezone"),
|
prometheus.BuildFQName(types.Namespace, Name, "timezone"),
|
||||||
"OperatingSystem.LocalDateTime",
|
"Deprecated: Use windows_time_timezone instead.",
|
||||||
[]string{"timezone"},
|
[]string{"timezone"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.processes = prometheus.NewDesc(
|
c.processes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "processes"),
|
prometheus.BuildFQName(types.Namespace, Name, "processes"),
|
||||||
"OperatingSystem.NumberOfProcesses",
|
"Deprecated: Use `windows_system_processes` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.processesLimit = prometheus.NewDesc(
|
c.processesLimit = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "processes_limit"),
|
prometheus.BuildFQName(types.Namespace, Name, "processes_limit"),
|
||||||
"OperatingSystem.MaxNumberOfProcesses",
|
"Deprecated: Use `windows_system_process_limit` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.processMemoryLimitBytes = prometheus.NewDesc(
|
c.processMemoryLimitBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "process_memory_limit_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "process_memory_limit_bytes"),
|
||||||
"OperatingSystem.MaxProcessMemorySize",
|
"Deprecated: Use `windows_memory_process_memory_limit_bytes` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.users = prometheus.NewDesc(
|
c.users = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "users"),
|
prometheus.BuildFQName(types.Namespace, Name, "users"),
|
||||||
"OperatingSystem.NumberOfUsers",
|
"Deprecated: Use `count(windows_logon_logon_type)` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.virtualMemoryBytes = prometheus.NewDesc(
|
c.virtualMemoryBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "virtual_memory_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "virtual_memory_bytes"),
|
||||||
"OperatingSystem.TotalVirtualMemorySize",
|
"Deprecated: Use `windows_memory_commit_limit` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.visibleMemoryBytes = prometheus.NewDesc(
|
c.visibleMemoryBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "visible_memory_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "visible_memory_bytes"),
|
||||||
"OperatingSystem.TotalVisibleMemorySize",
|
"Deprecated: Use `windows_memory_physical_total_bytes` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.virtualMemoryFreeBytes = prometheus.NewDesc(
|
c.virtualMemoryFreeBytes = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "virtual_memory_free_bytes"),
|
prometheus.BuildFQName(types.Namespace, Name, "virtual_memory_free_bytes"),
|
||||||
"OperatingSystem.FreeVirtualMemory",
|
"Deprecated: Use `windows_memory_commit_limit - windows_memory_committed_bytes` instead.",
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting os metrics", "err", err)
|
errs := make([]error, 0, 5)
|
||||||
|
|
||||||
|
c.collect(ch)
|
||||||
|
|
||||||
|
if err := c.collectHostname(ch); err != nil {
|
||||||
|
logger.Error("failed collecting os metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.collectLoggedInUserCount(ch); err != nil {
|
||||||
|
logger.Error("failed collecting os user count metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.collectMemory(ch); err != nil {
|
||||||
|
logger.Error("failed collecting os memory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.collectTime(ch); err != nil {
|
||||||
|
logger.Error("failed collecting os time metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.collectPaging(ctx, logger, ch); err != nil {
|
||||||
|
logger.Error("failed collecting os paging metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectLoggedInUserCount(ch chan<- prometheus.Metric) error {
|
||||||
|
workstationInfo, err := netapi32.GetWorkstationInfo()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.users,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(workstationInfo.LoggedOnUsers),
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win32_OperatingSystem docs:
|
func (c *Collector) collectHostname(ch chan<- prometheus.Metric) error {
|
||||||
// - https://msdn.microsoft.com/en-us/library/aa394239 - Win32_OperatingSystem class.
|
hostname, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSHostname)
|
||||||
type Win32_OperatingSystem struct {
|
if err != nil {
|
||||||
Caption string
|
return err
|
||||||
FreePhysicalMemory uint64
|
}
|
||||||
FreeSpaceInPagingFiles uint64
|
|
||||||
FreeVirtualMemory uint64
|
domain, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSDomain)
|
||||||
LocalDateTime time.Time
|
if err != nil {
|
||||||
MaxNumberOfProcesses uint32
|
return err
|
||||||
MaxProcessMemorySize uint64
|
}
|
||||||
NumberOfProcesses uint32
|
|
||||||
NumberOfUsers uint32
|
fqdn, err := sysinfoapi.GetComputerName(sysinfoapi.ComputerNameDNSFullyQualified)
|
||||||
SizeStoredInPagingFiles uint64
|
if err != nil {
|
||||||
TotalVirtualMemorySize uint64
|
return err
|
||||||
TotalVisibleMemorySize uint64
|
}
|
||||||
Version string
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.hostname,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
hostname,
|
||||||
|
domain,
|
||||||
|
fqdn,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
|
||||||
nwgi, err := netapi32.GetWorkstationInfo()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gmse, err := sysinfoapi.GlobalMemoryStatusEx()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTime := time.Now()
|
|
||||||
|
|
||||||
timeZoneInfo, err := kernel32.GetDynamicTimeZoneInformation()
|
timeZoneInfo, err := kernel32.GetDynamicTimeZoneInformation()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeZoneKeyName contains the english name of the timezone.
|
// timeZoneKeyName contains the english name of the timezone.
|
||||||
timezoneName := syscall.UTF16ToString(timeZoneInfo.TimeZoneKeyName[:])
|
timezoneName := windows.UTF16ToString(timeZoneInfo.TimeZoneKeyName[:])
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.time,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(time.Now().Unix()),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.timezone,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
timezoneName,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectMemory(ch chan<- prometheus.Metric) error {
|
||||||
|
memoryStatusEx, err := sysinfoapi.GlobalMemoryStatusEx()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.physicalMemoryFreeBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.AvailPhys),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.virtualMemoryFreeBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.AvailPageFile),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.virtualMemoryBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.TotalPageFile),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.visibleMemoryBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.TotalPhys),
|
||||||
|
)
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.processMemoryLimitBytes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(memoryStatusEx.TotalVirtual),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectPaging(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
// Get total allocation of paging files across all disks.
|
// Get total allocation of paging files across all disks.
|
||||||
memManKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management`, registry.QUERY_VALUE)
|
memManKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management`, registry.QUERY_VALUE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -228,96 +394,43 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
pagingFiles, _, pagingErr := memManKey.GetStringsValue("ExistingPageFiles")
|
pagingFiles, _, pagingErr := memManKey.GetStringsValue("ExistingPageFiles")
|
||||||
|
|
||||||
var fsipf float64
|
var fsipf float64
|
||||||
|
|
||||||
for _, pagingFile := range pagingFiles {
|
for _, pagingFile := range pagingFiles {
|
||||||
fileString := strings.ReplaceAll(pagingFile, `\??\`, "")
|
fileString := strings.ReplaceAll(pagingFile, `\??\`, "")
|
||||||
file, err := os.Stat(fileString)
|
file, err := os.Stat(fileString)
|
||||||
// For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting.
|
// For unknown reasons, Windows doesn't always create a page file. Continue collection rather than aborting.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Debug(logger).Log("msg", fmt.Sprintf("Failed to read page file (reason: %s): %s\n", err, fileString))
|
logger.Debug(fmt.Sprintf("Failed to read page file (reason: %s): %s\n", err, fileString))
|
||||||
} else {
|
} else {
|
||||||
fsipf += float64(file.Size())
|
fsipf += float64(file.Size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get build number and product name from registry
|
|
||||||
ntKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer ntKey.Close()
|
|
||||||
|
|
||||||
pn, _, err := ntKey.GetStringValue("ProductName")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bn, _, err := ntKey.GetStringValue("CurrentBuildNumber")
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
revision, _, err := ntKey.GetIntegerValue("UBR")
|
|
||||||
if errors.Is(err, registry.ErrNotExist) {
|
|
||||||
revision = 0
|
|
||||||
} else if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
gpi, err := psapi.GetPerformanceInfo()
|
gpi, err := psapi.GetPerformanceInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pfc := make([]pagingFileCounter, 0)
|
pfc := make([]pagingFileCounter, 0)
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Paging File"], &pfc, logger); err != nil {
|
if err = perflib.UnmarshalObject(ctx.PerfObjects["Paging File"], &pfc, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current page file usage.
|
// Get current page file usage.
|
||||||
var pfbRaw float64
|
var pfbRaw float64
|
||||||
|
|
||||||
for _, pageFile := range pfc {
|
for _, pageFile := range pfc {
|
||||||
if strings.Contains(strings.ToLower(pageFile.Name), "_total") {
|
if strings.Contains(strings.ToLower(pageFile.Name), "_total") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
pfbRaw += pageFile.Usage
|
pfbRaw += pageFile.Usage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subtract from total page file allocation on disk.
|
|
||||||
pfb := fsipf - (pfbRaw * float64(gpi.PageSize))
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.osInformation,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
1.0,
|
|
||||||
"Microsoft "+pn, // Caption
|
|
||||||
fmt.Sprintf("%d.%d.%s", nwgi.VersionMajor, nwgi.VersionMinor, bn), // Version
|
|
||||||
strconv.FormatUint(uint64(nwgi.VersionMajor), 10), // Major Version
|
|
||||||
strconv.FormatUint(uint64(nwgi.VersionMinor), 10), // Minor Version
|
|
||||||
bn, // Build number
|
|
||||||
strconv.FormatUint(revision, 10), // Revision
|
|
||||||
)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.physicalMemoryFreeBytes,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(gmse.AvailPhys),
|
|
||||||
)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.time,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(currentTime.Unix()),
|
|
||||||
)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.timezone,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
1.0,
|
|
||||||
timezoneName,
|
|
||||||
)
|
|
||||||
|
|
||||||
if pagingErr == nil {
|
if pagingErr == nil {
|
||||||
|
// Subtract from total page file allocation on disk.
|
||||||
|
pfb := fsipf - (pfbRaw * float64(gpi.PageSize))
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.pagingFreeBytes,
|
c.pagingFreeBytes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
@@ -330,12 +443,23 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
fsipf,
|
fsipf,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
_ = level.Debug(logger).Log("msg", "Could not find HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management key. windows_os_paging_free_bytes and windows_os_paging_limit_bytes will be omitted.")
|
logger.Debug("Could not find HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management key. windows_os_paging_free_bytes and windows_os_paging_limit_bytes will be omitted.")
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.virtualMemoryFreeBytes,
|
c.processes,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(gmse.AvailPageFile),
|
float64(gpi.ProcessCount),
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collect(ch chan<- prometheus.Metric) {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.osInformation,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.
|
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.
|
||||||
@@ -346,36 +470,33 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
float64(4294967295),
|
float64(4294967295),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.processMemoryLimitBytes,
|
func (c *Collector) getWindowsVersion() (string, string, string, error) {
|
||||||
prometheus.GaugeValue,
|
// Get build number and product name from registry
|
||||||
float64(gmse.TotalVirtual),
|
ntKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
|
||||||
)
|
if err != nil {
|
||||||
|
return "", "", "", fmt.Errorf("failed to open registry key: %w", err)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
}
|
||||||
c.processes,
|
|
||||||
prometheus.GaugeValue,
|
defer ntKey.Close()
|
||||||
float64(gpi.ProcessCount),
|
|
||||||
)
|
productName, _, err := ntKey.GetStringValue("ProductName")
|
||||||
|
if err != nil {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
return "", "", "", err
|
||||||
c.users,
|
}
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(nwgi.LoggedOnUsers),
|
buildNumber, _, err := ntKey.GetStringValue("CurrentBuildNumber")
|
||||||
)
|
if err != nil {
|
||||||
|
return "", "", "", err
|
||||||
ch <- prometheus.MustNewConstMetric(
|
}
|
||||||
c.virtualMemoryBytes,
|
|
||||||
prometheus.GaugeValue,
|
revision, _, err := ntKey.GetIntegerValue("UBR")
|
||||||
float64(gmse.TotalPageFile),
|
if errors.Is(err, registry.ErrNotExist) {
|
||||||
)
|
revision = 0
|
||||||
|
} else if err != nil {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
return "", "", "", err
|
||||||
c.visibleMemoryBytes,
|
}
|
||||||
prometheus.GaugeValue,
|
|
||||||
float64(gmse.TotalPhys),
|
return productName, buildNumber, strconv.FormatUint(revision, 10), nil
|
||||||
)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
181
pkg/collector/perfdata/perfdata.go
Normal file
181
pkg/collector/perfdata/perfdata.go
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"maps"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/alecthomas/kingpin/v2"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/yusufpapurcu/wmi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
Name = "perfdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Objects []Object `yaml:"objects"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var ConfigDefaults = Config{
|
||||||
|
Objects: make([]Object, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Collector is a Prometheus collector for perfdata metrics.
|
||||||
|
type Collector struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config *Config) *Collector {
|
||||||
|
if config == nil {
|
||||||
|
config = &ConfigDefaults
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Objects == nil {
|
||||||
|
config.Objects = ConfigDefaults.Objects
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &Collector{
|
||||||
|
config: *config,
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithFlags(app *kingpin.Application) *Collector {
|
||||||
|
c := &Collector{
|
||||||
|
config: ConfigDefaults,
|
||||||
|
}
|
||||||
|
|
||||||
|
var objects string
|
||||||
|
|
||||||
|
app.Flag(
|
||||||
|
"collector.perfdata.objects",
|
||||||
|
"Objects of performance data to observe. See docs for more information on how to use this flag. By default, no objects are observed.",
|
||||||
|
).Default("").StringVar(&objects)
|
||||||
|
|
||||||
|
app.Action(func(*kingpin.ParseContext) error {
|
||||||
|
if objects == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(objects), &c.config.Objects); err != nil {
|
||||||
|
return fmt.Errorf("failed to parse objects: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
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 {
|
||||||
|
for _, object := range c.config.Objects {
|
||||||
|
object.collector.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
|
logger.Warn("The perfdata collector is in an experimental state! The configuration may change in future. Please report any issues.")
|
||||||
|
|
||||||
|
for i, object := range c.config.Objects {
|
||||||
|
collector, err := perfdata.NewCollector(object.Object, object.Instances, slices.Sorted(maps.Keys(object.Counters)))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create pdh collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if object.InstanceLabel == "" {
|
||||||
|
c.config.Objects[i].InstanceLabel = "instance"
|
||||||
|
}
|
||||||
|
|
||||||
|
c.config.Objects[i].collector = collector
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
if err := c.collect(ch); err != nil {
|
||||||
|
logger.Error("failed collecting performance data metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||||
|
for _, object := range c.config.Objects {
|
||||||
|
data, err := object.collector.Collect()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for instance, counters := range data {
|
||||||
|
for counter, value := range counters {
|
||||||
|
var labels prometheus.Labels
|
||||||
|
if instance != perfdata.EmptyInstance {
|
||||||
|
labels = prometheus.Labels{object.InstanceLabel: instance}
|
||||||
|
}
|
||||||
|
|
||||||
|
metricType := value.Type
|
||||||
|
|
||||||
|
if val, ok := object.Counters[counter]; ok {
|
||||||
|
switch val.Type {
|
||||||
|
case "counter":
|
||||||
|
metricType = prometheus.CounterValue
|
||||||
|
case "gauge":
|
||||||
|
metricType = prometheus.GaugeValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
prometheus.NewDesc(
|
||||||
|
sanitizeMetricName(fmt.Sprintf("%s_perfdata_%s_%s", types.Namespace, object.Object, counter)),
|
||||||
|
fmt.Sprintf("Performance data for \\%s\\%s", object.Object, counter),
|
||||||
|
nil,
|
||||||
|
labels,
|
||||||
|
),
|
||||||
|
metricType,
|
||||||
|
value.FirstValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sanitizeMetricName(name string) string {
|
||||||
|
replacer := strings.NewReplacer(
|
||||||
|
".", "",
|
||||||
|
"%", "",
|
||||||
|
"/", "_",
|
||||||
|
" ", "_",
|
||||||
|
"-", "_",
|
||||||
|
)
|
||||||
|
|
||||||
|
return strings.Trim(replacer.Replace(strings.ToLower(name)), "_")
|
||||||
|
}
|
||||||
87
pkg/collector/perfdata/perfdata_collector_test.go
Normal file
87
pkg/collector/perfdata/perfdata_collector_test.go
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"regexp"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector/perfdata"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
type collectorAdapter struct {
|
||||||
|
perfdata.Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe implements the prometheus.Collector interface.
|
||||||
|
func (a collectorAdapter) Describe(_ chan<- *prometheus.Desc) {}
|
||||||
|
|
||||||
|
// Collect implements the prometheus.Collector interface.
|
||||||
|
func (a collectorAdapter) Collect(ch chan<- prometheus.Metric) {
|
||||||
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||||
|
|
||||||
|
if err := a.Collector.Collect(nil, logger, ch); err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to update collector: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCollector(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
object string
|
||||||
|
instances []string
|
||||||
|
counters map[string]perfdata.Counter
|
||||||
|
expectedMetrics *regexp.Regexp
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
object: "Memory",
|
||||||
|
instances: nil,
|
||||||
|
counters: map[string]perfdata.Counter{"Available Bytes": {Type: "gauge"}},
|
||||||
|
expectedMetrics: regexp.MustCompile(`^# HELP windows_perfdata_memory_available_bytes Performance data for \\\\Memory\\\\Available Bytes\s*# TYPE windows_perfdata_memory_available_bytes gauge\s*windows_perfdata_memory_available_bytes \d`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
object: "Process",
|
||||||
|
instances: []string{"*"},
|
||||||
|
counters: map[string]perfdata.Counter{"Thread Count": {Type: "counter"}},
|
||||||
|
expectedMetrics: regexp.MustCompile(`^# HELP windows_perfdata_process_thread_count Performance data for \\\\Process\\\\Thread Count\s*# TYPE windows_perfdata_process_thread_count counter\s*windows_perfdata_process_thread_count\{instance=".+"} \d`),
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.object, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
perfDataCollector := perfdata.New(&perfdata.Config{
|
||||||
|
Objects: []perfdata.Object{
|
||||||
|
{
|
||||||
|
Object: tc.object,
|
||||||
|
Instances: tc.instances,
|
||||||
|
Counters: tc.counters,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||||
|
err := perfDataCollector.Build(logger, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
registry := prometheus.NewRegistry()
|
||||||
|
registry.MustRegister(collectorAdapter{*perfDataCollector})
|
||||||
|
|
||||||
|
rw := httptest.NewRecorder()
|
||||||
|
promhttp.HandlerFor(registry, promhttp.HandlerOpts{ErrorHandling: promhttp.ContinueOnError}).ServeHTTP(rw, &http.Request{})
|
||||||
|
got := rw.Body.String()
|
||||||
|
|
||||||
|
assert.NotEmpty(t, got)
|
||||||
|
assert.Regexp(t, tc.expectedMetrics, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
18
pkg/collector/perfdata/perfdata_test.go
Normal file
18
pkg/collector/perfdata/perfdata_test.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/alecthomas/kingpin/v2"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector/perfdata"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/testutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkCollector(b *testing.B) {
|
||||||
|
perfDataObjects := `[{"object":"Processor Information","instances":["*"],"counters":{"*": {}}}]`
|
||||||
|
kingpin.CommandLine.GetArg("collector.perfdata.objects").StringVar(&perfDataObjects)
|
||||||
|
|
||||||
|
testutils.FuncBenchmarkCollector(b, perfdata.Name, perfdata.NewWithFlags)
|
||||||
|
}
|
||||||
18
pkg/collector/perfdata/types.go
Normal file
18
pkg/collector/perfdata/types.go
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package perfdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Object struct {
|
||||||
|
Object string `json:"object" yaml:"object"`
|
||||||
|
Instances []string `json:"instances" yaml:"instances"`
|
||||||
|
Counters map[string]Counter `json:"counters" yaml:"counters"`
|
||||||
|
InstanceLabel string `json:"instance_label" yaml:"instance_label"` //nolint:tagliatelle
|
||||||
|
|
||||||
|
collector *perfdata.Collector
|
||||||
|
}
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
Type string `json:"type" yaml:"type"`
|
||||||
|
}
|
||||||
@@ -4,12 +4,11 @@ package physical_disk
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -106,15 +105,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"PhysicalDisk"}, nil
|
return []string{"PhysicalDisk"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.requestsQueued = prometheus.NewDesc(
|
c.requestsQueued = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "requests_queued"),
|
prometheus.BuildFQName(types.Namespace, Name, "requests_queued"),
|
||||||
"The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)",
|
"The number of requests queued to the disk (PhysicalDisk.CurrentDiskQueueLength)",
|
||||||
@@ -204,12 +203,16 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting physical_disk metrics", "err", err)
|
logger.Error("failed collecting physical_disk metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,9 +235,11 @@ type PhysicalDisk struct {
|
|||||||
AvgDiskSecPerTransfer float64 `perflib:"Avg. Disk sec/Transfer"`
|
AvgDiskSecPerTransfer float64 `perflib:"Avg. Disk sec/Transfer"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []PhysicalDisk
|
var dst []PhysicalDisk
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["PhysicalDisk"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["PhysicalDisk"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ package printer
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -104,11 +103,11 @@ func NewWithFlags(app *kingpin.Application) *Collector {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -139,7 +138,9 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
|
|
||||||
func (c *Collector) GetName() string { return Name }
|
func (c *Collector) GetName() string { return Name }
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) { return []string{"Printer"}, nil }
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
|
return []string{"Printer"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type wmiPrinter struct {
|
type wmiPrinter struct {
|
||||||
Name string
|
Name string
|
||||||
@@ -153,15 +154,21 @@ type wmiPrintJob struct {
|
|||||||
Status string
|
Status string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectPrinterStatus(ch); err != nil {
|
if err := c.collectPrinterStatus(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed to collect printer status metrics", "err", err)
|
logger.Error("failed to collect printer status metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectPrinterJobStatus(ch); err != nil {
|
if err := c.collectPrinterJobStatus(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed to collect printer job status metrics", "err", err)
|
logger.Error("failed to collect printer job status metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,13 @@ package process
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -124,16 +122,16 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Process"}, nil
|
return []string{"Process"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
@@ -142,7 +140,7 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
c.wmiClient = wmiClient
|
c.wmiClient = wmiClient
|
||||||
|
|
||||||
if c.config.ProcessInclude.String() == "^(?:.*)$" && c.config.ProcessExclude.String() == "^(?:)$" {
|
if c.config.ProcessInclude.String() == "^(?:.*)$" && c.config.ProcessExclude.String() == "^(?:)$" {
|
||||||
_ = level.Warn(logger).Log("msg", "No filters specified for process collector. This will generate a very large number of metrics!")
|
logger.Warn("No filters specified for process collector. This will generate a very large number of metrics!")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.info = prometheus.NewDesc(
|
c.info = prometheus.NewDesc(
|
||||||
@@ -285,9 +283,10 @@ type WorkerProcess struct {
|
|||||||
ProcessId uint64
|
ProcessId uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
data := make([]perflibProcess, 0)
|
data := make([]perflibProcess, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Process"], &data, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["Process"], &data, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -296,7 +295,9 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
var workerProcesses []WorkerProcess
|
var workerProcesses []WorkerProcess
|
||||||
if c.config.EnableWorkerProcess {
|
if c.config.EnableWorkerProcess {
|
||||||
if err := c.wmiClient.Query("SELECT * FROM WorkerProcess", &workerProcesses, nil, "root\\WebAdministration"); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM WorkerProcess", &workerProcesses, nil, "root\\WebAdministration"); err != nil {
|
||||||
_ = level.Debug(logger).Log("msg", "Could not query WebAdministration namespace for IIS worker processes", "err", err)
|
logger.Debug("Could not query WebAdministration namespace for IIS worker processes",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -316,6 +317,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
for _, wp := range workerProcesses {
|
for _, wp := range workerProcesses {
|
||||||
if wp.ProcessId == uint64(process.IDProcess) {
|
if wp.ProcessId == uint64(process.IDProcess) {
|
||||||
processName = strings.Join([]string{processName, wp.AppPoolName}, "_")
|
processName = strings.Join([]string{processName, wp.AppPoolName}, "_")
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,7 +325,10 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
|
|
||||||
cmdLine, processOwner, processGroupID, err := c.getProcessInformation(logger, uint32(process.IDProcess))
|
cmdLine, processOwner, processGroupID, err := c.getProcessInformation(logger, uint32(process.IDProcess))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Debug(logger).Log("msg", "Failed to get process information", "pid", pid, "err", err)
|
logger.Debug("Failed to get process information",
|
||||||
|
slog.String("pid", pid),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -485,7 +490,7 @@ func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ref: https://github.com/microsoft/hcsshim/blob/8beabacfc2d21767a07c20f8dd5f9f3932dbf305/internal/uvm/stats.go#L25
|
// ref: https://github.com/microsoft/hcsshim/blob/8beabacfc2d21767a07c20f8dd5f9f3932dbf305/internal/uvm/stats.go#L25
|
||||||
func (c *Collector) getProcessInformation(logger log.Logger, pid uint32) (string, string, uint32, error) {
|
func (c *Collector) getProcessInformation(logger *slog.Logger, pid uint32) (string, string, uint32, error) {
|
||||||
if pid == 0 {
|
if pid == 0 {
|
||||||
return "", "", 0, nil
|
return "", "", 0, nil
|
||||||
}
|
}
|
||||||
@@ -501,7 +506,9 @@ func (c *Collector) getProcessInformation(logger log.Logger, pid uint32) (string
|
|||||||
|
|
||||||
defer func(hProcess windows.Handle) {
|
defer func(hProcess windows.Handle) {
|
||||||
if err := windows.CloseHandle(hProcess); err != nil {
|
if err := windows.CloseHandle(hProcess); err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "CloseHandle failed", "err", err)
|
logger.Warn("CloseHandle failed",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}(hProcess)
|
}(hProcess)
|
||||||
|
|
||||||
@@ -528,12 +535,14 @@ func (c *Collector) getProcessInformation(logger log.Logger, pid uint32) (string
|
|||||||
func (c *Collector) getExtendedProcessInformation(hProcess windows.Handle) (string, uint32, error) {
|
func (c *Collector) getExtendedProcessInformation(hProcess windows.Handle) (string, uint32, error) {
|
||||||
// Get the process environment block (PEB) address
|
// Get the process environment block (PEB) address
|
||||||
var pbi windows.PROCESS_BASIC_INFORMATION
|
var pbi windows.PROCESS_BASIC_INFORMATION
|
||||||
|
|
||||||
retLen := uint32(unsafe.Sizeof(pbi))
|
retLen := uint32(unsafe.Sizeof(pbi))
|
||||||
if err := windows.NtQueryInformationProcess(hProcess, windows.ProcessBasicInformation, unsafe.Pointer(&pbi), retLen, &retLen); err != nil {
|
if err := windows.NtQueryInformationProcess(hProcess, windows.ProcessBasicInformation, unsafe.Pointer(&pbi), retLen, &retLen); err != nil {
|
||||||
return "", 0, fmt.Errorf("failed to query process basic information: %w", err)
|
return "", 0, fmt.Errorf("failed to query process basic information: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
peb := windows.PEB{}
|
peb := windows.PEB{}
|
||||||
|
|
||||||
err := windows.ReadProcessMemory(hProcess,
|
err := windows.ReadProcessMemory(hProcess,
|
||||||
uintptr(unsafe.Pointer(pbi.PebBaseAddress)),
|
uintptr(unsafe.Pointer(pbi.PebBaseAddress)),
|
||||||
(*byte)(unsafe.Pointer(&peb)),
|
(*byte)(unsafe.Pointer(&peb)),
|
||||||
@@ -545,6 +554,7 @@ func (c *Collector) getExtendedProcessInformation(hProcess windows.Handle) (stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
processParameters := windows.RTL_USER_PROCESS_PARAMETERS{}
|
processParameters := windows.RTL_USER_PROCESS_PARAMETERS{}
|
||||||
|
|
||||||
err = windows.ReadProcessMemory(hProcess,
|
err = windows.ReadProcessMemory(hProcess,
|
||||||
uintptr(unsafe.Pointer(peb.ProcessParameters)),
|
uintptr(unsafe.Pointer(peb.ProcessParameters)),
|
||||||
(*byte)(unsafe.Pointer(&processParameters)),
|
(*byte)(unsafe.Pointer(&processParameters)),
|
||||||
@@ -570,7 +580,7 @@ func (c *Collector) getExtendedProcessInformation(hProcess windows.Handle) (stri
|
|||||||
return strings.TrimSpace(windows.UTF16ToString(cmdLineUTF16)), processParameters.ProcessGroupId, nil
|
return strings.TrimSpace(windows.UTF16ToString(cmdLineUTF16)), processParameters.ProcessGroupId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) getProcessOwner(logger log.Logger, hProcess windows.Handle) (string, error) {
|
func (c *Collector) getProcessOwner(logger *slog.Logger, hProcess windows.Handle) (string, error) {
|
||||||
var tok windows.Token
|
var tok windows.Token
|
||||||
|
|
||||||
if err := windows.OpenProcessToken(hProcess, windows.TOKEN_QUERY, &tok); err != nil {
|
if err := windows.OpenProcessToken(hProcess, windows.TOKEN_QUERY, &tok); err != nil {
|
||||||
@@ -583,7 +593,9 @@ func (c *Collector) getProcessOwner(logger log.Logger, hProcess windows.Handle)
|
|||||||
|
|
||||||
defer func(tok windows.Token) {
|
defer func(tok windows.Token) {
|
||||||
if err := tok.Close(); err != nil {
|
if err := tok.Close(); err != nil {
|
||||||
_ = level.Warn(logger).Log("msg", "Token close failed", "err", err)
|
logger.Warn("Token close failed",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}(tok)
|
}(tok)
|
||||||
|
|
||||||
@@ -620,7 +632,7 @@ func (c *Collector) openProcess(pid uint32) (windows.Handle, bool, error) {
|
|||||||
return 0, false, fmt.Errorf("failed to open process: %w", err)
|
return 0, false, fmt.Errorf("failed to open process: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors.Is(err, syscall.Errno(0x57)) { // invalid parameter, for PIDs that don't exist
|
if errors.Is(err, windows.Errno(0x57)) { // invalid parameter, for PIDs that don't exist
|
||||||
return 0, false, errors.New("process not found")
|
return 0, false, errors.New("process not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,48 +4,71 @@ package collector
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Prometheus implements prometheus.Collector for a set of Windows Collectors.
|
// Interface guard.
|
||||||
|
var _ prometheus.Collector = (*Prometheus)(nil)
|
||||||
|
|
||||||
|
// Prometheus implements prometheus.Collector for a set of Windows MetricCollectors.
|
||||||
type Prometheus struct {
|
type Prometheus struct {
|
||||||
maxScrapeDuration time.Duration
|
maxScrapeDuration time.Duration
|
||||||
collectors *Collectors
|
logger *slog.Logger
|
||||||
logger log.Logger
|
metricCollectors *MetricCollectors
|
||||||
|
|
||||||
// Base metrics returned by Prometheus
|
// Base metrics returned by Prometheus
|
||||||
scrapeDurationDesc *prometheus.Desc
|
scrapeDurationDesc *prometheus.Desc
|
||||||
scrapeSuccessDesc *prometheus.Desc
|
collectorScrapeDurationDesc *prometheus.Desc
|
||||||
scrapeTimeoutDesc *prometheus.Desc
|
collectorScrapeSuccessDesc *prometheus.Desc
|
||||||
snapshotDuration *prometheus.Desc
|
collectorScrapeTimeoutDesc *prometheus.Desc
|
||||||
|
snapshotDuration *prometheus.Desc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrometheus returns a new Prometheus where the set of Collectors must
|
type collectorStatus struct {
|
||||||
|
name string
|
||||||
|
statusCode collectorStatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
type collectorStatusCode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
pending collectorStatusCode = iota
|
||||||
|
success
|
||||||
|
failed
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewPrometheusCollector returns a new Prometheus where the set of MetricCollectors must
|
||||||
// return metrics within the given timeout.
|
// return metrics within the given timeout.
|
||||||
func NewPrometheus(timeout time.Duration, cs *Collectors, logger log.Logger) *Prometheus {
|
func (c *MetricCollectors) NewPrometheusCollector(timeout time.Duration, logger *slog.Logger) *Prometheus {
|
||||||
return &Prometheus{
|
return &Prometheus{
|
||||||
maxScrapeDuration: timeout,
|
maxScrapeDuration: timeout,
|
||||||
collectors: cs,
|
metricCollectors: c,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
scrapeDurationDesc: prometheus.NewDesc(
|
scrapeDurationDesc: prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, "exporter", "scrape_duration_seconds"),
|
||||||
|
"windows_exporter: Total scrape duration.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
collectorScrapeDurationDesc: prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_duration_seconds"),
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_duration_seconds"),
|
||||||
"windows_exporter: Duration of a collection.",
|
"windows_exporter: Duration of a collection.",
|
||||||
[]string{"collector"},
|
[]string{"collector"},
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
scrapeSuccessDesc: prometheus.NewDesc(
|
collectorScrapeSuccessDesc: prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_success"),
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_success"),
|
||||||
"windows_exporter: Whether the collector was successful.",
|
"windows_exporter: Whether the collector was successful.",
|
||||||
[]string{"collector"},
|
[]string{"collector"},
|
||||||
nil,
|
nil,
|
||||||
),
|
),
|
||||||
scrapeTimeoutDesc: prometheus.NewDesc(
|
collectorScrapeTimeoutDesc: prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, "exporter", "collector_timeout"),
|
prometheus.BuildFQName(types.Namespace, "exporter", "collector_timeout"),
|
||||||
"windows_exporter: Whether the collector timed out.",
|
"windows_exporter: Whether the collector timed out.",
|
||||||
[]string{"collector"},
|
[]string{"collector"},
|
||||||
@@ -60,133 +83,159 @@ func NewPrometheus(timeout time.Duration, cs *Collectors, logger log.Logger) *Pr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Describe sends all the descriptors of the Collectors included to
|
func (p *Prometheus) Describe(_ chan<- *prometheus.Desc) {}
|
||||||
// the provided channel.
|
|
||||||
func (coll *Prometheus) Describe(ch chan<- *prometheus.Desc) {
|
|
||||||
ch <- coll.scrapeDurationDesc
|
|
||||||
ch <- coll.scrapeSuccessDesc
|
|
||||||
}
|
|
||||||
|
|
||||||
type collectorOutcome int
|
// Collect sends the collected metrics from each of the MetricCollectors to
|
||||||
|
|
||||||
const (
|
|
||||||
pending collectorOutcome = iota
|
|
||||||
success
|
|
||||||
failed
|
|
||||||
)
|
|
||||||
|
|
||||||
// Collect sends the collected metrics from each of the Collectors to
|
|
||||||
// prometheus.
|
// prometheus.
|
||||||
func (coll *Prometheus) Collect(ch chan<- prometheus.Metric) {
|
func (p *Prometheus) Collect(ch chan<- prometheus.Metric) {
|
||||||
t := time.Now()
|
t := time.Now()
|
||||||
|
|
||||||
scrapeContext, err := coll.collectors.PrepareScrapeContext()
|
// Scrape Performance Counters for all collectors
|
||||||
|
scrapeContext, err := p.metricCollectors.PrepareScrapeContext()
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
coll.snapshotDuration,
|
p.snapshotDuration,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
time.Since(t).Seconds(),
|
time.Since(t).Seconds(),
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ch <- prometheus.NewInvalidMetric(coll.scrapeSuccessDesc, fmt.Errorf("failed to prepare scrape: %w", err))
|
ch <- prometheus.NewInvalidMetric(p.collectorScrapeSuccessDesc, fmt.Errorf("failed to prepare scrape: %w", err))
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WaitGroup to wait for all collectors to finish
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(coll.collectors.collectors))
|
wg.Add(len(p.metricCollectors.Collectors))
|
||||||
collectorOutcomes := make(map[string]collectorOutcome)
|
|
||||||
for name := range coll.collectors.collectors {
|
|
||||||
collectorOutcomes[name] = pending
|
|
||||||
}
|
|
||||||
|
|
||||||
metricsBuffer := make(chan prometheus.Metric)
|
// Using a channel to collect the status of each collector
|
||||||
l := sync.Mutex{}
|
// A channel is safe to use concurrently while a map is not
|
||||||
finished := false
|
collectorStatusCh := make(chan collectorStatus, len(p.metricCollectors.Collectors))
|
||||||
go func() {
|
|
||||||
for m := range metricsBuffer {
|
|
||||||
l.Lock()
|
|
||||||
if !finished {
|
|
||||||
ch <- m
|
|
||||||
}
|
|
||||||
l.Unlock()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
for name, c := range coll.collectors.collectors {
|
// Execute all collectors concurrently
|
||||||
go func(name string, c Collector) {
|
// timeout handling is done in the execute function
|
||||||
|
for name, metricsCollector := range p.metricCollectors.Collectors {
|
||||||
|
go func(name string, metricsCollector Collector) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
outcome := coll.execute(coll.logger, name, c, scrapeContext, metricsBuffer)
|
|
||||||
l.Lock()
|
collectorStatusCh <- collectorStatus{
|
||||||
if !finished {
|
name: name,
|
||||||
collectorOutcomes[name] = outcome
|
statusCode: p.execute(name, metricsCollector, scrapeContext, ch),
|
||||||
}
|
}
|
||||||
l.Unlock()
|
}(name, metricsCollector)
|
||||||
}(name, c)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allDone := make(chan struct{})
|
// Wait for all collectors to finish
|
||||||
go func() {
|
wg.Wait()
|
||||||
wg.Wait()
|
|
||||||
close(allDone)
|
|
||||||
close(metricsBuffer)
|
|
||||||
}()
|
|
||||||
|
|
||||||
// Wait until either all Collectors finish, or timeout expires
|
// Close the channel since we are done writing to it
|
||||||
select {
|
close(collectorStatusCh)
|
||||||
case <-allDone:
|
|
||||||
case <-time.After(coll.maxScrapeDuration):
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Lock()
|
for status := range collectorStatusCh {
|
||||||
finished = true
|
|
||||||
|
|
||||||
remainingCollectorNames := make([]string, 0)
|
|
||||||
for name, outcome := range collectorOutcomes {
|
|
||||||
var successValue, timeoutValue float64
|
var successValue, timeoutValue float64
|
||||||
if outcome == pending {
|
if status.statusCode == pending {
|
||||||
timeoutValue = 1.0
|
timeoutValue = 1.0
|
||||||
remainingCollectorNames = append(remainingCollectorNames, name)
|
|
||||||
}
|
}
|
||||||
if outcome == success {
|
|
||||||
|
if status.statusCode == success {
|
||||||
successValue = 1.0
|
successValue = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
coll.scrapeSuccessDesc,
|
p.collectorScrapeSuccessDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
successValue,
|
successValue,
|
||||||
name,
|
status.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
coll.scrapeTimeoutDesc,
|
p.collectorScrapeTimeoutDesc,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
timeoutValue,
|
timeoutValue,
|
||||||
name,
|
status.name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(remainingCollectorNames) > 0 {
|
ch <- prometheus.MustNewConstMetric(
|
||||||
_ = level.Warn(coll.logger).Log("msg", fmt.Sprintf("Collection timed out, still waiting for %v", remainingCollectorNames))
|
p.scrapeDurationDesc,
|
||||||
}
|
prometheus.GaugeValue,
|
||||||
|
time.Since(t).Seconds(),
|
||||||
l.Unlock()
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (coll *Prometheus) execute(logger log.Logger, name string, c Collector, ctx *types.ScrapeContext, ch chan<- prometheus.Metric) collectorOutcome {
|
func (p *Prometheus) execute(name string, c Collector, ctx *types.ScrapeContext, ch chan<- prometheus.Metric) collectorStatusCode {
|
||||||
t := time.Now()
|
var (
|
||||||
err := c.Collect(ctx, logger, ch)
|
err error
|
||||||
duration := time.Since(t).Seconds()
|
duration time.Duration
|
||||||
ch <- prometheus.MustNewConstMetric(
|
timeout atomic.Bool
|
||||||
coll.scrapeDurationDesc,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
duration,
|
|
||||||
name,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// bufCh is a buffer channel to store the metrics
|
||||||
|
// This is needed because once timeout is reached, the prometheus registry channel is closed.
|
||||||
|
bufCh := make(chan prometheus.Metric, 10)
|
||||||
|
errCh := make(chan error, 1)
|
||||||
|
|
||||||
|
// Execute the collector
|
||||||
|
go func() {
|
||||||
|
errCh <- c.Collect(ctx, p.logger, bufCh)
|
||||||
|
|
||||||
|
close(bufCh)
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
// This prevents a panic from race-condition when closing the ch channel too early.
|
||||||
|
_ = recover()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Pass metrics to the prometheus registry
|
||||||
|
// If timeout is reached, the channel is closed.
|
||||||
|
// This will cause a panic if we try to write to it.
|
||||||
|
for m := range bufCh {
|
||||||
|
if !timeout.Load() {
|
||||||
|
ch <- m
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
|
||||||
|
// Wait for the collector to finish or timeout
|
||||||
|
select {
|
||||||
|
case err = <-errCh:
|
||||||
|
duration = time.Since(t)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
p.collectorScrapeDurationDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
duration.Seconds(),
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
case <-time.After(p.maxScrapeDuration):
|
||||||
|
timeout.Store(true)
|
||||||
|
|
||||||
|
duration = time.Since(t)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
p.collectorScrapeDurationDesc,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
duration.Seconds(),
|
||||||
|
name,
|
||||||
|
)
|
||||||
|
|
||||||
|
p.logger.Warn(fmt.Sprintf("collector %s timeouted after %s", name, p.maxScrapeDuration))
|
||||||
|
|
||||||
|
return pending
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(coll.logger).Log("msg", fmt.Sprintf("collector %s failed after %fs", name, duration), "err", err)
|
p.logger.Error(fmt.Sprintf("collector %s failed after %s", name, p.maxScrapeDuration),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return failed
|
return failed
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = level.Debug(coll.logger).Log("msg", fmt.Sprintf("collector %s succeeded after %fs.", name, duration))
|
p.logger.Error(fmt.Sprintf("collector %s succeeded after %s", name, p.maxScrapeDuration))
|
||||||
|
|
||||||
return success
|
return success
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
package remote_fx
|
package remote_fx
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
||||||
@@ -74,15 +73,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"RemoteFX Network", "RemoteFX Graphics"}, nil
|
return []string{"RemoteFX Network", "RemoteFX Graphics"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(log.Logger, *wmi.Client) error {
|
func (c *Collector) Build(*slog.Logger, *wmi.Client) error {
|
||||||
// net
|
// net
|
||||||
c.baseTCPRTT = prometheus.NewDesc(
|
c.baseTCPRTT = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "net_base_tcp_rtt_seconds"),
|
prometheus.BuildFQName(types.Namespace, Name, "net_base_tcp_rtt_seconds"),
|
||||||
@@ -206,21 +205,30 @@ func (c *Collector) Build(log.Logger, *wmi.Client) error {
|
|||||||
[]string{"session_name"},
|
[]string{"session_name"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectRemoteFXNetworkCount(ctx, logger, ch); err != nil {
|
if err := c.collectRemoteFXNetworkCount(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting terminal services session count metrics", "err", err)
|
logger.Error("failed collecting terminal services session count metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectRemoteFXGraphicsCounters(ctx, logger, ch); err != nil {
|
if err := c.collectRemoteFXGraphicsCounters(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting terminal services session count metrics", "err", err)
|
logger.Error("failed collecting terminal services session count metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,9 +249,10 @@ type perflibRemoteFxNetwork struct {
|
|||||||
RetransmissionRate float64 `perflib:"Percentage of packets that have been retransmitted"`
|
RetransmissionRate float64 `perflib:"Percentage of packets that have been retransmitted"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectRemoteFXNetworkCount(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectRemoteFXNetworkCount(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
dst := make([]perflibRemoteFxNetwork, 0)
|
dst := make([]perflibRemoteFxNetwork, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["RemoteFX Network"], &dst, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["RemoteFX Network"], &dst, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -336,6 +345,7 @@ func (c *Collector) collectRemoteFXNetworkCount(ctx *types.ScrapeContext, logger
|
|||||||
normalizeSessionName(d.Name),
|
normalizeSessionName(d.Name),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,9 +362,10 @@ type perflibRemoteFxGraphics struct {
|
|||||||
SourceFramesPerSecond float64 `perflib:"Source Frames/Second"`
|
SourceFramesPerSecond float64 `perflib:"Source Frames/Second"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectRemoteFXGraphicsCounters(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectRemoteFXGraphicsCounters(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
dst := make([]perflibRemoteFxGraphics, 0)
|
dst := make([]perflibRemoteFxGraphics, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["RemoteFX Graphics"], &dst, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["RemoteFX Graphics"], &dst, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ package scheduled_task
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/go-ole/go-ole"
|
"github.com/go-ole/go-ole"
|
||||||
"github.com/go-ole/go-ole/oleutil"
|
"github.com/go-ole/go-ole/oleutil"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
@@ -129,15 +128,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.lastResult = prometheus.NewDesc(
|
c.lastResult = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "last_result"),
|
prometheus.BuildFQName(types.Namespace, Name, "last_result"),
|
||||||
"The result that was returned the last time the registered task was run",
|
"The result that was returned the last time the registered task was run",
|
||||||
@@ -162,10 +161,13 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting user metrics", "err", err)
|
logger.Error("failed collecting user metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,10 +266,12 @@ func getScheduledTasks() (ScheduledTasks, error) {
|
|||||||
defer taskSchedulerObj.Release()
|
defer taskSchedulerObj.Release()
|
||||||
|
|
||||||
taskServiceObj := taskSchedulerObj.MustQueryInterface(ole.IID_IDispatch)
|
taskServiceObj := taskSchedulerObj.MustQueryInterface(ole.IID_IDispatch)
|
||||||
|
|
||||||
_, err = oleutil.CallMethod(taskServiceObj, "Connect")
|
_, err = oleutil.CallMethod(taskServiceObj, "Connect")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTasks, err
|
return scheduledTasks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer taskServiceObj.Release()
|
defer taskServiceObj.Release()
|
||||||
|
|
||||||
res, err := oleutil.CallMethod(taskServiceObj, "GetFolder", `\`)
|
res, err := oleutil.CallMethod(taskServiceObj, "GetFolder", `\`)
|
||||||
@@ -325,6 +329,7 @@ func fetchTasksRecursively(folder *ole.IDispatch, scheduledTasks *ScheduledTasks
|
|||||||
err = oleutil.ForEach(subFolders, func(v *ole.VARIANT) error {
|
err = oleutil.ForEach(subFolders, func(v *ole.VARIANT) error {
|
||||||
subFolder := v.ToIDispatch()
|
subFolder := v.ToIDispatch()
|
||||||
defer subFolder.Release()
|
defer subFolder.Release()
|
||||||
|
|
||||||
return fetchTasksRecursively(subFolder, scheduledTasks)
|
return fetchTasksRecursively(subFolder, scheduledTasks)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -338,6 +343,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskNameVar.Clear(); tempErr != nil {
|
if tempErr := taskNameVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -348,6 +354,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskPathVar.Clear(); tempErr != nil {
|
if tempErr := taskPathVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -358,6 +365,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskEnabledVar.Clear(); tempErr != nil {
|
if tempErr := taskEnabledVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -368,6 +376,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskStateVar.Clear(); tempErr != nil {
|
if tempErr := taskStateVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -378,6 +387,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskNumberOfMissedRunsVar.Clear(); tempErr != nil {
|
if tempErr := taskNumberOfMissedRunsVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -388,6 +398,7 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return scheduledTask, err
|
return scheduledTask, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if tempErr := taskLastTaskResultVar.Clear(); tempErr != nil {
|
if tempErr := taskLastTaskResultVar.Clear(); tempErr != nil {
|
||||||
err = tempErr
|
err = tempErr
|
||||||
@@ -396,9 +407,11 @@ func parseTask(task *ole.IDispatch) (ScheduledTask, error) {
|
|||||||
|
|
||||||
scheduledTask.Name = taskNameVar.ToString()
|
scheduledTask.Name = taskNameVar.ToString()
|
||||||
scheduledTask.Path = strings.ReplaceAll(taskPathVar.ToString(), "\\", "/")
|
scheduledTask.Path = strings.ReplaceAll(taskPathVar.ToString(), "\\", "/")
|
||||||
|
|
||||||
if val, ok := taskEnabledVar.Value().(bool); ok {
|
if val, ok := taskEnabledVar.Value().(bool); ok {
|
||||||
scheduledTask.Enabled = val
|
scheduledTask.Enabled = val
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduledTask.State = TaskState(taskStateVar.Val)
|
scheduledTask.State = TaskState(taskStateVar.Val)
|
||||||
scheduledTask.MissedRunsCount = float64(taskNumberOfMissedRunsVar.Val)
|
scheduledTask.MissedRunsCount = float64(taskNumberOfMissedRunsVar.Val)
|
||||||
scheduledTask.LastTaskResult = TaskResult(taskLastTaskResultVar.Val)
|
scheduledTask.LastTaskResult = TaskResult(taskLastTaskResultVar.Val)
|
||||||
|
|||||||
@@ -5,16 +5,13 @@ package service
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/utils"
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
@@ -24,30 +21,25 @@ import (
|
|||||||
const Name = "service"
|
const Name = "service"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ServiceWhereClause string `yaml:"service_where_clause"`
|
ServiceInclude *regexp.Regexp `yaml:"service_include"`
|
||||||
UseAPI bool `yaml:"use_api"`
|
ServiceExclude *regexp.Regexp `yaml:"service_exclude"`
|
||||||
V2 bool `yaml:"v2"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ConfigDefaults = Config{
|
var ConfigDefaults = Config{
|
||||||
ServiceWhereClause: "",
|
ServiceInclude: types.RegExpAny,
|
||||||
UseAPI: false,
|
ServiceExclude: types.RegExpEmpty,
|
||||||
V2: false,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A Collector is a Prometheus Collector for WMI Win32_Service metrics.
|
// A Collector is a Prometheus Collector for service metrics.
|
||||||
type Collector struct {
|
type Collector struct {
|
||||||
serviceWhereClause *string
|
config Config
|
||||||
useAPI *bool
|
|
||||||
v2 *bool
|
|
||||||
|
|
||||||
wmiClient *wmi.Client
|
state *prometheus.Desc
|
||||||
|
processID *prometheus.Desc
|
||||||
|
info *prometheus.Desc
|
||||||
|
startMode *prometheus.Desc
|
||||||
|
|
||||||
Information *prometheus.Desc
|
serviceManagerHandle *mgr.Mgr
|
||||||
State *prometheus.Desc
|
|
||||||
StartMode *prometheus.Desc
|
|
||||||
Status *prometheus.Desc
|
|
||||||
StateV2 *prometheus.Desc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *Config) *Collector {
|
func New(config *Config) *Collector {
|
||||||
@@ -55,372 +47,162 @@ func New(config *Config) *Collector {
|
|||||||
config = &ConfigDefaults
|
config = &ConfigDefaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.ServiceExclude == nil {
|
||||||
|
config.ServiceExclude = ConfigDefaults.ServiceExclude
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ServiceInclude == nil {
|
||||||
|
config.ServiceInclude = ConfigDefaults.ServiceInclude
|
||||||
|
}
|
||||||
|
|
||||||
c := &Collector{
|
c := &Collector{
|
||||||
serviceWhereClause: &config.ServiceWhereClause,
|
config: *config,
|
||||||
useAPI: &config.UseAPI,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWithFlags(app *kingpin.Application) *Collector {
|
func NewWithFlags(app *kingpin.Application) *Collector {
|
||||||
return &Collector{
|
c := &Collector{
|
||||||
serviceWhereClause: app.Flag(
|
config: ConfigDefaults,
|
||||||
"collector.service.services-where",
|
|
||||||
"WQL 'where' clause to use in WMI metrics query. Limits the response to the services you specify and reduces the size of the response.",
|
|
||||||
).Default(ConfigDefaults.ServiceWhereClause).String(),
|
|
||||||
useAPI: app.Flag(
|
|
||||||
"collector.service.use-api",
|
|
||||||
"Use API calls to collect service data instead of WMI. Flag 'collector.service.services-where' won't be effective.",
|
|
||||||
).Default(strconv.FormatBool(ConfigDefaults.UseAPI)).Bool(),
|
|
||||||
v2: app.Flag(
|
|
||||||
"collector.service.v2",
|
|
||||||
"Enable V2 service collector. This collector can services state much more efficiently, can't provide general service information.",
|
|
||||||
).Default(strconv.FormatBool(ConfigDefaults.V2)).Bool(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var serviceExclude, serviceInclude string
|
||||||
|
|
||||||
|
app.Flag(
|
||||||
|
"collector.service.exclude",
|
||||||
|
"Regexp of service to exclude. Service name (not the display name!) must both match include and not match exclude to be included.",
|
||||||
|
).Default(c.config.ServiceExclude.String()).StringVar(&serviceExclude)
|
||||||
|
|
||||||
|
app.Flag(
|
||||||
|
"collector.service.include",
|
||||||
|
"Regexp of service to include. Process name (not the display name!) must both match include and not match exclude to be included.",
|
||||||
|
).Default(c.config.ServiceInclude.String()).StringVar(&serviceInclude)
|
||||||
|
|
||||||
|
app.Action(func(*kingpin.ParseContext) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.config.ServiceExclude, err = regexp.Compile(fmt.Sprintf("^(?:%s)$", serviceExclude))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("collector.process.exclude: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.config.ServiceInclude, err = regexp.Compile(fmt.Sprintf("^(?:%s)$", serviceInclude))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("collector.process.include: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetName() string {
|
func (c *Collector) GetName() string {
|
||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
return nil
|
logger = logger.With(slog.String("collector", Name))
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
if c.config.ServiceInclude.String() == "^(?:.*)$" && c.config.ServiceExclude.String() == "^(?:)$" {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
logger.Warn("No filters specified for service collector. This will generate a very large number of metrics!")
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.wmiClient = wmiClient
|
c.info = prometheus.NewDesc(
|
||||||
|
|
||||||
logger = log.With(logger, "collector", Name)
|
|
||||||
|
|
||||||
if utils.IsEmpty(c.serviceWhereClause) {
|
|
||||||
_ = level.Warn(logger).Log("msg", "No where-clause specified for service collector. This will generate a very large number of metrics!")
|
|
||||||
}
|
|
||||||
if *c.useAPI {
|
|
||||||
_ = level.Warn(logger).Log("msg", "API collection is enabled.")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Information = prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
prometheus.BuildFQName(types.Namespace, Name, "info"),
|
||||||
"A metric with a constant '1' value labeled with service information",
|
"A metric with a constant '1' value labeled with service information",
|
||||||
[]string{"name", "display_name", "process_id", "run_as"},
|
[]string{"name", "display_name", "run_as", "path_name"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.State = prometheus.NewDesc(
|
c.state = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "state"),
|
prometheus.BuildFQName(types.Namespace, Name, "state"),
|
||||||
"The state of the service (State)",
|
"The state of the service (State)",
|
||||||
[]string{"name", "state"},
|
[]string{"name", "status"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.StartMode = prometheus.NewDesc(
|
c.startMode = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "start_mode"),
|
prometheus.BuildFQName(types.Namespace, Name, "start_mode"),
|
||||||
"The start mode of the service (StartMode)",
|
"The start mode of the service (StartMode)",
|
||||||
[]string{"name", "start_mode"},
|
[]string{"name", "start_mode"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
c.Status = prometheus.NewDesc(
|
c.processID = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "status"),
|
prometheus.BuildFQName(types.Namespace, Name, "process"),
|
||||||
"The status of the service (Status)",
|
"Process of started service. The value is the creation time of the process as a unix timestamp.",
|
||||||
[]string{"name", "status"},
|
[]string{"name", "process_id"},
|
||||||
nil,
|
|
||||||
)
|
|
||||||
c.StateV2 = prometheus.NewDesc(
|
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "state"),
|
|
||||||
"The state of the service (State)",
|
|
||||||
[]string{"name", "display_name", "status"},
|
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EnumServiceStatusEx requires only SC_MANAGER_ENUM_SERVICE.
|
||||||
|
handle, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_ENUMERATE_SERVICE)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open scm: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.serviceManagerHandle = &mgr.Mgr{Handle: handle}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) Close(logger *slog.Logger) error {
|
||||||
|
if err := c.serviceManagerHandle.Disconnect(); err != nil {
|
||||||
|
logger.Warn("Failed to disconnect from scm",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
var err error
|
|
||||||
|
|
||||||
switch {
|
if err := c.collect(logger, ch); err != nil {
|
||||||
case *c.useAPI:
|
logger.Error("failed collecting API service metrics:",
|
||||||
if err = c.collectAPI(logger, ch); err != nil {
|
slog.Any("err", err),
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting API service metrics:", "err", err)
|
|
||||||
}
|
|
||||||
case *c.v2:
|
|
||||||
if err = c.collectAPIV2(logger, ch); err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting API service metrics:", "err", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if err = c.collectWMI(ch); err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting WMI service metrics:", "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Win32_Service docs:
|
|
||||||
// - https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx
|
|
||||||
type Win32_Service struct {
|
|
||||||
DisplayName string
|
|
||||||
Name string
|
|
||||||
ProcessId uint32
|
|
||||||
State string
|
|
||||||
Status string
|
|
||||||
StartMode string
|
|
||||||
StartName *string
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
allStates = []string{
|
|
||||||
"stopped",
|
|
||||||
"start pending",
|
|
||||||
"stop pending",
|
|
||||||
"running",
|
|
||||||
"continue pending",
|
|
||||||
"pause pending",
|
|
||||||
"paused",
|
|
||||||
"unknown",
|
|
||||||
}
|
|
||||||
apiStateValues = map[uint32]string{
|
|
||||||
windows.SERVICE_CONTINUE_PENDING: "continue pending",
|
|
||||||
windows.SERVICE_PAUSE_PENDING: "pause pending",
|
|
||||||
windows.SERVICE_PAUSED: "paused",
|
|
||||||
windows.SERVICE_RUNNING: "running",
|
|
||||||
windows.SERVICE_START_PENDING: "start pending",
|
|
||||||
windows.SERVICE_STOP_PENDING: "stop pending",
|
|
||||||
windows.SERVICE_STOPPED: "stopped",
|
|
||||||
}
|
|
||||||
allStartModes = []string{
|
|
||||||
"boot",
|
|
||||||
"system",
|
|
||||||
"auto",
|
|
||||||
"manual",
|
|
||||||
"disabled",
|
|
||||||
}
|
|
||||||
apiStartModeValues = map[uint32]string{
|
|
||||||
windows.SERVICE_AUTO_START: "auto",
|
|
||||||
windows.SERVICE_BOOT_START: "boot",
|
|
||||||
windows.SERVICE_DEMAND_START: "manual",
|
|
||||||
windows.SERVICE_DISABLED: "disabled",
|
|
||||||
windows.SERVICE_SYSTEM_START: "system",
|
|
||||||
}
|
|
||||||
allStatuses = []string{
|
|
||||||
"ok",
|
|
||||||
"error",
|
|
||||||
"degraded",
|
|
||||||
"unknown",
|
|
||||||
"pred fail",
|
|
||||||
"starting",
|
|
||||||
"stopping",
|
|
||||||
"service",
|
|
||||||
"stressed",
|
|
||||||
"nonrecover",
|
|
||||||
"no contact",
|
|
||||||
"lost comm",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Collector) collectWMI(ch chan<- prometheus.Metric) error {
|
|
||||||
var dst []Win32_Service
|
|
||||||
query := "SELECT * FROM Win32_Service"
|
|
||||||
|
|
||||||
if *c.serviceWhereClause != "" {
|
|
||||||
query += " WHERE " + *c.serviceWhereClause
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.wmiClient.Query(query, &dst); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, service := range dst {
|
|
||||||
pid := strconv.FormatUint(uint64(service.ProcessId), 10)
|
|
||||||
|
|
||||||
runAs := ""
|
|
||||||
if service.StartName != nil {
|
|
||||||
runAs = *service.StartName
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.Information,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
1.0,
|
|
||||||
strings.ToLower(service.Name),
|
|
||||||
service.DisplayName,
|
|
||||||
pid,
|
|
||||||
runAs,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, state := range allStates {
|
return fmt.Errorf("failed collecting API service metrics: %w", err)
|
||||||
isCurrentState := 0.0
|
|
||||||
if state == strings.ToLower(service.State) {
|
|
||||||
isCurrentState = 1.0
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.State,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentState,
|
|
||||||
strings.ToLower(service.Name),
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, startMode := range allStartModes {
|
|
||||||
isCurrentStartMode := 0.0
|
|
||||||
if startMode == strings.ToLower(service.StartMode) {
|
|
||||||
isCurrentStartMode = 1.0
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.StartMode,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentStartMode,
|
|
||||||
strings.ToLower(service.Name),
|
|
||||||
startMode,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, status := range allStatuses {
|
|
||||||
isCurrentStatus := 0.0
|
|
||||||
if status == strings.ToLower(service.Status) {
|
|
||||||
isCurrentStatus = 1.0
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.Status,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentStatus,
|
|
||||||
strings.ToLower(service.Name),
|
|
||||||
status,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectAPI(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
svcmgrConnection, err := mgr.Connect()
|
services, err := c.queryAllServices()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
logger.Warn("Failed to query services",
|
||||||
}
|
slog.Any("err", err),
|
||||||
defer svcmgrConnection.Disconnect() //nolint:errcheck
|
)
|
||||||
|
|
||||||
// List All Services from the Services Manager.
|
|
||||||
serviceList, err := svcmgrConnection.ListServices()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through the Services List.
|
|
||||||
for _, service := range serviceList {
|
|
||||||
(func() {
|
|
||||||
// Get UTF16 service name.
|
|
||||||
serviceName, err := syscall.UTF16PtrFromString(service)
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Service %s get name error: %#v", service, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open connection for service handler.
|
|
||||||
serviceHandle, err := windows.OpenService(svcmgrConnection.Handle, serviceName, windows.GENERIC_READ)
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Open service %s error: %#v", service, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create handle for each service.
|
|
||||||
serviceManager := &mgr.Service{Name: service, Handle: serviceHandle}
|
|
||||||
defer serviceManager.Close()
|
|
||||||
|
|
||||||
// Get Service Configuration.
|
|
||||||
serviceConfig, err := serviceManager.Config()
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Get service %s config error: %#v", service, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Service Current Status.
|
|
||||||
serviceStatus, err := serviceManager.Query()
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Get service %s status error: %#v", service, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pid := strconv.FormatUint(uint64(serviceStatus.ProcessId), 10)
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.Information,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
1.0,
|
|
||||||
strings.ToLower(service),
|
|
||||||
serviceConfig.DisplayName,
|
|
||||||
pid,
|
|
||||||
serviceConfig.ServiceStartName,
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, state := range apiStateValues {
|
|
||||||
isCurrentState := 0.0
|
|
||||||
if state == apiStateValues[uint32(serviceStatus.State)] {
|
|
||||||
isCurrentState = 1.0
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.State,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentState,
|
|
||||||
strings.ToLower(service),
|
|
||||||
state,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, startMode := range apiStartModeValues {
|
|
||||||
isCurrentStartMode := 0.0
|
|
||||||
if startMode == apiStartModeValues[serviceConfig.StartType] {
|
|
||||||
isCurrentStartMode = 1.0
|
|
||||||
}
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.StartMode,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentStartMode,
|
|
||||||
strings.ToLower(service),
|
|
||||||
startMode,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Collector) collectAPIV2(logger log.Logger, ch chan<- prometheus.Metric) error {
|
|
||||||
services, err := c.queryAllServiceStates(logger)
|
|
||||||
if err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to query services", "err", err)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if services == nil {
|
if services == nil {
|
||||||
_ = level.Warn(logger).Log("msg", "No services queried")
|
logger.Warn("No services queried")
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var isCurrentState float64
|
// Iterate through the Services List.
|
||||||
|
for _, service := range services {
|
||||||
|
serviceName := windows.UTF16PtrToString(service.ServiceName)
|
||||||
|
if c.config.ServiceExclude.MatchString(serviceName) ||
|
||||||
|
!c.config.ServiceInclude.MatchString(serviceName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, svc := range services {
|
if err := c.collectService(ch, logger, service); err != nil {
|
||||||
for state, stateValue := range apiStateValues {
|
logger.Warn("failed collecting service info",
|
||||||
isCurrentState = 0.0
|
slog.Any("err", err),
|
||||||
if state == svc.ServiceStatusProcess.CurrentState {
|
slog.String("service", windows.UTF16PtrToString(service.ServiceName)),
|
||||||
isCurrentState = 1.0
|
|
||||||
}
|
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
|
||||||
c.StateV2,
|
|
||||||
prometheus.GaugeValue,
|
|
||||||
isCurrentState,
|
|
||||||
windows.UTF16PtrToString(svc.ServiceName),
|
|
||||||
windows.UTF16PtrToString(svc.DisplayName),
|
|
||||||
stateValue,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -428,56 +210,207 @@ func (c *Collector) collectAPIV2(logger log.Logger, ch chan<- prometheus.Metric)
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// queryAllServiceStates returns all service states of the current Windows system
|
var apiStateValues = map[uint32]string{
|
||||||
// This is realized by ask Service Manager directly.
|
windows.SERVICE_CONTINUE_PENDING: "continue pending",
|
||||||
//
|
windows.SERVICE_PAUSE_PENDING: "pause pending",
|
||||||
// Unless explicitly stated otherwise all files in this repository are licensed
|
windows.SERVICE_PAUSED: "paused",
|
||||||
// under the Apache License Version 2.0.
|
windows.SERVICE_RUNNING: "running",
|
||||||
// This product includes software developed at Datadog (https://www.datadoghq.com/).
|
windows.SERVICE_START_PENDING: "start pending",
|
||||||
// Copyright 2016-present Datadog, Inc.
|
windows.SERVICE_STOP_PENDING: "stop pending",
|
||||||
//
|
windows.SERVICE_STOPPED: "stopped",
|
||||||
// Source: https://github.com/DataDog/datadog-agent/blob/afbd8b6c87939c92610c654cb07fdfd439e4fb27/pkg/util/winutil/scmmonitor.go#L61-L96
|
}
|
||||||
func (c *Collector) queryAllServiceStates(logger log.Logger) ([]windows.ENUM_SERVICE_STATUS_PROCESS, error) {
|
|
||||||
// EnumServiceStatusEx requires only SC_MANAGER_ENUM_SERVICE.
|
var apiStartModeValues = map[uint32]string{
|
||||||
h, err := windows.OpenSCManager(nil, nil, windows.SC_MANAGER_ENUMERATE_SERVICE)
|
windows.SERVICE_AUTO_START: "auto",
|
||||||
|
windows.SERVICE_BOOT_START: "boot",
|
||||||
|
windows.SERVICE_DEMAND_START: "manual",
|
||||||
|
windows.SERVICE_DISABLED: "disabled",
|
||||||
|
windows.SERVICE_SYSTEM_START: "system",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) collectService(ch chan<- prometheus.Metric, logger *slog.Logger, service windows.ENUM_SERVICE_STATUS_PROCESS) error {
|
||||||
|
// Open connection for service handler.
|
||||||
|
serviceHandle, err := windows.OpenService(c.serviceManagerHandle.Handle, service.ServiceName, windows.SERVICE_QUERY_CONFIG)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to open scm: %w", err)
|
return fmt.Errorf("failed to open service: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
m := &mgr.Mgr{Handle: h}
|
serviceNameString := windows.UTF16PtrToString(service.ServiceName)
|
||||||
defer func() {
|
|
||||||
if err := m.Disconnect(); err != nil {
|
|
||||||
_ = level.Warn(logger).Log("msg", "Failed to disconnect from scm", "err", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
var bytesNeeded, servicesReturned uint32
|
// Create handle for each service.
|
||||||
var buf []byte
|
serviceManager := &mgr.Service{Name: serviceNameString, Handle: serviceHandle}
|
||||||
for {
|
defer func(serviceManager *mgr.Service) {
|
||||||
var p *byte
|
if err := serviceManager.Close(); err != nil {
|
||||||
if len(buf) > 0 {
|
logger.Warn("failed to close service handle",
|
||||||
p = &buf[0]
|
slog.Any("err", err),
|
||||||
|
slog.String("service", serviceNameString),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
err = windows.EnumServicesStatusEx(m.Handle, windows.SC_ENUM_PROCESS_INFO,
|
}(serviceManager)
|
||||||
windows.SERVICE_WIN32, windows.SERVICE_STATE_ALL,
|
|
||||||
p, uint32(len(buf)), &bytesNeeded, &servicesReturned, nil, nil)
|
// Get Service Configuration.
|
||||||
if err == nil {
|
serviceConfig, err := serviceManager.Config()
|
||||||
break
|
if err != nil {
|
||||||
|
if !errors.Is(err, windows.ERROR_FILE_NOT_FOUND) && !errors.Is(err, windows.ERROR_MUI_FILE_NOT_FOUND) {
|
||||||
|
return fmt.Errorf("failed to get service configuration: %w", err)
|
||||||
}
|
}
|
||||||
if !errors.Is(err, windows.ERROR_MORE_DATA) {
|
|
||||||
return nil, fmt.Errorf("failed to enum services %w", err)
|
logger.Debug("failed collecting service",
|
||||||
|
slog.Any("err", err),
|
||||||
|
slog.String("service", serviceNameString),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.info,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
serviceNameString,
|
||||||
|
serviceConfig.DisplayName,
|
||||||
|
serviceConfig.ServiceStartName,
|
||||||
|
serviceConfig.BinaryPathName,
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
isCurrentStartMode float64
|
||||||
|
isCurrentState float64
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, startMode := range apiStartModeValues {
|
||||||
|
isCurrentStartMode = 0.0
|
||||||
|
if startMode == apiStartModeValues[serviceConfig.StartType] {
|
||||||
|
isCurrentStartMode = 1.0
|
||||||
}
|
}
|
||||||
if bytesNeeded <= uint32(len(buf)) {
|
ch <- prometheus.MustNewConstMetric(
|
||||||
return nil, err
|
c.startMode,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
isCurrentStartMode,
|
||||||
|
serviceNameString,
|
||||||
|
startMode,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for state, stateValue := range apiStateValues {
|
||||||
|
isCurrentState = 0.0
|
||||||
|
if state == service.ServiceStatusProcess.CurrentState {
|
||||||
|
isCurrentState = 1.0
|
||||||
}
|
}
|
||||||
buf = make([]byte, bytesNeeded)
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.state,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
isCurrentState,
|
||||||
|
serviceNameString,
|
||||||
|
stateValue,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
processID := strconv.FormatUint(uint64(service.ServiceStatusProcess.ProcessId), 10)
|
||||||
|
|
||||||
|
if processID != "0" { //nolint: nestif
|
||||||
|
processStartTime, err := getProcessStartTime(logger, service.ServiceStatusProcess.ProcessId)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
|
||||||
|
logger.Debug("failed to get process start time",
|
||||||
|
slog.String("service", serviceNameString),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logger.Warn("failed to get process start time",
|
||||||
|
slog.String("service", serviceNameString),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.processID,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(processStartTime/1_000_000_000),
|
||||||
|
serviceNameString,
|
||||||
|
processID,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// queryAllServices returns all service states of the current Windows system
|
||||||
|
// This is realized by ask Service Manager directly.
|
||||||
|
func (c *Collector) queryAllServices() ([]windows.ENUM_SERVICE_STATUS_PROCESS, error) {
|
||||||
|
var (
|
||||||
|
bytesNeeded uint32
|
||||||
|
servicesReturned uint32
|
||||||
|
resumeHandle uint32
|
||||||
|
)
|
||||||
|
|
||||||
|
if err := windows.EnumServicesStatusEx(
|
||||||
|
c.serviceManagerHandle.Handle,
|
||||||
|
windows.SC_STATUS_PROCESS_INFO,
|
||||||
|
windows.SERVICE_WIN32,
|
||||||
|
windows.SERVICE_STATE_ALL,
|
||||||
|
nil,
|
||||||
|
0,
|
||||||
|
&bytesNeeded,
|
||||||
|
&servicesReturned,
|
||||||
|
&resumeHandle,
|
||||||
|
nil,
|
||||||
|
); !errors.Is(err, windows.ERROR_MORE_DATA) {
|
||||||
|
return nil, fmt.Errorf("could not fetch buffer size for EnumServicesStatusEx: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, bytesNeeded)
|
||||||
|
if err := windows.EnumServicesStatusEx(
|
||||||
|
c.serviceManagerHandle.Handle,
|
||||||
|
windows.SC_STATUS_PROCESS_INFO,
|
||||||
|
windows.SERVICE_WIN32,
|
||||||
|
windows.SERVICE_STATE_ALL,
|
||||||
|
&buf[0],
|
||||||
|
bytesNeeded,
|
||||||
|
&bytesNeeded,
|
||||||
|
&servicesReturned,
|
||||||
|
&resumeHandle,
|
||||||
|
nil,
|
||||||
|
); err != nil {
|
||||||
|
return nil, fmt.Errorf("could not query windows service list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if servicesReturned == 0 {
|
if servicesReturned == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
services := unsafe.Slice((*windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])), servicesReturned)
|
services := unsafe.Slice((*windows.ENUM_SERVICE_STATUS_PROCESS)(unsafe.Pointer(&buf[0])), int(servicesReturned))
|
||||||
|
|
||||||
return services, nil
|
return services, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getProcessStartTime(logger *slog.Logger, pid uint32) (uint64, error) {
|
||||||
|
handle, err := windows.OpenProcess(windows.PROCESS_QUERY_LIMITED_INFORMATION, false, pid)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to open process %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func(handle windows.Handle) {
|
||||||
|
err := windows.CloseHandle(handle)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("failed to close process handle",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}(handle)
|
||||||
|
|
||||||
|
var creation windows.Filetime
|
||||||
|
|
||||||
|
var exit windows.Filetime
|
||||||
|
|
||||||
|
var krn windows.Filetime
|
||||||
|
|
||||||
|
var user windows.Filetime
|
||||||
|
|
||||||
|
err = windows.GetProcessTimes(handle, &creation, &exit, &krn, &user)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to get process times %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint64(creation.Nanoseconds()), nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
package smb
|
package smb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -47,17 +46,17 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
"SMB Server Shares",
|
"SMB Server Shares",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
// desc creates a new prometheus description
|
// desc creates a new prometheus description
|
||||||
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
desc := func(metricName string, description string, labels ...string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(
|
return prometheus.NewDesc(
|
||||||
@@ -75,10 +74,12 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect collects smb metrics and sends them to prometheus.
|
// Collect collects smb metrics and sends them to prometheus.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectServerShares(ctx, logger, ch); err != nil {
|
if err := c.collectServerShares(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed to collect server share metrics", "err", err)
|
logger.Error("failed to collect server share metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -94,12 +95,15 @@ type perflibServerShares struct {
|
|||||||
TreeConnectCount float64 `perflib:"Tree Connect Count"`
|
TreeConnectCount float64 `perflib:"Tree Connect Count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectServerShares(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectServerShares(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibServerShares
|
var data []perflibServerShares
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMB Server Shares"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMB Server Shares"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, instance := range data {
|
for _, instance := range data {
|
||||||
labelName := c.toLabelName(instance.Name)
|
labelName := c.toLabelName(instance.Name)
|
||||||
if !strings.HasSuffix(labelName, "_total") {
|
if !strings.HasSuffix(labelName, "_total") {
|
||||||
@@ -118,6 +122,7 @@ func (c *Collector) collectServerShares(ctx *types.ScrapeContext, logger log.Log
|
|||||||
instance.TreeConnectCount,
|
instance.TreeConnectCount,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,5 +130,6 @@ func (c *Collector) collectServerShares(ctx *types.ScrapeContext, logger log.Log
|
|||||||
func (c *Collector) toLabelName(name string) string {
|
func (c *Collector) toLabelName(name string) string {
|
||||||
s := strings.ReplaceAll(strings.Join(strings.Fields(strings.ToLower(name)), "_"), ".", "_")
|
s := strings.ReplaceAll(strings.Join(strings.Fields(strings.ToLower(name)), "_"), ".", "_")
|
||||||
s = strings.ReplaceAll(s, "__", "_")
|
s = strings.ReplaceAll(s, "__", "_")
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,10 @@
|
|||||||
package smbclient
|
package smbclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -69,17 +68,17 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
"SMB Client Shares",
|
"SMB Client Shares",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
// desc creates a new prometheus description
|
// desc creates a new prometheus description
|
||||||
desc := func(metricName string, description string, labels []string) *prometheus.Desc {
|
desc := func(metricName string, description string, labels []string) *prometheus.Desc {
|
||||||
return prometheus.NewDesc(
|
return prometheus.NewDesc(
|
||||||
@@ -179,10 +178,13 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect collects smb client metrics and sends them to prometheus.
|
// Collect collects smb client metrics and sends them to prometheus.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectClientShares(ctx, logger, ch); err != nil {
|
if err := c.collectClientShares(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "Error in ClientShares", "err", err)
|
logger.Error("Error in ClientShares",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,12 +218,15 @@ type perflibClientShares struct {
|
|||||||
WriteRequestsPerSec float64 `perflib:"Write Requests/sec"`
|
WriteRequestsPerSec float64 `perflib:"Write Requests/sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectClientShares(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectClientShares(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var data []perflibClientShares
|
var data []perflibClientShares
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMB Client Shares"], &data, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMB Client Shares"], &data, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, instance := range data {
|
for _, instance := range data {
|
||||||
if instance.Name == "_Total" {
|
if instance.Name == "_Total" {
|
||||||
continue
|
continue
|
||||||
@@ -380,5 +385,6 @@ func (c *Collector) collectClientShares(ctx *types.ScrapeContext, logger log.Log
|
|||||||
serverValue, shareValue,
|
serverValue, shareValue,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ package smtp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -134,18 +133,18 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"SMTP Server"}, nil
|
return []string{"SMTP Server"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
_ = level.Info(logger).Log("msg", "smtp collector is in an experimental state! Metrics for this collector have not been tested.")
|
logger.Info("smtp collector is in an experimental state! Metrics for this collector have not been tested.")
|
||||||
|
|
||||||
c.badMailedMessagesBadPickupFileTotal = prometheus.NewDesc(
|
c.badMailedMessagesBadPickupFileTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "badmailed_messages_bad_pickup_file_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "badmailed_messages_bad_pickup_file_total"),
|
||||||
@@ -405,12 +404,16 @@ func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting smtp metrics", "err", err)
|
logger.Error("failed collecting smtp metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,9 +465,11 @@ type PerflibSMTPServer struct {
|
|||||||
RoutingTableLookupsTotal float64 `perflib:"Routing Table Lookups Total"`
|
RoutingTableLookupsTotal float64 `perflib:"Routing Table Lookups Total"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []PerflibSMTPServer
|
var dst []PerflibSMTPServer
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMTP Server"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["SMTP Server"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -763,5 +768,6 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
server.Name,
|
server.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -25,6 +26,8 @@ type Collector struct {
|
|||||||
contextSwitchesTotal *prometheus.Desc
|
contextSwitchesTotal *prometheus.Desc
|
||||||
exceptionDispatchesTotal *prometheus.Desc
|
exceptionDispatchesTotal *prometheus.Desc
|
||||||
processorQueueLength *prometheus.Desc
|
processorQueueLength *prometheus.Desc
|
||||||
|
processes *prometheus.Desc
|
||||||
|
processesLimit *prometheus.Desc
|
||||||
systemCallsTotal *prometheus.Desc
|
systemCallsTotal *prometheus.Desc
|
||||||
systemUpTime *prometheus.Desc
|
systemUpTime *prometheus.Desc
|
||||||
threads *prometheus.Desc
|
threads *prometheus.Desc
|
||||||
@@ -50,15 +53,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"System"}, nil
|
return []string{"System"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
c.contextSwitchesTotal = prometheus.NewDesc(
|
c.contextSwitchesTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "context_switches_total"),
|
||||||
"Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)",
|
"Total number of context switches (WMI source: PerfOS_System.ContextSwitchesPersec)",
|
||||||
@@ -71,6 +74,19 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
c.processes = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "processes"),
|
||||||
|
"Current number of processes (WMI source: PerfOS_System.Processes)",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
c.processesLimit = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "processes_limit"),
|
||||||
|
"Maximum number of processes.",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
|
||||||
c.processorQueueLength = prometheus.NewDesc(
|
c.processorQueueLength = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "processor_queue_length"),
|
prometheus.BuildFQName(types.Namespace, Name, "processor_queue_length"),
|
||||||
"Length of processor queue (WMI source: PerfOS_System.ProcessorQueueLength)",
|
"Length of processor queue (WMI source: PerfOS_System.ProcessorQueueLength)",
|
||||||
@@ -95,17 +111,22 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting system metrics", "err", err)
|
logger.Error("failed collecting system metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,16 +138,23 @@ type system struct {
|
|||||||
ProcessorQueueLength float64 `perflib:"Processor Queue Length"`
|
ProcessorQueueLength float64 `perflib:"Processor Queue Length"`
|
||||||
SystemCallsPersec float64 `perflib:"System Calls/sec"`
|
SystemCallsPersec float64 `perflib:"System Calls/sec"`
|
||||||
SystemUpTime float64 `perflib:"System Up Time"`
|
SystemUpTime float64 `perflib:"System Up Time"`
|
||||||
|
Processes float64 `perflib:"Processes"`
|
||||||
Threads float64 `perflib:"Threads"`
|
Threads float64 `perflib:"Threads"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
var dst []system
|
var dst []system
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["System"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["System"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(dst) == 0 {
|
||||||
|
return errors.New("no data returned from Performance Counter")
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.contextSwitchesTotal,
|
c.contextSwitchesTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
@@ -142,6 +170,11 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
dst[0].ProcessorQueueLength,
|
dst[0].ProcessorQueueLength,
|
||||||
)
|
)
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.processes,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
dst[0].Processes,
|
||||||
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.systemCallsTotal,
|
c.systemCallsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
@@ -157,5 +190,15 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
dst[0].Threads,
|
dst[0].Threads,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Windows has no defined limit, and is based off available resources. This currently isn't calculated by WMI and is set to default value.
|
||||||
|
// https://techcommunity.microsoft.com/t5/windows-blog-archive/pushing-the-limits-of-windows-processes-and-threads/ba-p/723824
|
||||||
|
// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-operatingsystem
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.processesLimit,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(4294967295),
|
||||||
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
16
pkg/collector/tcp/const.go
Normal file
16
pkg/collector/tcp/const.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package tcp
|
||||||
|
|
||||||
|
// Win32_PerfRawData_Tcpip_TCPv4 docs
|
||||||
|
// - https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx
|
||||||
|
// The TCPv6 performance object uses the same fields.
|
||||||
|
const (
|
||||||
|
ConnectionFailures = "Connection Failures"
|
||||||
|
ConnectionsActive = "Connections Active"
|
||||||
|
ConnectionsEstablished = "Connections Established"
|
||||||
|
ConnectionsPassive = "Connections Passive"
|
||||||
|
ConnectionsReset = "Connections Reset"
|
||||||
|
SegmentsPersec = "Segments/sec"
|
||||||
|
SegmentsReceivedPersec = "Segments Received/sec"
|
||||||
|
SegmentsRetransmittedPersec = "Segments Retransmitted/sec"
|
||||||
|
SegmentsSentPersec = "Segments Sent/sec"
|
||||||
|
)
|
||||||
@@ -3,10 +3,11 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -22,6 +23,9 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
perfDataCollector4 *perfdata.Collector
|
||||||
|
perfDataCollector6 *perfdata.Collector
|
||||||
|
|
||||||
connectionFailures *prometheus.Desc
|
connectionFailures *prometheus.Desc
|
||||||
connectionsActive *prometheus.Desc
|
connectionsActive *prometheus.Desc
|
||||||
connectionsEstablished *prometheus.Desc
|
connectionsEstablished *prometheus.Desc
|
||||||
@@ -53,15 +57,39 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"TCPv4"}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
|
counters := []string{
|
||||||
|
ConnectionFailures,
|
||||||
|
ConnectionsActive,
|
||||||
|
ConnectionsEstablished,
|
||||||
|
ConnectionsPassive,
|
||||||
|
ConnectionsReset,
|
||||||
|
SegmentsPersec,
|
||||||
|
SegmentsReceivedPersec,
|
||||||
|
SegmentsRetransmittedPersec,
|
||||||
|
SegmentsSentPersec,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
c.perfDataCollector4, err = perfdata.NewCollector("TCPv4", nil, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create TCPv4 collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.perfDataCollector6, err = perfdata.NewCollector("TCPv6", nil, counters)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create TCPv6 collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
c.connectionFailures = prometheus.NewDesc(
|
c.connectionFailures = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "connection_failures_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "connection_failures_total"),
|
||||||
"(TCP.ConnectionFailures)",
|
"(TCP.ConnectionFailures)",
|
||||||
@@ -116,111 +144,96 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
[]string{"af"},
|
[]string{"af"},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting tcp metrics", "err", err)
|
logger.Error("failed collecting tcp metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Win32_PerfRawData_Tcpip_TCPv4 docs
|
func writeTCPCounters(metrics map[string]perfdata.CounterValues, labels []string, c *Collector, ch chan<- prometheus.Metric) {
|
||||||
// - https://msdn.microsoft.com/en-us/library/aa394341(v=vs.85).aspx
|
|
||||||
// The TCPv6 performance object uses the same fields.
|
|
||||||
type tcp struct {
|
|
||||||
ConnectionFailures float64 `perflib:"Connection Failures"`
|
|
||||||
ConnectionsActive float64 `perflib:"Connections Active"`
|
|
||||||
ConnectionsEstablished float64 `perflib:"Connections Established"`
|
|
||||||
ConnectionsPassive float64 `perflib:"Connections Passive"`
|
|
||||||
ConnectionsReset float64 `perflib:"Connections Reset"`
|
|
||||||
SegmentsPersec float64 `perflib:"Segments/sec"`
|
|
||||||
SegmentsReceivedPersec float64 `perflib:"Segments Received/sec"`
|
|
||||||
SegmentsRetransmittedPersec float64 `perflib:"Segments Retransmitted/sec"`
|
|
||||||
SegmentsSentPersec float64 `perflib:"Segments Sent/sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTCPCounters(metrics tcp, labels []string, c *Collector, ch chan<- prometheus.Metric) {
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.connectionFailures,
|
c.connectionFailures,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.ConnectionFailures,
|
metrics[ConnectionFailures].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.connectionsActive,
|
c.connectionsActive,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.ConnectionsActive,
|
metrics[ConnectionsActive].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.connectionsEstablished,
|
c.connectionsEstablished,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
metrics.ConnectionsEstablished,
|
metrics[ConnectionsEstablished].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.connectionsPassive,
|
c.connectionsPassive,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.ConnectionsPassive,
|
metrics[ConnectionsPassive].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.connectionsReset,
|
c.connectionsReset,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.ConnectionsReset,
|
metrics[ConnectionsReset].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.segmentsTotal,
|
c.segmentsTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.SegmentsPersec,
|
metrics[SegmentsPersec].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.segmentsReceivedTotal,
|
c.segmentsReceivedTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.SegmentsReceivedPersec,
|
metrics[SegmentsReceivedPersec].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.segmentsRetransmittedTotal,
|
c.segmentsRetransmittedTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.SegmentsRetransmittedPersec,
|
metrics[SegmentsRetransmittedPersec].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.segmentsSentTotal,
|
c.segmentsSentTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
metrics.SegmentsSentPersec,
|
metrics[SegmentsSentPersec].FirstValue,
|
||||||
labels...,
|
labels...,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collect(ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
data, err := c.perfDataCollector4.Collect()
|
||||||
var dst []tcp
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to collect TCPv4 metrics: %w", err)
|
||||||
// TCPv4 counters
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["TCPv4"], &dst, logger); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(dst) != 0 {
|
|
||||||
writeTCPCounters(dst[0], []string{"ipv4"}, c, ch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCPv6 counters
|
writeTCPCounters(data[perfdata.EmptyInstance], []string{"ipv4"}, c, ch)
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["TCPv6"], &dst, logger); err != nil {
|
|
||||||
return err
|
data, err = c.perfDataCollector6.Collect()
|
||||||
}
|
if err != nil {
|
||||||
if len(dst) != 0 {
|
return fmt.Errorf("failed to collect TCPv6 metrics: %w", err)
|
||||||
writeTCPCounters(dst[0], []string{"ipv6"}, c, ch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeTCPCounters(data[perfdata.EmptyInstance], []string{"ipv6"}, c, ch)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package teradici_pcoip
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -92,17 +91,18 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
_ = level.Warn(logger).
|
logger.Warn("teradici_pcoip collector is deprecated and will be removed in the future.",
|
||||||
Log("msg", "teradici_pcoip collector is deprecated and will be removed in the future.", "collector", Name)
|
slog.String("collector", Name),
|
||||||
|
)
|
||||||
|
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
@@ -336,33 +336,54 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectAudio(ch); err != nil {
|
if err := c.collectAudio(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting teradici session audio metrics", "err", err)
|
logger.Error("failed collecting teradici session audio metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectGeneral(ch); err != nil {
|
if err := c.collectGeneral(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting teradici session general metrics", "err", err)
|
logger.Error("failed collecting teradici session general metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectImaging(ch); err != nil {
|
if err := c.collectImaging(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting teradici session imaging metrics", "err", err)
|
logger.Error("failed collecting teradici session imaging metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectNetwork(ch); err != nil {
|
if err := c.collectNetwork(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting teradici session network metrics", "err", err)
|
logger.Error("failed collecting teradici session network metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectUsb(ch); err != nil {
|
if err := c.collectUsb(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting teradici session USB metrics", "err", err)
|
logger.Error("failed collecting teradici session USB metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,6 +444,7 @@ func (c *Collector) collectAudio(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionAudioStatistics", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionAudioStatistics", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -465,6 +487,7 @@ func (c *Collector) collectGeneral(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionGeneralStatistics", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionGeneralStatistics", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -519,6 +542,7 @@ func (c *Collector) collectImaging(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionImagingStatistics", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionImagingStatistics", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -597,6 +621,7 @@ func (c *Collector) collectNetwork(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionNetworkStatistics", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionNetworkStatistics", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -669,6 +694,7 @@ func (c *Collector) collectUsb(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM win32_PerfRawData_TeradiciPerf_PCoIPSessionUsbStatistics", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,17 @@ package terminal_services
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/headers/wtsapi32"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/wtsapi32"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -32,17 +31,20 @@ type Win32_ServerFeature struct {
|
|||||||
ID uint32
|
ID uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
func isConnectionBrokerServer(logger log.Logger, wmiClient *wmi.Client) bool {
|
func isConnectionBrokerServer(logger *slog.Logger, wmiClient *wmi.Client) bool {
|
||||||
var dst []Win32_ServerFeature
|
var dst []Win32_ServerFeature
|
||||||
if err := wmiClient.Query("SELECT * FROM Win32_ServerFeature", &dst); err != nil {
|
if err := wmiClient.Query("SELECT * FROM Win32_ServerFeature", &dst); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range dst {
|
for _, d := range dst {
|
||||||
if d.ID == ConnectionBrokerFeatureID {
|
if d.ID == ConnectionBrokerFeatureID {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = level.Debug(logger).Log("msg", "host is not a connection broker skipping Connection Broker performance metrics.")
|
|
||||||
|
logger.Debug("host is not a connection broker skipping Connection Broker performance metrics.")
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +57,7 @@ type Collector struct {
|
|||||||
|
|
||||||
connectionBrokerEnabled bool
|
connectionBrokerEnabled bool
|
||||||
|
|
||||||
hServer syscall.Handle
|
hServer windows.Handle
|
||||||
|
|
||||||
sessionInfo *prometheus.Desc
|
sessionInfo *prometheus.Desc
|
||||||
connectionBrokerPerformance *prometheus.Desc
|
connectionBrokerPerformance *prometheus.Desc
|
||||||
@@ -94,14 +96,14 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
"Terminal Services Session",
|
"Terminal Services Session",
|
||||||
"Remote Desktop Connection Broker Counterset",
|
"Remote Desktop Connection Broker Counterset",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
err := wtsapi32.WTSCloseServer(c.hServer)
|
err := wtsapi32.WTSCloseServer(c.hServer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to close WTS server: %w", err)
|
return fmt.Errorf("failed to close WTS server: %w", err)
|
||||||
@@ -110,8 +112,8 @@ func (c *Collector) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
|
|
||||||
c.connectionBrokerEnabled = isConnectionBrokerServer(logger, wmiClient)
|
c.connectionBrokerEnabled = isConnectionBrokerServer(logger, wmiClient)
|
||||||
|
|
||||||
@@ -218,24 +220,35 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectWTSSessions(logger, ch); err != nil {
|
if err := c.collectWTSSessions(logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting terminal services session infos", "err", err)
|
logger.Error("failed collecting terminal services session infos",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectTSSessionCounters(ctx, logger, ch); err != nil {
|
if err := c.collectTSSessionCounters(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting terminal services session count metrics", "err", err)
|
logger.Error("failed collecting terminal services session count metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// only collect CollectionBrokerPerformance if host is a Connection Broker
|
// only collect CollectionBrokerPerformance if host is a Connection Broker
|
||||||
if c.connectionBrokerEnabled {
|
if c.connectionBrokerEnabled {
|
||||||
if err := c.collectCollectionBrokerPerformanceCounter(ctx, logger, ch); err != nil {
|
if err := c.collectCollectionBrokerPerformanceCounter(ctx, logger, ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting Connection Broker performance metrics", "err", err)
|
logger.Error("failed collecting Connection Broker performance metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,13 +271,15 @@ type perflibTerminalServicesSession struct {
|
|||||||
WorkingSetPeak float64 `perflib:"Working Set Peak"`
|
WorkingSetPeak float64 `perflib:"Working Set Peak"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
dst := make([]perflibTerminalServicesSession, 0)
|
dst := make([]perflibTerminalServicesSession, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Terminal Services Session"], &dst, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["Terminal Services Session"], &dst, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
names := make(map[string]bool)
|
names := make(map[string]bool)
|
||||||
|
|
||||||
for _, d := range dst {
|
for _, d := range dst {
|
||||||
@@ -277,6 +292,7 @@ func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger lo
|
|||||||
if _, ok := names[n]; ok {
|
if _, ok := names[n]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
names[n] = true
|
names[n] = true
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
@@ -373,6 +389,7 @@ func (c *Collector) collectTSSessionCounters(ctx *types.ScrapeContext, logger lo
|
|||||||
d.Name,
|
d.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,13 +399,15 @@ type perflibRemoteDesktopConnectionBrokerCounterset struct {
|
|||||||
FailedConnections float64 `perflib:"Failed Connections"`
|
FailedConnections float64 `perflib:"Failed Connections"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectCollectionBrokerPerformanceCounter(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectCollectionBrokerPerformanceCounter(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
dst := make([]perflibRemoteDesktopConnectionBrokerCounterset, 0)
|
dst := make([]perflibRemoteDesktopConnectionBrokerCounterset, 0)
|
||||||
|
|
||||||
err := perflib.UnmarshalObject(ctx.PerfObjects["Remote Desktop Connection Broker Counterset"], &dst, logger)
|
err := perflib.UnmarshalObject(ctx.PerfObjects["Remote Desktop Connection Broker Counterset"], &dst, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -417,7 +436,7 @@ func (c *Collector) collectCollectionBrokerPerformanceCounter(ctx *types.ScrapeC
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collectWTSSessions(logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectWTSSessions(logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
sessions, err := wtsapi32.WTSEnumerateSessionsEx(c.hServer, logger)
|
sessions, err := wtsapi32.WTSEnumerateSessionsEx(c.hServer, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to enumerate WTS sessions: %w", err)
|
return fmt.Errorf("failed to enumerate WTS sessions: %w", err)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
@@ -28,8 +29,6 @@ import (
|
|||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/dimchansky/utfbom"
|
"github.com/dimchansky/utfbom"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
dto "github.com/prometheus/client_model/go"
|
dto "github.com/prometheus/client_model/go"
|
||||||
@@ -97,17 +96,18 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, _ *wmi.Client) error {
|
||||||
_ = level.Info(logger).
|
logger.Info("textfile Collector directories: "+strings.Join(c.config.TextFileDirectories, ","),
|
||||||
Log("msg", "textfile Collector directories: "+strings.Join(c.config.TextFileDirectories, ","), "collector", Name)
|
slog.String("collector", Name),
|
||||||
|
)
|
||||||
|
|
||||||
c.mTimeDesc = prometheus.NewDesc(
|
c.mTimeDesc = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, "textfile", "mtime_seconds"),
|
prometheus.BuildFQName(types.Namespace, "textfile", "mtime_seconds"),
|
||||||
@@ -123,11 +123,14 @@ func (c *Collector) Build(logger log.Logger, _ *wmi.Client) error {
|
|||||||
// Duplicates will be detected where the metric name, labels and label values are identical.
|
// Duplicates will be detected where the metric name, labels and label values are identical.
|
||||||
func duplicateMetricEntry(metricFamilies []*dto.MetricFamily) bool {
|
func duplicateMetricEntry(metricFamilies []*dto.MetricFamily) bool {
|
||||||
uniqueMetrics := make(map[string]map[string]string)
|
uniqueMetrics := make(map[string]map[string]string)
|
||||||
|
|
||||||
for _, metricFamily := range metricFamilies {
|
for _, metricFamily := range metricFamilies {
|
||||||
metricName := metricFamily.GetName()
|
metricName := metricFamily.GetName()
|
||||||
|
|
||||||
for _, metric := range metricFamily.GetMetric() {
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
metricLabels := metric.GetLabel()
|
metricLabels := metric.GetLabel()
|
||||||
labels := make(map[string]string)
|
labels := make(map[string]string)
|
||||||
|
|
||||||
for _, label := range metricLabels {
|
for _, label := range metricLabels {
|
||||||
labels[label.GetName()] = label.GetValue()
|
labels[label.GetName()] = label.GetValue()
|
||||||
}
|
}
|
||||||
@@ -138,17 +141,21 @@ func duplicateMetricEntry(metricFamilies []*dto.MetricFamily) bool {
|
|||||||
if mapContainsKey && reflect.DeepEqual(uniqueMetrics[metricName], labels) {
|
if mapContainsKey && reflect.DeepEqual(uniqueMetrics[metricName], labels) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqueMetrics[metricName] = labels
|
uniqueMetrics[metricName] = labels
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) convertMetricFamily(logger log.Logger, metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric) {
|
func (c *Collector) convertMetricFamily(logger *slog.Logger, metricFamily *dto.MetricFamily, ch chan<- prometheus.Metric) {
|
||||||
var valType prometheus.ValueType
|
var valType prometheus.ValueType
|
||||||
|
|
||||||
var val float64
|
var val float64
|
||||||
|
|
||||||
allLabelNames := map[string]struct{}{}
|
allLabelNames := map[string]struct{}{}
|
||||||
|
|
||||||
for _, metric := range metricFamily.GetMetric() {
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
labels := metric.GetLabel()
|
labels := metric.GetLabel()
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
@@ -160,12 +167,15 @@ func (c *Collector) convertMetricFamily(logger log.Logger, metricFamily *dto.Met
|
|||||||
|
|
||||||
for _, metric := range metricFamily.GetMetric() {
|
for _, metric := range metricFamily.GetMetric() {
|
||||||
if metric.TimestampMs != nil {
|
if metric.TimestampMs != nil {
|
||||||
_ = level.Warn(logger).Log("msg", fmt.Sprintf("Ignoring unsupported custom timestamp on textfile Collector metric %v", metric))
|
logger.Warn(fmt.Sprintf("Ignoring unsupported custom timestamp on textfile Collector metric %v", metric))
|
||||||
}
|
}
|
||||||
|
|
||||||
labels := metric.GetLabel()
|
labels := metric.GetLabel()
|
||||||
|
|
||||||
var names []string
|
var names []string
|
||||||
|
|
||||||
var values []string
|
var values []string
|
||||||
|
|
||||||
for _, label := range labels {
|
for _, label := range labels {
|
||||||
names = append(names, label.GetName())
|
names = append(names, label.GetName())
|
||||||
values = append(values, label.GetValue())
|
values = append(values, label.GetValue())
|
||||||
@@ -173,12 +183,15 @@ func (c *Collector) convertMetricFamily(logger log.Logger, metricFamily *dto.Met
|
|||||||
|
|
||||||
for k := range allLabelNames {
|
for k := range allLabelNames {
|
||||||
present := false
|
present := false
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if k == name {
|
if k == name {
|
||||||
present = true
|
present = true
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !present {
|
if !present {
|
||||||
names = append(names, k)
|
names = append(names, k)
|
||||||
values = append(values, "")
|
values = append(values, "")
|
||||||
@@ -230,9 +243,11 @@ func (c *Collector) convertMetricFamily(logger log.Logger, metricFamily *dto.Met
|
|||||||
buckets, values...,
|
buckets, values...,
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
_ = level.Error(logger).Log("msg", "unknown metric type for file")
|
logger.Error("unknown metric type for file")
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {
|
if metricType == dto.MetricType_GAUGE || metricType == dto.MetricType_COUNTER || metricType == dto.MetricType_UNTYPED {
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
prometheus.NewDesc(
|
prometheus.NewDesc(
|
||||||
@@ -254,6 +269,7 @@ func (c *Collector) exportMTimes(mTimes map[string]time.Time, ch chan<- promethe
|
|||||||
for filename := range mTimes {
|
for filename := range mTimes {
|
||||||
filenames = append(filenames, filename)
|
filenames = append(filenames, filename)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(filenames)
|
sort.Strings(filenames)
|
||||||
|
|
||||||
for _, filename := range filenames {
|
for _, filename := range filenames {
|
||||||
@@ -280,6 +296,7 @@ func (cr carriageReturnFilteringReader) Read(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pi := 0
|
pi := 0
|
||||||
|
|
||||||
for i := range n {
|
for i := range n {
|
||||||
if buf[i] != '\r' {
|
if buf[i] != '\r' {
|
||||||
p[pi] = buf[i]
|
p[pi] = buf[i]
|
||||||
@@ -291,8 +308,8 @@ func (cr carriageReturnFilteringReader) Read(p []byte) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Collect implements the Collector interface.
|
// Collect implements the Collector interface.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
errorMetric := 0.0
|
errorMetric := 0.0
|
||||||
mTimes := map[string]time.Time{}
|
mTimes := map[string]time.Time{}
|
||||||
|
|
||||||
@@ -305,43 +322,68 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<-
|
|||||||
for _, directory := range c.config.TextFileDirectories {
|
for _, directory := range c.config.TextFileDirectories {
|
||||||
err := filepath.WalkDir(directory, func(path string, dirEntry os.DirEntry, err error) error {
|
err := filepath.WalkDir(directory, func(path string, dirEntry os.DirEntry, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "Error reading directory: "+path, "err", err)
|
logger.Error("Error reading directory: "+path,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !dirEntry.IsDir() && strings.HasSuffix(dirEntry.Name(), ".prom") {
|
if !dirEntry.IsDir() && strings.HasSuffix(dirEntry.Name(), ".prom") {
|
||||||
_ = level.Debug(logger).Log("msg", "Processing file: "+path)
|
logger.Debug("Processing file: " + path)
|
||||||
|
|
||||||
families_array, err := scrapeFile(path, logger)
|
families_array, err := scrapeFile(path, logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("Error scraping file: %q. Skip File.", path), "err", err)
|
logger.Error(fmt.Sprintf("Error scraping file: %q. Skip File.", path),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fileInfo, err := os.Stat(path)
|
fileInfo, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("Error reading file info: %q. Skip File.", path), "err", err)
|
logger.Error(fmt.Sprintf("Error reading file info: %q. Skip File.", path),
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, hasName := mTimes[fileInfo.Name()]; hasName {
|
if _, hasName := mTimes[fileInfo.Name()]; hasName {
|
||||||
_ = level.Error(logger).Log("msg", fmt.Sprintf("Duplicate filename detected: %q. Skip File.", path))
|
logger.Error(fmt.Sprintf("Duplicate filename detected: %q. Skip File.", path))
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
mTimes[fileInfo.Name()] = fileInfo.ModTime()
|
mTimes[fileInfo.Name()] = fileInfo.ModTime()
|
||||||
|
|
||||||
metricFamilies = append(metricFamilies, families_array...)
|
metricFamilies = append(metricFamilies, families_array...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil && directory != "" {
|
if err != nil && directory != "" {
|
||||||
_ = level.Error(logger).Log("msg", "Error reading textfile Collector directory: "+directory, "err", err)
|
logger.Error("Error reading textfile Collector directory: "+directory,
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If duplicates are detected across *multiple* files, return error.
|
// If duplicates are detected across *multiple* files, return error.
|
||||||
if duplicateMetricEntry(metricFamilies) {
|
if duplicateMetricEntry(metricFamilies) {
|
||||||
_ = level.Error(logger).Log("msg", "Duplicate metrics detected across multiple files")
|
logger.Error("Duplicate metrics detected across multiple files")
|
||||||
|
|
||||||
errorMetric = 1.0
|
errorMetric = 1.0
|
||||||
} else {
|
} else {
|
||||||
for _, mf := range metricFamilies {
|
for _, mf := range metricFamilies {
|
||||||
@@ -359,24 +401,32 @@ func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<-
|
|||||||
),
|
),
|
||||||
prometheus.GaugeValue, errorMetric,
|
prometheus.GaugeValue, errorMetric,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrapeFile(path string, log log.Logger) ([]*dto.MetricFamily, error) {
|
func scrapeFile(path string, logger *slog.Logger) ([]*dto.MetricFamily, error) {
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var parser expfmt.TextParser
|
var parser expfmt.TextParser
|
||||||
|
|
||||||
r, encoding := utfbom.Skip(carriageReturnFilteringReader{r: file})
|
r, encoding := utfbom.Skip(carriageReturnFilteringReader{r: file})
|
||||||
if err = checkBOM(encoding); err != nil {
|
if err = checkBOM(encoding); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
parsedFamilies, err := parser.TextToMetricFamilies(r)
|
parsedFamilies, err := parser.TextToMetricFamilies(r)
|
||||||
|
|
||||||
closeErr := file.Close()
|
closeErr := file.Close()
|
||||||
if closeErr != nil {
|
if closeErr != nil {
|
||||||
_ = level.Warn(log).Log("msg", fmt.Sprintf("Error closing file %q", path), "err", closeErr)
|
logger.Warn("error closing file "+path,
|
||||||
|
slog.Any("err", closeErr),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -386,11 +436,13 @@ func scrapeFile(path string, log log.Logger) ([]*dto.MetricFamily, error) {
|
|||||||
|
|
||||||
for _, mf := range parsedFamilies {
|
for _, mf := range parsedFamilies {
|
||||||
families_array = append(families_array, mf)
|
families_array = append(families_array, mf)
|
||||||
|
|
||||||
for _, m := range mf.GetMetric() {
|
for _, m := range mf.GetMetric() {
|
||||||
if m.TimestampMs != nil {
|
if m.TimestampMs != nil {
|
||||||
return nil, errors.New("textfile contains unsupported client-side timestamps")
|
return nil, errors.New("textfile contains unsupported client-side timestamps")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if mf.Help == nil {
|
if mf.Help == nil {
|
||||||
help := "Metric read from " + path
|
help := "Metric read from " + path
|
||||||
mf.Help = &help
|
mf.Help = &help
|
||||||
@@ -401,6 +453,7 @@ func scrapeFile(path string, log log.Logger) ([]*dto.MetricFamily, error) {
|
|||||||
if duplicateMetricEntry(families_array) {
|
if duplicateMetricEntry(families_array) {
|
||||||
return nil, errors.New("duplicate metrics detected")
|
return nil, errors.New("duplicate metrics detected")
|
||||||
}
|
}
|
||||||
|
|
||||||
return families_array, nil
|
return families_array, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,5 +467,6 @@ func checkBOM(encoding utfbom.Encoding) error {
|
|||||||
|
|
||||||
func getDefaultPath() string {
|
func getDefaultPath() string {
|
||||||
execPath, _ := os.Executable()
|
execPath, _ := os.Executable()
|
||||||
|
|
||||||
return filepath.Join(filepath.Dir(execPath), "textfile_inputs")
|
return filepath.Join(filepath.Dir(execPath), "textfile_inputs")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ func TestCRFilter(t *testing.T) {
|
|||||||
|
|
||||||
sr := strings.NewReader("line 1\r\nline 2")
|
sr := strings.NewReader("line 1\r\nline 2")
|
||||||
cr := carriageReturnFilteringReader{r: sr}
|
cr := carriageReturnFilteringReader{r: sr}
|
||||||
|
|
||||||
b, err := io.ReadAll(cr)
|
b, err := io.ReadAll(cr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@@ -43,9 +44,11 @@ func TestCheckBOM(t *testing.T) {
|
|||||||
if d.err == "" && err != nil {
|
if d.err == "" && err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.err != "" && err == nil {
|
if d.err != "" && err == nil {
|
||||||
t.Errorf("Missing expected error %s", d.err)
|
t.Errorf("Missing expected error %s", d.err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil && !strings.Contains(err.Error(), d.err) {
|
if err != nil && !strings.Contains(err.Error(), d.err) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package textfile_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/collector/textfile"
|
"github.com/prometheus-community/windows_exporter/pkg/collector/textfile"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -18,7 +18,7 @@ var baseDir = "../../../tools/textfile-test"
|
|||||||
|
|
||||||
//nolint:paralleltest
|
//nolint:paralleltest
|
||||||
func TestMultipleDirectories(t *testing.T) {
|
func TestMultipleDirectories(t *testing.T) {
|
||||||
logger := log.NewLogfmtLogger(os.Stdout)
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||||
testDir := baseDir + "/multiple-dirs"
|
testDir := baseDir + "/multiple-dirs"
|
||||||
testDirs := fmt.Sprintf("%[1]s/dir1,%[1]s/dir2,%[1]s/dir3", testDir)
|
testDirs := fmt.Sprintf("%[1]s/dir1,%[1]s/dir2,%[1]s/dir3", testDir)
|
||||||
|
|
||||||
@@ -33,16 +33,21 @@ func TestMultipleDirectories(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %s", err)
|
t.Errorf("Unexpected error %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := make(chan prometheus.Metric)
|
metrics := make(chan prometheus.Metric)
|
||||||
got := ""
|
got := ""
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
var metric dto.Metric
|
var metric dto.Metric
|
||||||
|
|
||||||
val := <-metrics
|
val := <-metrics
|
||||||
|
|
||||||
err := val.Write(&metric)
|
err := val.Write(&metric)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %s", err)
|
t.Errorf("Unexpected error %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got += metric.String()
|
got += metric.String()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -61,7 +66,7 @@ func TestMultipleDirectories(t *testing.T) {
|
|||||||
|
|
||||||
//nolint:paralleltest
|
//nolint:paralleltest
|
||||||
func TestDuplicateFileName(t *testing.T) {
|
func TestDuplicateFileName(t *testing.T) {
|
||||||
logger := log.NewLogfmtLogger(os.Stdout)
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
||||||
testDir := baseDir + "/duplicate-filename"
|
testDir := baseDir + "/duplicate-filename"
|
||||||
textFileCollector := textfile.New(&textfile.Config{
|
textFileCollector := textfile.New(&textfile.Config{
|
||||||
TextFileDirectories: []string{testDir},
|
TextFileDirectories: []string{testDir},
|
||||||
@@ -74,19 +79,25 @@ func TestDuplicateFileName(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %s", err)
|
t.Errorf("Unexpected error %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics := make(chan prometheus.Metric)
|
metrics := make(chan prometheus.Metric)
|
||||||
got := ""
|
got := ""
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
var metric dto.Metric
|
var metric dto.Metric
|
||||||
|
|
||||||
val := <-metrics
|
val := <-metrics
|
||||||
|
|
||||||
err := val.Write(&metric)
|
err := val.Write(&metric)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %s", err)
|
t.Errorf("Unexpected error %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
got += metric.String()
|
got += metric.String()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = textFileCollector.Collect(scrapeContext, logger, metrics)
|
err = textFileCollector.Collect(scrapeContext, logger, metrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Unexpected error %s", err)
|
t.Errorf("Unexpected error %s", err)
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package thermalzone
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -49,15 +48,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -87,17 +86,22 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
},
|
},
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ch); err != nil {
|
if err := c.collect(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting thermalzone metrics", "err", err)
|
logger.Error("failed collecting thermalzone metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,17 @@ package time
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
"github.com/prometheus-community/windows_exporter/pkg/headers/kernel32"
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/winversion"
|
"github.com/prometheus-community/windows_exporter/pkg/winversion"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Name = "time"
|
const Name = "time"
|
||||||
@@ -25,6 +27,8 @@ var ConfigDefaults = Config{}
|
|||||||
type Collector struct {
|
type Collector struct {
|
||||||
config Config
|
config Config
|
||||||
|
|
||||||
|
currentTime *prometheus.Desc
|
||||||
|
timezone *prometheus.Desc
|
||||||
clockFrequencyAdjustmentPPBTotal *prometheus.Desc
|
clockFrequencyAdjustmentPPBTotal *prometheus.Desc
|
||||||
computedTimeOffset *prometheus.Desc
|
computedTimeOffset *prometheus.Desc
|
||||||
ntpClientTimeSourceCount *prometheus.Desc
|
ntpClientTimeSourceCount *prometheus.Desc
|
||||||
@@ -53,19 +57,31 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{"Windows Time Service"}, nil
|
return []string{"Windows Time Service"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, _ *wmi.Client) error {
|
||||||
if winversion.WindowsVersionFloat() <= 6.1 {
|
if winversion.WindowsVersionFloat() <= 6.1 {
|
||||||
return errors.New("windows version older than Server 2016 detected. The time collector will not run and should be disabled via CLI flags or configuration file")
|
return errors.New("windows version older than Server 2016 detected. The time collector will not run and should be disabled via CLI flags or configuration file")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.currentTime = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "current_timestamp_seconds"),
|
||||||
|
"OperatingSystem.LocalDateTime",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
)
|
||||||
|
c.timezone = prometheus.NewDesc(
|
||||||
|
prometheus.BuildFQName(types.Namespace, Name, "timezone"),
|
||||||
|
"OperatingSystem.LocalDateTime",
|
||||||
|
[]string{"timezone"},
|
||||||
|
nil,
|
||||||
|
)
|
||||||
c.clockFrequencyAdjustmentPPBTotal = prometheus.NewDesc(
|
c.clockFrequencyAdjustmentPPBTotal = prometheus.NewDesc(
|
||||||
prometheus.BuildFQName(types.Namespace, Name, "clock_frequency_adjustment_ppb_total"),
|
prometheus.BuildFQName(types.Namespace, Name, "clock_frequency_adjustment_ppb_total"),
|
||||||
"Total adjustment made to the local system clock frequency by W32Time in Parts Per Billion (PPB) units.",
|
"Total adjustment made to the local system clock frequency by W32Time in Parts Per Billion (PPB) units.",
|
||||||
@@ -102,18 +118,34 @@ func (c *Collector) Build(_ log.Logger, _ *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collect(ctx, logger, ch); err != nil {
|
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting time metrics", "err", err)
|
errs := make([]error, 0, 2)
|
||||||
return err
|
|
||||||
|
if err := c.collectTime(ch); err != nil {
|
||||||
|
logger.Error("failed collecting time metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
if err := c.collectNTP(ctx, logger, ch); err != nil {
|
||||||
|
logger.Error("failed collecting time ntp metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perflib "Windows Time Service".
|
// Perflib "Windows Time Service".
|
||||||
@@ -121,18 +153,49 @@ type windowsTime struct {
|
|||||||
ClockFrequencyAdjustmentPPBTotal float64 `perflib:"Clock Frequency Adjustment (ppb)"`
|
ClockFrequencyAdjustmentPPBTotal float64 `perflib:"Clock Frequency Adjustment (ppb)"`
|
||||||
ComputedTimeOffset float64 `perflib:"Computed Time Offset"`
|
ComputedTimeOffset float64 `perflib:"Computed Time Offset"`
|
||||||
NTPClientTimeSourceCount float64 `perflib:"NTP Client Time Source Count"`
|
NTPClientTimeSourceCount float64 `perflib:"NTP Client Time Source Count"`
|
||||||
NTPRoundtripDelay float64 `perflib:"NTP Roundtrip Delay"`
|
NTPRoundTripDelay float64 `perflib:"NTP Roundtrip Delay"`
|
||||||
NTPServerIncomingRequestsTotal float64 `perflib:"NTP Server Incoming Requests"`
|
NTPServerIncomingRequestsTotal float64 `perflib:"NTP Server Incoming Requests"`
|
||||||
NTPServerOutgoingResponsesTotal float64 `perflib:"NTP Server Outgoing Responses"`
|
NTPServerOutgoingResponsesTotal float64 `perflib:"NTP Server Outgoing Responses"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.currentTime,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
float64(time.Now().Unix()),
|
||||||
|
)
|
||||||
|
|
||||||
|
timeZoneInfo, err := kernel32.GetDynamicTimeZoneInformation()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// timeZoneKeyName contains the english name of the timezone.
|
||||||
|
timezoneName := windows.UTF16ToString(timeZoneInfo.TimeZoneKeyName[:])
|
||||||
|
|
||||||
|
ch <- prometheus.MustNewConstMetric(
|
||||||
|
c.timezone,
|
||||||
|
prometheus.GaugeValue,
|
||||||
|
1.0,
|
||||||
|
timezoneName,
|
||||||
|
)
|
||||||
|
|
||||||
|
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.
|
var dst []windowsTime // Single-instance class, array is required but will have single entry.
|
||||||
|
|
||||||
if err := perflib.UnmarshalObject(ctx.PerfObjects["Windows Time Service"], &dst, logger); err != nil {
|
if err := perflib.UnmarshalObject(ctx.PerfObjects["Windows Time Service"], &dst, logger); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(dst) == 0 {
|
||||||
|
return errors.New("no data returned for Windows Time Service")
|
||||||
|
}
|
||||||
|
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.clockFrequencyAdjustmentPPBTotal,
|
c.clockFrequencyAdjustmentPPBTotal,
|
||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
@@ -151,7 +214,7 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ntpRoundTripDelay,
|
c.ntpRoundTripDelay,
|
||||||
prometheus.GaugeValue,
|
prometheus.GaugeValue,
|
||||||
dst[0].NTPRoundtripDelay/1000000, // microseconds -> seconds
|
dst[0].NTPRoundTripDelay/1000000, // microseconds -> seconds
|
||||||
)
|
)
|
||||||
ch <- prometheus.MustNewConstMetric(
|
ch <- prometheus.MustNewConstMetric(
|
||||||
c.ntpServerIncomingRequestsTotal,
|
c.ntpServerIncomingRequestsTotal,
|
||||||
@@ -163,5 +226,6 @@ func (c *Collector) collect(ctx *types.ScrapeContext, logger log.Logger, ch chan
|
|||||||
prometheus.CounterValue,
|
prometheus.CounterValue,
|
||||||
dst[0].NTPServerOutgoingResponsesTotal,
|
dst[0].NTPServerOutgoingResponsesTotal,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package collector
|
package collector
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Collectors struct {
|
type MetricCollectors struct {
|
||||||
collectors Map
|
Collectors Map
|
||||||
wmiClient *wmi.Client
|
WMIClient *wmi.Client
|
||||||
perfCounterQuery string
|
PerfCounterQuery string
|
||||||
}
|
}
|
||||||
|
|
||||||
type (
|
type (
|
||||||
@@ -21,13 +22,13 @@ type (
|
|||||||
|
|
||||||
// Collector interface that a collector has to implement.
|
// Collector interface that a collector has to implement.
|
||||||
type Collector interface {
|
type Collector interface {
|
||||||
Build(logger log.Logger, wmiClient *wmi.Client) error
|
Build(logger *slog.Logger, wmiClient *wmi.Client) error
|
||||||
// Close closes the collector
|
// Close closes the collector
|
||||||
Close() error
|
Close(logger *slog.Logger) error
|
||||||
// GetName get the name of the collector
|
// GetName get the name of the collector
|
||||||
GetName() string
|
GetName() string
|
||||||
// GetPerfCounter returns the perf counter required by the collector
|
// GetPerfCounter returns the perf counter required by the collector
|
||||||
GetPerfCounter(logger log.Logger) ([]string, error)
|
GetPerfCounter(logger *slog.Logger) ([]string, error)
|
||||||
// Collect Get new metrics and expose them via prometheus registry.
|
// Collect Get new metrics and expose them via prometheus registry.
|
||||||
Collect(ctx *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) (err error)
|
Collect(ctx *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) (err error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package vmware
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
"github.com/prometheus-community/windows_exporter/pkg/perflib"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
@@ -67,15 +66,15 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(_ *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
}
|
}
|
||||||
@@ -197,21 +196,30 @@ func (c *Collector) Build(_ log.Logger, wmiClient *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectMem(ch); err != nil {
|
if err := c.collectMem(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware memory metrics", "err", err)
|
logger.Error("failed collecting vmware memory metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectCpu(ch); err != nil {
|
if err := c.collectCpu(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware cpu metrics", "err", err)
|
logger.Error("failed collecting vmware cpu metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,6 +253,7 @@ func (c *Collector) collectMem(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VMem", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
@@ -333,6 +342,7 @@ func (c *Collector) collectCpu(ch chan<- prometheus.Metric) error {
|
|||||||
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU", &dst); err != nil {
|
if err := c.wmiClient.Query("SELECT * FROM Win32_PerfRawData_vmGuestLib_VCPU", &dst); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst) == 0 {
|
if len(dst) == 0 {
|
||||||
return errors.New("WMI query returned empty result set")
|
return errors.New("WMI query returned empty result set")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ package vmware_blast
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/types"
|
"github.com/prometheus-community/windows_exporter/pkg/types"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/yusufpapurcu/wmi"
|
"github.com/yusufpapurcu/wmi"
|
||||||
@@ -139,17 +138,18 @@ func (c *Collector) GetName() string {
|
|||||||
return Name
|
return Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) GetPerfCounter(_ log.Logger) ([]string, error) {
|
func (c *Collector) GetPerfCounter(_ *slog.Logger) ([]string, error) {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Close() error {
|
func (c *Collector) Close(_ *slog.Logger) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
func (c *Collector) Build(logger *slog.Logger, wmiClient *wmi.Client) error {
|
||||||
_ = level.Warn(logger).
|
logger.Warn("vmware_blast collector is deprecated and will be removed in the future.",
|
||||||
Log("msg", "vmware_blast collector is deprecated and will be removed in the future.", "collector", Name)
|
slog.String("collector", Name),
|
||||||
|
)
|
||||||
|
|
||||||
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
if wmiClient == nil || wmiClient.SWbemServicesClient == nil {
|
||||||
return errors.New("wmiClient or SWbemServicesClient is nil")
|
return errors.New("wmiClient or SWbemServicesClient is nil")
|
||||||
@@ -582,61 +582,110 @@ func (c *Collector) Build(logger log.Logger, wmiClient *wmi.Client) error {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect sends the metric values for each metric
|
// Collect sends the metric values for each metric
|
||||||
// to the provided prometheus Metric channel.
|
// to the provided prometheus Metric channel.
|
||||||
func (c *Collector) Collect(_ *types.ScrapeContext, logger log.Logger, ch chan<- prometheus.Metric) error {
|
func (c *Collector) Collect(_ *types.ScrapeContext, logger *slog.Logger, ch chan<- prometheus.Metric) error {
|
||||||
logger = log.With(logger, "collector", Name)
|
logger = logger.With(slog.String("collector", Name))
|
||||||
if err := c.collectAudio(ch); err != nil {
|
if err := c.collectAudio(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast audio metrics", "err", err)
|
logger.Error("failed collecting vmware blast audio metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectCdr(ch); err != nil {
|
if err := c.collectCdr(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast CDR metrics", "err", err)
|
logger.Error("failed collecting vmware blast CDR metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectClipboard(ch); err != nil {
|
if err := c.collectClipboard(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast clipboard metrics", "err", err)
|
logger.Error("failed collecting vmware blast clipboard metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectHtml5Mmr(ch); err != nil {
|
if err := c.collectHtml5Mmr(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast HTML5 MMR metrics", "err", err)
|
logger.Error("failed collecting vmware blast HTML5 MMR metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectImaging(ch); err != nil {
|
if err := c.collectImaging(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast imaging metrics", "err", err)
|
logger.Error("failed collecting vmware blast imaging metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectRtav(ch); err != nil {
|
if err := c.collectRtav(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast RTAV metrics", "err", err)
|
logger.Error("failed collecting vmware blast RTAV metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectSerialPortandScanner(ch); err != nil {
|
if err := c.collectSerialPortandScanner(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast serial port and scanner metrics", "err", err)
|
logger.Error("failed collecting vmware blast serial port and scanner metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectSession(ch); err != nil {
|
if err := c.collectSession(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast metrics", "err", err)
|
logger.Error("failed collecting vmware blast metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectSkypeforBusinessControl(ch); err != nil {
|
if err := c.collectSkypeforBusinessControl(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast skype for business control metrics", "err", err)
|
logger.Error("failed collecting vmware blast skype for business control metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectThinPrint(ch); err != nil {
|
if err := c.collectThinPrint(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast thin print metrics", "err", err)
|
logger.Error("failed collecting vmware blast thin print metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectUsb(ch); err != nil {
|
if err := c.collectUsb(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast USB metrics", "err", err)
|
logger.Error("failed collecting vmware blast USB metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.collectWindowsMediaMmr(ch); err != nil {
|
if err := c.collectWindowsMediaMmr(ch); err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed collecting vmware blast windows media MMR metrics", "err", err)
|
logger.Error("failed collecting vmware blast windows media MMR metrics",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,16 +14,16 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,9 +37,11 @@ type Resolver struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewResolver returns a Resolver structure.
|
// NewResolver returns a Resolver structure.
|
||||||
func NewResolver(file string, logger log.Logger, insecureSkipVerify bool) (*Resolver, error) {
|
func NewResolver(file string, logger *slog.Logger, insecureSkipVerify bool) (*Resolver, error) {
|
||||||
flags := map[string]string{}
|
flags := map[string]string{}
|
||||||
|
|
||||||
var fileBytes []byte
|
var fileBytes []byte
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if strings.HasPrefix(file, "http://") || strings.HasPrefix(file, "https://") {
|
if strings.HasPrefix(file, "http://") || strings.HasPrefix(file, "https://") {
|
||||||
fileBytes, err = readFromURL(file, logger, insecureSkipVerify)
|
fileBytes, err = readFromURL(file, logger, insecureSkipVerify)
|
||||||
@@ -57,7 +59,7 @@ func NewResolver(file string, logger log.Logger, insecureSkipVerify bool) (*Reso
|
|||||||
|
|
||||||
err = yaml.Unmarshal(fileBytes, &rawValues)
|
err = yaml.Unmarshal(fileBytes, &rawValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to unmarshal configuration file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten nested YAML values
|
// Flatten nested YAML values
|
||||||
@@ -71,35 +73,42 @@ func NewResolver(file string, logger log.Logger, insecureSkipVerify bool) (*Reso
|
|||||||
return &Resolver{flags: flags}, nil
|
return &Resolver{flags: flags}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFromFile(file string, logger log.Logger) ([]byte, error) {
|
func readFromFile(file string, logger *slog.Logger) ([]byte, error) {
|
||||||
_ = level.Info(logger).Log("msg", fmt.Sprintf("Loading configuration file: %v", file))
|
logger.Info("Loading configuration file: " + file)
|
||||||
|
|
||||||
if _, err := os.Stat(file); err != nil {
|
if _, err := os.Stat(file); err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to read configuration file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileBytes, err := os.ReadFile(file)
|
fileBytes, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to read configuration file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileBytes, err
|
return fileBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFromURL(file string, logger log.Logger, insecureSkipVerify bool) ([]byte, error) {
|
func readFromURL(file string, logger *slog.Logger, insecureSkipVerify bool) ([]byte, error) {
|
||||||
_ = level.Info(logger).Log("msg", fmt.Sprintf("Loading configuration file from URL: %v", file))
|
logger.Info("Loading configuration file from URL: " + file)
|
||||||
|
|
||||||
tr := &http.Transport{
|
tr := &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}, //nolint:gosec
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecureSkipVerify}, //nolint:gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
if insecureSkipVerify {
|
if insecureSkipVerify {
|
||||||
_ = level.Warn(logger).Log("msg", "Loading configuration file with TLS verification disabled")
|
logger.Warn("Loading configuration file with TLS verification disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
client := &http.Client{Transport: tr}
|
client := &http.Client{Transport: tr}
|
||||||
|
|
||||||
resp, err := client.Get(file)
|
req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, file, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to create HTTP request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to read configuration file from URL: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
@@ -130,6 +139,7 @@ func (c *Resolver) Bind(app *kingpin.Application, args []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.setDefault(app)
|
c.setDefault(app)
|
||||||
|
|
||||||
if pc.SelectedCommand != nil {
|
if pc.SelectedCommand != nil {
|
||||||
c.setDefault(pc.SelectedCommand)
|
c.setDefault(pc.SelectedCommand)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
// or {"a": {"b":[1,2]}} => {"a.b.0":1, "a.b.1": 2}.
|
// or {"a": {"b":[1,2]}} => {"a.b.0":1, "a.b.1": 2}.
|
||||||
func flatten(data map[string]interface{}) map[string]string {
|
func flatten(data map[string]interface{}) map[string]string {
|
||||||
ret := make(map[string]string)
|
ret := make(map[string]string)
|
||||||
|
|
||||||
for k, v := range data {
|
for k, v := range data {
|
||||||
switch typed := v.(type) {
|
switch typed := v.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
@@ -30,11 +31,13 @@ func flatten(data map[string]interface{}) map[string]string {
|
|||||||
ret[k] = fmt.Sprint(typed)
|
ret[k] = fmt.Sprint(typed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func flattenSlice(data []interface{}) map[string]string {
|
func flattenSlice(data []interface{}) map[string]string {
|
||||||
ret := make(map[string]string)
|
ret := make(map[string]string)
|
||||||
|
|
||||||
for idx, v := range data {
|
for idx, v := range data {
|
||||||
switch typed := v.(type) {
|
switch typed := v.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[interface{}]interface{}:
|
||||||
@@ -53,15 +56,18 @@ func flattenSlice(data []interface{}) map[string]string {
|
|||||||
ret[strconv.Itoa(idx)] = fmt.Sprint(typed)
|
ret[strconv.Itoa(idx)] = fmt.Sprint(typed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertMap(originalMap map[interface{}]interface{}) map[string]interface{} {
|
func convertMap(originalMap map[interface{}]interface{}) map[string]interface{} {
|
||||||
convertedMap := map[string]interface{}{}
|
convertedMap := map[string]interface{}{}
|
||||||
|
|
||||||
for key, value := range originalMap {
|
for key, value := range originalMap {
|
||||||
if keyString, ok := key.(string); ok {
|
if keyString, ok := key.(string); ok {
|
||||||
convertedMap[keyString] = value
|
convertedMap[keyString] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return convertedMap
|
return convertedMap
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ func TestConfigFlattening(t *testing.T) {
|
|||||||
|
|
||||||
log:
|
log:
|
||||||
level: debug`)
|
level: debug`)
|
||||||
|
|
||||||
var data map[string]interface{}
|
var data map[string]interface{}
|
||||||
|
|
||||||
err := yaml.Unmarshal(goodYamlConfig, &data)
|
err := yaml.Unmarshal(goodYamlConfig, &data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
package kernel32
|
package kernel32
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"syscall"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
kernel32 = syscall.NewLazyDLL("kernel32.dll")
|
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
|
||||||
|
|
||||||
procGetDynamicTimeZoneInformationSys = kernel32.NewProc("GetDynamicTimeZoneInformation")
|
procGetDynamicTimeZoneInformationSys = kernel32.NewProc("GetDynamicTimeZoneInformation")
|
||||||
|
kernelLocalFileTimeToFileTime = kernel32.NewProc("LocalFileTimeToFileTime")
|
||||||
)
|
)
|
||||||
|
|
||||||
// SYSTEMTIME contains a date and time.
|
// SYSTEMTIME contains a date and time.
|
||||||
@@ -50,3 +52,11 @@ func GetDynamicTimeZoneInformation() (DynamicTimezoneInformation, error) {
|
|||||||
|
|
||||||
return tzi, nil
|
return tzi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LocalFileTimeToFileTime(localFileTime, utcFileTime *windows.Filetime) uint32 {
|
||||||
|
ret, _, _ := kernelLocalFileTimeToFileTime.Call(
|
||||||
|
uintptr(unsafe.Pointer(localFileTime)),
|
||||||
|
uintptr(unsafe.Pointer(utcFileTime)))
|
||||||
|
|
||||||
|
return uint32(ret)
|
||||||
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ func netApiBufferFree(buffer *wKSTAInfo102) {
|
|||||||
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
|
// https://docs.microsoft.com/en-us/windows/win32/api/lmwksta/nf-lmwksta-netwkstagetinfo
|
||||||
func netWkstaGetInfo() (wKSTAInfo102, uint32, error) {
|
func netWkstaGetInfo() (wKSTAInfo102, uint32, error) {
|
||||||
var lpwi *wKSTAInfo102
|
var lpwi *wKSTAInfo102
|
||||||
|
|
||||||
pLevel := uintptr(102)
|
pLevel := uintptr(102)
|
||||||
|
|
||||||
r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi)))
|
r1, _, _ := procNetWkstaGetInfo.Call(0, pLevel, uintptr(unsafe.Pointer(&lpwi)))
|
||||||
@@ -86,6 +87,7 @@ func netWkstaGetInfo() (wKSTAInfo102, uint32, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deref := *lpwi
|
deref := *lpwi
|
||||||
|
|
||||||
return deref, 0, nil
|
return deref, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,6 +97,7 @@ func GetWorkstationInfo() (WorkstationInfo, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return WorkstationInfo{}, err
|
return WorkstationInfo{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
workstationInfo := WorkstationInfo{
|
workstationInfo := WorkstationInfo{
|
||||||
PlatformId: info.wki102_platform_id,
|
PlatformId: info.wki102_platform_id,
|
||||||
ComputerName: windows.UTF16PtrToString(info.wki102_computername),
|
ComputerName: windows.UTF16PtrToString(info.wki102_computername),
|
||||||
@@ -104,5 +107,6 @@ func GetWorkstationInfo() (WorkstationInfo, error) {
|
|||||||
LanRoot: windows.UTF16PtrToString(info.wki102_lanroot),
|
LanRoot: windows.UTF16PtrToString(info.wki102_lanroot),
|
||||||
LoggedOnUsers: info.wki102_logged_on_users,
|
LoggedOnUsers: info.wki102_logged_on_users,
|
||||||
}
|
}
|
||||||
|
|
||||||
return workstationInfo, nil
|
return workstationInfo, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,9 @@ func GlobalMemoryStatusEx() (MemoryStatus, error) {
|
|||||||
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
|
// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsysteminfo
|
||||||
func GetSystemInfo() SystemInfo {
|
func GetSystemInfo() SystemInfo {
|
||||||
var info lpSystemInfo
|
var info lpSystemInfo
|
||||||
|
|
||||||
procGetSystemInfo.Call(uintptr(unsafe.Pointer(&info))) //nolint:errcheck
|
procGetSystemInfo.Call(uintptr(unsafe.Pointer(&info))) //nolint:errcheck
|
||||||
|
|
||||||
return SystemInfo{
|
return SystemInfo{
|
||||||
Arch: ProcessorArchitecture(info.Arch.WProcessorArchitecture),
|
Arch: ProcessorArchitecture(info.Arch.WProcessorArchitecture),
|
||||||
PageSize: info.DwPageSize,
|
PageSize: info.DwPageSize,
|
||||||
@@ -153,12 +155,16 @@ func GetComputerName(f WinComputerNameFormat) (string, error) {
|
|||||||
// 1kb buffer to accept computer name. This should be more than enough as the maximum size
|
// 1kb buffer to accept computer name. This should be more than enough as the maximum size
|
||||||
// returned is the max length of a DNS name, which this author believes is 253 characters.
|
// returned is the max length of a DNS name, which this author believes is 253 characters.
|
||||||
size := 1024
|
size := 1024
|
||||||
|
|
||||||
var buffer [1024]uint16
|
var buffer [1024]uint16
|
||||||
|
|
||||||
r1, _, err := procGetComputerNameExW.Call(uintptr(f), uintptr(unsafe.Pointer(&buffer)), uintptr(unsafe.Pointer(&size)))
|
r1, _, err := procGetComputerNameExW.Call(uintptr(f), uintptr(unsafe.Pointer(&buffer)), uintptr(unsafe.Pointer(&size)))
|
||||||
if r1 == 0 {
|
if r1 == 0 {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes := buffer[0:size]
|
bytes := buffer[0:size]
|
||||||
out := utf16.Decode(bytes)
|
out := utf16.Decode(bytes)
|
||||||
|
|
||||||
return string(out), nil
|
return string(out), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,9 @@ package wtsapi32
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"syscall"
|
"log/slog"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -105,30 +103,30 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func WTSOpenServer(server string) (syscall.Handle, error) {
|
func WTSOpenServer(server string) (windows.Handle, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
serverName *uint16
|
serverName *uint16
|
||||||
)
|
)
|
||||||
|
|
||||||
if server != "" {
|
if server != "" {
|
||||||
serverName, err = syscall.UTF16PtrFromString(server)
|
serverName, err = windows.UTF16PtrFromString(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return syscall.InvalidHandle, err
|
return windows.InvalidHandle, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r1, _, err := procWTSOpenServerEx.Call(uintptr(unsafe.Pointer(serverName)))
|
r1, _, err := procWTSOpenServerEx.Call(uintptr(unsafe.Pointer(serverName)))
|
||||||
serverHandle := syscall.Handle(r1)
|
serverHandle := windows.Handle(r1)
|
||||||
|
|
||||||
if serverHandle == syscall.InvalidHandle {
|
if serverHandle == windows.InvalidHandle {
|
||||||
return syscall.InvalidHandle, err
|
return windows.InvalidHandle, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return serverHandle, nil
|
return serverHandle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WTSCloseServer(server syscall.Handle) error {
|
func WTSCloseServer(server windows.Handle) error {
|
||||||
r1, _, err := procWTSCloseServer.Call(uintptr(server))
|
r1, _, err := procWTSCloseServer.Call(uintptr(server))
|
||||||
|
|
||||||
if r1 != 1 {
|
if r1 != 1 {
|
||||||
@@ -152,8 +150,9 @@ func WTSFreeMemoryEx(class WTSTypeClass, pMemory uintptr, numberOfEntries uint32
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func WTSEnumerateSessionsEx(server syscall.Handle, logger log.Logger) ([]WTSSession, error) {
|
func WTSEnumerateSessionsEx(server windows.Handle, logger *slog.Logger) ([]WTSSession, error) {
|
||||||
var sessionInfoPointer uintptr
|
var sessionInfoPointer uintptr
|
||||||
|
|
||||||
var count uint32
|
var count uint32
|
||||||
|
|
||||||
pLevel := uint32(1)
|
pLevel := uint32(1)
|
||||||
@@ -173,7 +172,7 @@ func WTSEnumerateSessionsEx(server syscall.Handle, logger log.Logger) ([]WTSSess
|
|||||||
defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) {
|
defer func(class WTSTypeClass, pMemory uintptr, NumberOfEntries uint32) {
|
||||||
err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries)
|
err := WTSFreeMemoryEx(class, pMemory, NumberOfEntries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = level.Error(logger).Log("msg", "failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err))
|
logger.Warn("failed to free memory", "err", fmt.Errorf("WTSEnumerateSessionsEx: %w", err))
|
||||||
}
|
}
|
||||||
}(WTSTypeSessionInfoLevel1, sessionInfoPointer, count)
|
}(WTSTypeSessionInfoLevel1, sessionInfoPointer, count)
|
||||||
}
|
}
|
||||||
@@ -182,6 +181,7 @@ func WTSEnumerateSessionsEx(server syscall.Handle, logger log.Logger) ([]WTSSess
|
|||||||
sessionSize := unsafe.Sizeof(sizeTest)
|
sessionSize := unsafe.Sizeof(sizeTest)
|
||||||
|
|
||||||
sessions := make([]WTSSession, 0, count)
|
sessions := make([]WTSSession, 0, count)
|
||||||
|
|
||||||
for i := range count {
|
for i := range count {
|
||||||
curPtr := unsafe.Pointer(sessionInfoPointer + (uintptr(i) * sessionSize))
|
curPtr := unsafe.Pointer(sessionInfoPointer + (uintptr(i) * sessionSize))
|
||||||
data := (*wtsSessionInfo1)(curPtr)
|
data := (*wtsSessionInfo1)(curPtr)
|
||||||
|
|||||||
19
pkg/httphandler/health.go
Normal file
19
pkg/httphandler/health.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package httphandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HealthHandler struct{}
|
||||||
|
|
||||||
|
// Interface guard.
|
||||||
|
var _ http.Handler = (*HealthHandler)(nil)
|
||||||
|
|
||||||
|
func NewHealthHandler() HealthHandler {
|
||||||
|
return HealthHandler{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h HealthHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
_, _ = w.Write([]byte(`{"status":"ok"}`))
|
||||||
|
}
|
||||||
192
pkg/httphandler/httphandler.go
Normal file
192
pkg/httphandler/httphandler.go
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
package httphandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/collector"
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/collectors/version"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Interface guard.
|
||||||
|
var _ http.Handler = (*MetricsHTTPHandler)(nil)
|
||||||
|
|
||||||
|
const defaultScrapeTimeout = 10.0
|
||||||
|
|
||||||
|
type MetricsHTTPHandler struct {
|
||||||
|
metricCollectors *collector.MetricCollectors
|
||||||
|
// exporterMetricsRegistry is a separate registry for the metrics about
|
||||||
|
// the exporter itself.
|
||||||
|
exporterMetricsRegistry *prometheus.Registry
|
||||||
|
|
||||||
|
logger *slog.Logger
|
||||||
|
options Options
|
||||||
|
concurrencyCh chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
DisableExporterMetrics bool
|
||||||
|
TimeoutMargin float64
|
||||||
|
MaxRequests int
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(logger *slog.Logger, metricCollectors *collector.MetricCollectors, options *Options) *MetricsHTTPHandler {
|
||||||
|
if options == nil {
|
||||||
|
options = &Options{
|
||||||
|
DisableExporterMetrics: false,
|
||||||
|
TimeoutMargin: 0.5,
|
||||||
|
MaxRequests: 5,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := &MetricsHTTPHandler{
|
||||||
|
metricCollectors: metricCollectors,
|
||||||
|
logger: logger,
|
||||||
|
options: *options,
|
||||||
|
concurrencyCh: make(chan struct{}, options.MaxRequests),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !options.DisableExporterMetrics {
|
||||||
|
handler.exporterMetricsRegistry = prometheus.NewRegistry()
|
||||||
|
handler.exporterMetricsRegistry.MustRegister(
|
||||||
|
collectors.NewBuildInfoCollector(),
|
||||||
|
collectors.NewProcessCollector(collectors.ProcessCollectorOpts{}),
|
||||||
|
collectors.NewGoCollector(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MetricsHTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
logger := c.logger.With(
|
||||||
|
slog.Any("remote", r.RemoteAddr),
|
||||||
|
slog.Any("correlation_id", uuid.New().String()),
|
||||||
|
)
|
||||||
|
|
||||||
|
scrapeTimeout := c.getScrapeTimeout(logger, r)
|
||||||
|
|
||||||
|
handler, err := c.handlerFactory(logger, scrapeTimeout, r.URL.Query()["collect[]"])
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("Couldn't create filtered metrics handler",
|
||||||
|
slog.Any("err", err),
|
||||||
|
)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
_, _ = w.Write([]byte(fmt.Sprintf("Couldn't create filtered metrics handler: %s", err)))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MetricsHTTPHandler) getScrapeTimeout(logger *slog.Logger, r *http.Request) time.Duration {
|
||||||
|
var timeoutSeconds float64
|
||||||
|
|
||||||
|
if v := r.Header.Get("X-Prometheus-Scrape-Timeout-Seconds"); v != "" {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
timeoutSeconds, err = strconv.ParseFloat(v, 64)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn(fmt.Sprintf("Couldn't parse X-Prometheus-Scrape-Timeout-Seconds: %q. Defaulting timeout to %f", v, defaultScrapeTimeout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if timeoutSeconds == 0 {
|
||||||
|
timeoutSeconds = defaultScrapeTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutSeconds -= c.options.TimeoutMargin
|
||||||
|
|
||||||
|
return time.Duration(timeoutSeconds) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MetricsHTTPHandler) handlerFactory(logger *slog.Logger, scrapeTimeout time.Duration, requestedCollectors []string) (http.Handler, error) {
|
||||||
|
reg := prometheus.NewRegistry()
|
||||||
|
|
||||||
|
var metricCollectors *collector.MetricCollectors
|
||||||
|
if len(requestedCollectors) == 0 {
|
||||||
|
metricCollectors = c.metricCollectors
|
||||||
|
} else {
|
||||||
|
filteredCollectors := make(collector.Map)
|
||||||
|
|
||||||
|
for _, name := range requestedCollectors {
|
||||||
|
metricCollector, ok := c.metricCollectors.Collectors[name]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("couldn't find collector %s", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredCollectors[name] = metricCollector
|
||||||
|
}
|
||||||
|
|
||||||
|
metricCollectors = &collector.MetricCollectors{
|
||||||
|
Collectors: filteredCollectors,
|
||||||
|
WMIClient: c.metricCollectors.WMIClient,
|
||||||
|
PerfCounterQuery: c.metricCollectors.PerfCounterQuery,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.MustRegister(version.NewCollector("windows_exporter"))
|
||||||
|
|
||||||
|
if err := reg.Register(metricCollectors.NewPrometheusCollector(scrapeTimeout, c.logger)); err != nil {
|
||||||
|
return nil, fmt.Errorf("couldn't register Prometheus collector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var handler http.Handler
|
||||||
|
if c.exporterMetricsRegistry != nil {
|
||||||
|
handler = promhttp.HandlerFor(
|
||||||
|
prometheus.Gatherers{c.exporterMetricsRegistry, reg},
|
||||||
|
promhttp.HandlerOpts{
|
||||||
|
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
||||||
|
ErrorHandling: promhttp.ContinueOnError,
|
||||||
|
MaxRequestsInFlight: c.options.MaxRequests,
|
||||||
|
Registry: c.exporterMetricsRegistry,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
// Note that we have to use h.exporterMetricsRegistry here to
|
||||||
|
// use the same promhttp metrics for all expositions.
|
||||||
|
handler = promhttp.InstrumentMetricHandler(
|
||||||
|
c.exporterMetricsRegistry, handler,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
handler = promhttp.HandlerFor(
|
||||||
|
reg,
|
||||||
|
promhttp.HandlerOpts{
|
||||||
|
ErrorLog: slog.NewLogLogger(logger.Handler(), slog.LevelError),
|
||||||
|
ErrorHandling: promhttp.ContinueOnError,
|
||||||
|
MaxRequestsInFlight: c.options.MaxRequests,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.withConcurrencyLimit(handler.ServeHTTP), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *MetricsHTTPHandler) withConcurrencyLimit(next http.HandlerFunc) http.HandlerFunc {
|
||||||
|
if c.options.MaxRequests <= 0 {
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
select {
|
||||||
|
case c.concurrencyCh <- struct{}{}:
|
||||||
|
defer func() { <-c.concurrencyCh }()
|
||||||
|
default:
|
||||||
|
w.WriteHeader(http.StatusServiceUnavailable)
|
||||||
|
_, _ = w.Write([]byte("Too many concurrent requests"))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
next(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
45
pkg/httphandler/version.go
Normal file
45
pkg/httphandler/version.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package httphandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/common/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
type VersionHandler struct{}
|
||||||
|
|
||||||
|
// Same struct prometheus uses for their /version endpoint.
|
||||||
|
// Separate copy to avoid pulling all of prometheus as a dependency.
|
||||||
|
type prometheusVersion struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Revision string `json:"revision"`
|
||||||
|
Branch string `json:"branch"`
|
||||||
|
BuildUser string `json:"buildUser"`
|
||||||
|
BuildDate string `json:"buildDate"`
|
||||||
|
GoVersion string `json:"goVersion"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interface guard.
|
||||||
|
var _ http.Handler = (*VersionHandler)(nil)
|
||||||
|
|
||||||
|
func NewVersionHandler() VersionHandler {
|
||||||
|
return VersionHandler{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h VersionHandler) ServeHTTP(w http.ResponseWriter, _ *http.Request) {
|
||||||
|
// we can't use "version" directly as it is a package, and not an object that
|
||||||
|
// can be serialized.
|
||||||
|
err := json.NewEncoder(w).Encode(prometheusVersion{
|
||||||
|
Version: version.Version,
|
||||||
|
Revision: version.Revision,
|
||||||
|
Branch: version.Branch,
|
||||||
|
BuildUser: version.BuildUser,
|
||||||
|
BuildDate: version.BuildDate,
|
||||||
|
GoVersion: version.GoVersion,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, fmt.Sprintf("error encoding JSON: %s", err), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,7 +50,9 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = logger.Error(102, fmt.Sprintf("Failed to detect service: %v", err))
|
_ = logger.Error(102, fmt.Sprintf("Failed to detect service: %v", err))
|
||||||
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +61,9 @@ func init() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = logger.Info(100, "Attempting to start exporter service")
|
_ = logger.Info(100, "Attempting to start exporter service")
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
err = svc.Run(serviceName, &windowsExporterService{})
|
err = svc.Run(serviceName, &windowsExporterService{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
//go:build windows
|
//go:build windows
|
||||||
// +build windows
|
|
||||||
|
|
||||||
// Package eventlog provides a Logger that writes to Windows Event Log.
|
// Package eventlog provides a Logger that writes to Windows Event Log.
|
||||||
package eventlog
|
package eventlog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
|
||||||
"syscall"
|
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/go-kit/log/level"
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
goeventlog "golang.org/x/sys/windows/svc/eventlog"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -25,109 +18,36 @@ const (
|
|||||||
neLogOemCode = uint32(3299)
|
neLogOemCode = uint32(3299)
|
||||||
)
|
)
|
||||||
|
|
||||||
type Priority struct {
|
// Interface guard.
|
||||||
etype int
|
var _ io.Writer = (*Writer)(nil)
|
||||||
|
|
||||||
|
type Writer struct {
|
||||||
|
handle windows.Handle
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEventLogLogger returns a new Logger which writes to Windows EventLog in event log format.
|
// NewEventLogWriter returns a new Writer which writes to Windows EventLog.
|
||||||
// The body of the log message is the formatted output from the Logger returned
|
func NewEventLogWriter(handle windows.Handle) *Writer {
|
||||||
// by newLogger.
|
return &Writer{handle: handle}
|
||||||
func NewEventLogLogger(w *goeventlog.Log, newLogger func(io.Writer) log.Logger) log.Logger {
|
}
|
||||||
l := &eventlogLogger{
|
|
||||||
w: w,
|
func (w *Writer) Write(p []byte) (int, error) {
|
||||||
newLogger: newLogger,
|
var eType uint16
|
||||||
prioritySelector: defaultPrioritySelector,
|
|
||||||
bufPool: sync.Pool{New: func() interface{} {
|
switch {
|
||||||
return &loggerBuf{}
|
case bytes.Contains(p, []byte(" level=error")) || bytes.Contains(p, []byte(`"level":"error"`)):
|
||||||
}},
|
eType = windows.EVENTLOG_ERROR_TYPE
|
||||||
|
case bytes.Contains(p, []byte(" level=warn")) || bytes.Contains(p, []byte(`"level":"warn"`)):
|
||||||
|
eType = windows.EVENTLOG_WARNING_TYPE
|
||||||
|
default:
|
||||||
|
eType = windows.EVENTLOG_INFORMATION_TYPE
|
||||||
}
|
}
|
||||||
|
|
||||||
return l
|
msg, err := windows.UTF16PtrFromString(string(p))
|
||||||
}
|
|
||||||
|
|
||||||
type eventlogLogger struct {
|
|
||||||
w *goeventlog.Log
|
|
||||||
newLogger func(io.Writer) log.Logger
|
|
||||||
prioritySelector PrioritySelector
|
|
||||||
bufPool sync.Pool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *eventlogLogger) Log(keyvals ...interface{}) error {
|
|
||||||
priority := l.prioritySelector(keyvals...)
|
|
||||||
|
|
||||||
lb, err := l.getLoggerBuf()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return 0, fmt.Errorf("error convert string to UTF-16: %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
defer l.putLoggerBuf(lb)
|
|
||||||
if err := lb.logger.Log(keyvals...); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// golang.org/x/sys/windows/svc/eventlog does not provide func which allows to send more than one string.
|
|
||||||
// See: https://github.com/golang/go/issues/59780
|
|
||||||
|
|
||||||
msg, err := syscall.UTF16PtrFromString(lb.buf.String())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error convert string to UTF-16: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ss := []*uint16{msg, nil, nil, nil, nil, nil, nil, nil, nil}
|
ss := []*uint16{msg, nil, nil, nil, nil, nil, nil, nil, nil}
|
||||||
return windows.ReportEvent(l.w.Handle, uint16(priority.etype), 0, neLogOemCode, 0, 9, 0, &ss[0], nil)
|
|
||||||
}
|
return len(p), windows.ReportEvent(w.handle, eType, 0, neLogOemCode, 0, 9, 0, &ss[0], nil)
|
||||||
|
|
||||||
type loggerBuf struct {
|
|
||||||
buf *bytes.Buffer
|
|
||||||
logger log.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *eventlogLogger) getLoggerBuf() (*loggerBuf, error) {
|
|
||||||
lb, ok := l.bufPool.Get().(*loggerBuf)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("failed to get loggerBuf from pool")
|
|
||||||
}
|
|
||||||
|
|
||||||
if lb.buf == nil {
|
|
||||||
lb.buf = &bytes.Buffer{}
|
|
||||||
lb.logger = l.newLogger(lb.buf)
|
|
||||||
} else {
|
|
||||||
lb.buf.Reset()
|
|
||||||
}
|
|
||||||
return lb, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *eventlogLogger) putLoggerBuf(lb *loggerBuf) {
|
|
||||||
l.bufPool.Put(lb)
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrioritySelector inspects the list of keyvals and selects an eventlog priority.
|
|
||||||
type PrioritySelector func(keyvals ...interface{}) Priority
|
|
||||||
|
|
||||||
// defaultPrioritySelector convert a kit/log level into a Windows Eventlog level.
|
|
||||||
func defaultPrioritySelector(keyvals ...interface{}) Priority {
|
|
||||||
l := len(keyvals)
|
|
||||||
|
|
||||||
eType := windows.EVENTLOG_SUCCESS
|
|
||||||
|
|
||||||
for i := 0; i < l; i += 2 {
|
|
||||||
if keyvals[i] == level.Key() {
|
|
||||||
var val interface{}
|
|
||||||
if i+1 < l {
|
|
||||||
val = keyvals[i+1]
|
|
||||||
}
|
|
||||||
if v, ok := val.(level.Value); ok {
|
|
||||||
switch v {
|
|
||||||
case level.ErrorValue():
|
|
||||||
eType = windows.EVENTLOG_ERROR_TYPE
|
|
||||||
case level.WarnValue():
|
|
||||||
eType = windows.EVENTLOG_WARNING_TYPE
|
|
||||||
case level.InfoValue():
|
|
||||||
eType = windows.EVENTLOG_INFORMATION_TYPE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Priority{etype: eType}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ package flag
|
|||||||
import (
|
import (
|
||||||
"github.com/alecthomas/kingpin/v2"
|
"github.com/alecthomas/kingpin/v2"
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/log"
|
"github.com/prometheus-community/windows_exporter/pkg/log"
|
||||||
"github.com/prometheus/common/promlog"
|
"github.com/prometheus/common/promslog"
|
||||||
promlogflag "github.com/prometheus/common/promlog/flag"
|
"github.com/prometheus/common/promslog/flag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileFlagName is the canonical flag name to configure the log file.
|
// FileFlagName is the canonical flag name to configure the log file.
|
||||||
@@ -29,15 +29,9 @@ const FileFlagHelp = "Output file of log messages. One of [stdout, stderr, event
|
|||||||
// AddFlags adds the flags used by this package to the Kingpin application.
|
// AddFlags adds the flags used by this package to the Kingpin application.
|
||||||
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine).
|
// To use the default Kingpin application, call AddFlags(kingpin.CommandLine).
|
||||||
func AddFlags(a *kingpin.Application, config *log.Config) {
|
func AddFlags(a *kingpin.Application, config *log.Config) {
|
||||||
config.Level = &promlog.AllowedLevel{}
|
config.Config = new(promslog.Config)
|
||||||
a.Flag(promlogflag.LevelFlagName, promlogflag.LevelFlagHelp).
|
flag.AddFlags(a, config.Config)
|
||||||
Default("info").SetValue(config.Level)
|
|
||||||
|
|
||||||
config.File = &log.AllowedFile{}
|
config.File = &log.AllowedFile{}
|
||||||
a.Flag(FileFlagName, FileFlagHelp).
|
a.Flag(FileFlagName, FileFlagHelp).Default("stderr").SetValue(config.File)
|
||||||
Default("stderr").SetValue(config.File)
|
|
||||||
|
|
||||||
config.Format = &promlog.AllowedFormat{}
|
|
||||||
a.Flag(promlogflag.FormatFlagName, promlogflag.FormatFlagHelp).
|
|
||||||
Default("logfmt").SetValue(config.Format)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/go-kit/log"
|
|
||||||
"github.com/prometheus-community/windows_exporter/pkg/log/eventlog"
|
"github.com/prometheus-community/windows_exporter/pkg/log/eventlog"
|
||||||
"github.com/prometheus/common/promlog"
|
"github.com/prometheus/common/promslog"
|
||||||
goeventlog "golang.org/x/sys/windows/svc/eventlog"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AllowedFile is a settable identifier for the output file that the logger can have.
|
// AllowedFile is a settable identifier for the output file that the logger can have.
|
||||||
@@ -25,71 +25,45 @@ func (f *AllowedFile) String() string {
|
|||||||
// Set updates the value of the allowed format.
|
// Set updates the value of the allowed format.
|
||||||
func (f *AllowedFile) Set(s string) error {
|
func (f *AllowedFile) Set(s string) error {
|
||||||
f.s = s
|
f.s = s
|
||||||
|
|
||||||
switch s {
|
switch s {
|
||||||
case "stdout":
|
case "stdout":
|
||||||
f.w = os.Stdout
|
f.w = os.Stdout
|
||||||
case "stderr":
|
case "stderr":
|
||||||
f.w = os.Stderr
|
f.w = os.Stderr
|
||||||
case "eventlog":
|
case "eventlog":
|
||||||
f.w = nil
|
handle, err := windows.RegisterEventSource(nil, windows.StringToUTF16Ptr("windows_exporter"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to open event log: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f.w = eventlog.NewEventLogWriter(handle)
|
||||||
default:
|
default:
|
||||||
file, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o200)
|
file, err := os.OpenFile(s, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0o200)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to open log file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
f.w = file
|
f.w = file
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is a struct containing configurable settings for the logger.
|
// Config is a struct containing configurable settings for the logger.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
promlog.Config
|
*promslog.Config
|
||||||
|
|
||||||
File *AllowedFile
|
File *AllowedFile
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config *Config) (log.Logger, error) {
|
func New(config *Config) (*slog.Logger, error) {
|
||||||
if config.File == nil {
|
if config.File == nil {
|
||||||
return nil, errors.New("log file undefined")
|
return nil, errors.New("log file undefined")
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Format == nil {
|
config.Config.Writer = config.File.w
|
||||||
return nil, errors.New("log format undefined")
|
config.Config.Style = promslog.GoKitStyle
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
return promslog.New(config.Config), nil
|
||||||
l log.Logger
|
|
||||||
loggerFunc func(io.Writer) log.Logger
|
|
||||||
)
|
|
||||||
|
|
||||||
switch config.Format.String() {
|
|
||||||
case "json":
|
|
||||||
loggerFunc = log.NewJSONLogger
|
|
||||||
case "logfmt":
|
|
||||||
loggerFunc = log.NewLogfmtLogger
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported log.format %q", config.Format.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case config.File.s == "eventlog":
|
|
||||||
|
|
||||||
w, err := goeventlog.Open("windows_exporter")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
l = eventlog.NewEventLogLogger(w, loggerFunc)
|
|
||||||
case config.File.w == nil:
|
|
||||||
panic("logger: file writer is nil")
|
|
||||||
default:
|
|
||||||
l = loggerFunc(log.NewSyncWriter(config.File.w))
|
|
||||||
}
|
|
||||||
|
|
||||||
promlogConfig := promlog.Config{
|
|
||||||
Format: config.Format,
|
|
||||||
Level: config.Level,
|
|
||||||
}
|
|
||||||
|
|
||||||
return promlog.NewWithLogger(l, &promlogConfig), nil
|
|
||||||
}
|
}
|
||||||
|
|||||||
236
pkg/perfdata/collector.go
Normal file
236
pkg/perfdata/collector.go
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
)
|
||||||
|
|
||||||
|
const EmptyInstance = "------"
|
||||||
|
|
||||||
|
type Collector struct {
|
||||||
|
time time.Time
|
||||||
|
object string
|
||||||
|
counters []Counter
|
||||||
|
handle pdhQueryHandle
|
||||||
|
}
|
||||||
|
|
||||||
|
type Counter struct {
|
||||||
|
Name string
|
||||||
|
Instances map[string]pdhCounterHandle
|
||||||
|
Type uint32
|
||||||
|
Frequency float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type CounterValues struct {
|
||||||
|
Type prometheus.ValueType
|
||||||
|
FirstValue float64
|
||||||
|
SecondValue float64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCollector(object string, instances []string, counters []string) (*Collector, error) {
|
||||||
|
var handle pdhQueryHandle
|
||||||
|
|
||||||
|
if ret := PdhOpenQuery(0, 0, &handle); ret != ErrorSuccess {
|
||||||
|
return nil, NewPdhError(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(instances) == 0 {
|
||||||
|
instances = []string{EmptyInstance}
|
||||||
|
}
|
||||||
|
|
||||||
|
collector := &Collector{
|
||||||
|
object: object,
|
||||||
|
counters: make([]Counter, 0, len(counters)),
|
||||||
|
handle: handle,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, counterName := range counters {
|
||||||
|
if counterName == "*" {
|
||||||
|
return nil, errors.New("wildcard counters are not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
counter := Counter{
|
||||||
|
Name: counterName,
|
||||||
|
Instances: make(map[string]pdhCounterHandle, len(instances)),
|
||||||
|
}
|
||||||
|
|
||||||
|
var counterPath string
|
||||||
|
|
||||||
|
for _, instance := range instances {
|
||||||
|
counterPath = formatCounterPath(object, instance, counterName)
|
||||||
|
|
||||||
|
var counterHandle pdhCounterHandle
|
||||||
|
|
||||||
|
if ret := PdhAddEnglishCounter(handle, counterPath, 0, &counterHandle); ret != ErrorSuccess {
|
||||||
|
return nil, fmt.Errorf("failed to add counter %s: %w", counterPath, NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
counter.Instances[instance] = counterHandle
|
||||||
|
|
||||||
|
if counter.Type == 0 {
|
||||||
|
// Get the info with the current buffer size
|
||||||
|
bufLen := uint32(0)
|
||||||
|
|
||||||
|
if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, nil); ret != PdhMoreData {
|
||||||
|
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, bufLen)
|
||||||
|
if ret := PdhGetCounterInfo(counterHandle, 0, &bufLen, &buf[0]); ret != ErrorSuccess {
|
||||||
|
return nil, fmt.Errorf("PdhGetCounterInfo: %w", NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
ci := (*PdhCounterInfo)(unsafe.Pointer(&buf[0]))
|
||||||
|
counter.Type = ci.DwType
|
||||||
|
|
||||||
|
frequency := float64(0)
|
||||||
|
|
||||||
|
if ret := PdhGetCounterTimeBase(counterHandle, &frequency); ret != ErrorSuccess {
|
||||||
|
return nil, fmt.Errorf("PdhGetCounterTimeBase: %w", NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
counter.Frequency = frequency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collector.counters = append(collector.counters, counter)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(collector.counters) == 0 {
|
||||||
|
return nil, errors.New("no counters configured")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := collector.Collect(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to collect initial data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return collector, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) Collect() (map[string]map[string]CounterValues, error) {
|
||||||
|
if len(c.counters) == 0 {
|
||||||
|
return map[string]map[string]CounterValues{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if ret := PdhCollectQueryData(c.handle); ret != ErrorSuccess {
|
||||||
|
return nil, fmt.Errorf("failed to collect query data: %w", NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
c.time = time.Now()
|
||||||
|
|
||||||
|
var data map[string]map[string]CounterValues
|
||||||
|
|
||||||
|
for _, counter := range c.counters {
|
||||||
|
for _, instance := range counter.Instances {
|
||||||
|
// Get the info with the current buffer size
|
||||||
|
var itemCount uint32
|
||||||
|
|
||||||
|
// Get the info with the current buffer size
|
||||||
|
bufLen := uint32(0)
|
||||||
|
|
||||||
|
ret := PdhGetRawCounterArray(instance, &bufLen, &itemCount, nil)
|
||||||
|
if ret != PdhMoreData {
|
||||||
|
return nil, fmt.Errorf("PdhGetRawCounterArray: %w", NewPdhError(ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := make([]byte, bufLen)
|
||||||
|
|
||||||
|
ret = PdhGetRawCounterArray(instance, &bufLen, &itemCount, &buf[0])
|
||||||
|
if ret != ErrorSuccess {
|
||||||
|
if err := NewPdhError(ret); !isKnownCounterDataError(err) {
|
||||||
|
return nil, fmt.Errorf("PdhGetRawCounterArray: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
items := (*[1 << 20]PdhRawCounterItem)(unsafe.Pointer(&buf[0]))[:itemCount]
|
||||||
|
|
||||||
|
if data == nil {
|
||||||
|
data = make(map[string]map[string]CounterValues, itemCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
var metricType prometheus.ValueType
|
||||||
|
if val, ok := supportedCounterTypes[counter.Type]; ok {
|
||||||
|
metricType = val
|
||||||
|
} else {
|
||||||
|
metricType = prometheus.GaugeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range items {
|
||||||
|
if item.RawValue.CStatus == PdhCstatusValidData || item.RawValue.CStatus == PdhCstatusNewData {
|
||||||
|
instanceName := windows.UTF16PtrToString(item.SzName)
|
||||||
|
if strings.HasSuffix(instanceName, "_Total") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if instanceName == "" {
|
||||||
|
instanceName = EmptyInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := data[instanceName]; !ok {
|
||||||
|
data[instanceName] = make(map[string]CounterValues, len(c.counters))
|
||||||
|
}
|
||||||
|
|
||||||
|
values := CounterValues{
|
||||||
|
Type: metricType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a workaround for the issue with the elapsed time counter type.
|
||||||
|
// Source: https://github.com/prometheus-community/windows_exporter/pull/335/files#diff-d5d2528f559ba2648c2866aec34b1eaa5c094dedb52bd0ff22aa5eb83226bd8dR76-R83
|
||||||
|
|
||||||
|
switch counter.Type {
|
||||||
|
case PERF_ELAPSED_TIME:
|
||||||
|
values.FirstValue = float64(item.RawValue.FirstValue-WindowsEpoch) / counter.Frequency
|
||||||
|
values.SecondValue = float64(item.RawValue.SecondValue-WindowsEpoch) / counter.Frequency
|
||||||
|
case PERF_100NSEC_TIMER, PERF_PRECISION_100NS_TIMER:
|
||||||
|
values.FirstValue = float64(item.RawValue.FirstValue) * TicksToSecondScaleFactor
|
||||||
|
values.SecondValue = float64(item.RawValue.SecondValue) * TicksToSecondScaleFactor
|
||||||
|
default:
|
||||||
|
values.FirstValue = float64(item.RawValue.FirstValue)
|
||||||
|
values.SecondValue = float64(item.RawValue.SecondValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
data[instanceName][counter.Name] = values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Collector) Close() {
|
||||||
|
PdhCloseQuery(c.handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatCounterPath(object, instance, counterName string) string {
|
||||||
|
var counterPath string
|
||||||
|
|
||||||
|
if instance == EmptyInstance {
|
||||||
|
counterPath = fmt.Sprintf(`\%s\%s`, object, counterName)
|
||||||
|
} else {
|
||||||
|
counterPath = fmt.Sprintf(`\%s(%s)\%s`, object, instance, counterName)
|
||||||
|
}
|
||||||
|
|
||||||
|
return counterPath
|
||||||
|
}
|
||||||
|
|
||||||
|
func isKnownCounterDataError(err error) bool {
|
||||||
|
var pdhErr *Error
|
||||||
|
|
||||||
|
return errors.As(err, &pdhErr) && (pdhErr.ErrorCode == PdhInvalidData ||
|
||||||
|
pdhErr.ErrorCode == PdhCalcNegativeDenominator ||
|
||||||
|
pdhErr.ErrorCode == PdhCalcNegativeValue ||
|
||||||
|
pdhErr.ErrorCode == PdhCstatusInvalidData ||
|
||||||
|
pdhErr.ErrorCode == PdhCstatusNoInstance ||
|
||||||
|
pdhErr.ErrorCode == PdhNoData)
|
||||||
|
}
|
||||||
49
pkg/perfdata/collector_bench_test.go
Normal file
49
pkg/perfdata/collector_bench_test.go
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package perfdata_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func BenchmarkTestCollector(b *testing.B) {
|
||||||
|
counters := []string{
|
||||||
|
"% Processor Time",
|
||||||
|
"% Privileged Time",
|
||||||
|
"% User Time",
|
||||||
|
"Creating Process ID",
|
||||||
|
"Elapsed Time",
|
||||||
|
"Handle Count",
|
||||||
|
"ID Process",
|
||||||
|
"IO Data Bytes/sec",
|
||||||
|
"IO Data Operations/sec",
|
||||||
|
"IO Other Bytes/sec",
|
||||||
|
"IO Other Operations/sec",
|
||||||
|
"IO Read Bytes/sec",
|
||||||
|
"IO Read Operations/sec",
|
||||||
|
"IO Write Bytes/sec",
|
||||||
|
"IO Write Operations/sec",
|
||||||
|
"Page Faults/sec",
|
||||||
|
"Page File Bytes Peak",
|
||||||
|
"Page File Bytes",
|
||||||
|
"Pool Nonpaged Bytes",
|
||||||
|
"Pool Paged Bytes",
|
||||||
|
"Priority Base",
|
||||||
|
"Private Bytes",
|
||||||
|
"Thread Count",
|
||||||
|
"Virtual Bytes Peak",
|
||||||
|
"Virtual Bytes",
|
||||||
|
"Working Set - Private",
|
||||||
|
"Working Set Peak",
|
||||||
|
"Working Set",
|
||||||
|
}
|
||||||
|
performanceData, err := perfdata.NewCollector("Process", []string{"*"}, counters)
|
||||||
|
require.NoError(b, err)
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, _ = performanceData.Collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
performanceData.Close()
|
||||||
|
}
|
||||||
86
pkg/perfdata/collector_test.go
Normal file
86
pkg/perfdata/collector_test.go
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus-community/windows_exporter/pkg/perfdata"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCollector(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
for _, tc := range []struct {
|
||||||
|
object string
|
||||||
|
instances []string
|
||||||
|
counters []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
object: "Memory",
|
||||||
|
counters: []string{
|
||||||
|
"Available Bytes",
|
||||||
|
"Available KBytes",
|
||||||
|
"Available MBytes",
|
||||||
|
"Cache Bytes",
|
||||||
|
"Cache Bytes Peak",
|
||||||
|
"Cache Faults/sec",
|
||||||
|
"Commit Limit",
|
||||||
|
"Committed Bytes",
|
||||||
|
"Demand Zero Faults/sec",
|
||||||
|
"Free & Zero Page List Bytes",
|
||||||
|
"Free System Page Table Entries",
|
||||||
|
"Modified Page List Bytes",
|
||||||
|
"Page Reads/sec",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
object: "TCPv4",
|
||||||
|
counters: []string{
|
||||||
|
"Connection Failures",
|
||||||
|
"Connections Active",
|
||||||
|
"Connections Established",
|
||||||
|
"Connections Passive",
|
||||||
|
"Connections Reset",
|
||||||
|
"Segments/sec",
|
||||||
|
"Segments Received/sec",
|
||||||
|
"Segments Retransmitted/sec",
|
||||||
|
"Segments Sent/sec",
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
object: "Process",
|
||||||
|
instances: []string{"*"},
|
||||||
|
counters: []string{
|
||||||
|
"Thread Count",
|
||||||
|
"ID Process",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.object, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
performanceData, err := perfdata.NewCollector(tc.object, tc.instances, tc.counters)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
||||||
|
data, err := performanceData.Collect()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, data)
|
||||||
|
|
||||||
|
for instance, d := range data {
|
||||||
|
require.NotEmpty(t, d)
|
||||||
|
|
||||||
|
if instance == "Idle" || instance == "Secure System" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range tc.counters {
|
||||||
|
assert.NotZerof(t, d[c].FirstValue, "object: %s, instance: %s, counter: %s", tc.object, instance, c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
78
pkg/perfdata/const.go
Normal file
78
pkg/perfdata/const.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package perfdata
|
||||||
|
|
||||||
|
import "github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
|
// Conversion factors.
|
||||||
|
const (
|
||||||
|
TicksToSecondScaleFactor = 1 / 1e7
|
||||||
|
WindowsEpoch = 116444736000000000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Based on https://github.com/leoluk/perflib_exporter/blob/master/collector/mapper.go
|
||||||
|
//
|
||||||
|
//goland:noinspection GoUnusedConst
|
||||||
|
const (
|
||||||
|
PERF_COUNTER_RAWCOUNT_HEX = 0x00000000
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT_HEX = 0x00000100
|
||||||
|
PERF_COUNTER_TEXT = 0x00000b00
|
||||||
|
PERF_COUNTER_RAWCOUNT = 0x00010000
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT = 0x00010100
|
||||||
|
PERF_DOUBLE_RAW = 0x00012000
|
||||||
|
PERF_COUNTER_DELTA = 0x00400400
|
||||||
|
PERF_COUNTER_LARGE_DELTA = 0x00400500
|
||||||
|
PERF_SAMPLE_COUNTER = 0x00410400
|
||||||
|
PERF_COUNTER_QUEUELEN_TYPE = 0x00450400
|
||||||
|
PERF_COUNTER_LARGE_QUEUELEN_TYPE = 0x00450500
|
||||||
|
PERF_COUNTER_100NS_QUEUELEN_TYPE = 0x00550500
|
||||||
|
PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE = 0x00650500
|
||||||
|
PERF_COUNTER_COUNTER = 0x10410400
|
||||||
|
PERF_COUNTER_BULK_COUNT = 0x10410500
|
||||||
|
PERF_RAW_FRACTION = 0x20020400
|
||||||
|
PERF_LARGE_RAW_FRACTION = 0x20020500
|
||||||
|
PERF_COUNTER_TIMER = 0x20410500
|
||||||
|
PERF_PRECISION_SYSTEM_TIMER = 0x20470500
|
||||||
|
PERF_100NSEC_TIMER = 0x20510500
|
||||||
|
PERF_PRECISION_100NS_TIMER = 0x20570500
|
||||||
|
PERF_OBJ_TIME_TIMER = 0x20610500
|
||||||
|
PERF_PRECISION_OBJECT_TIMER = 0x20670500
|
||||||
|
PERF_SAMPLE_FRACTION = 0x20c20400
|
||||||
|
PERF_COUNTER_TIMER_INV = 0x21410500
|
||||||
|
PERF_100NSEC_TIMER_INV = 0x21510500
|
||||||
|
PERF_COUNTER_MULTI_TIMER = 0x22410500
|
||||||
|
PERF_100NSEC_MULTI_TIMER = 0x22510500
|
||||||
|
PERF_COUNTER_MULTI_TIMER_INV = 0x23410500
|
||||||
|
PERF_100NSEC_MULTI_TIMER_INV = 0x23510500
|
||||||
|
PERF_AVERAGE_TIMER = 0x30020400
|
||||||
|
PERF_ELAPSED_TIME = 0x30240500
|
||||||
|
PERF_COUNTER_NODATA = 0x40000200
|
||||||
|
PERF_AVERAGE_BULK = 0x40020500
|
||||||
|
PERF_SAMPLE_BASE = 0x40030401
|
||||||
|
PERF_AVERAGE_BASE = 0x40030402
|
||||||
|
PERF_RAW_BASE = 0x40030403
|
||||||
|
PERF_PRECISION_TIMESTAMP = 0x40030500
|
||||||
|
PERF_LARGE_RAW_BASE = 0x40030503
|
||||||
|
PERF_COUNTER_MULTI_BASE = 0x42030500
|
||||||
|
PERF_COUNTER_HISTOGRAM_TYPE = 0x80000000
|
||||||
|
)
|
||||||
|
|
||||||
|
var supportedCounterTypes = map[uint32]prometheus.ValueType{
|
||||||
|
PERF_COUNTER_RAWCOUNT_HEX: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT_HEX: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_RAWCOUNT: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_LARGE_RAWCOUNT: prometheus.GaugeValue,
|
||||||
|
PERF_COUNTER_DELTA: prometheus.CounterValue,
|
||||||
|
PERF_COUNTER_COUNTER: prometheus.CounterValue,
|
||||||
|
PERF_COUNTER_BULK_COUNT: prometheus.CounterValue,
|
||||||
|
PERF_RAW_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_LARGE_RAW_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_100NSEC_TIMER: prometheus.CounterValue,
|
||||||
|
PERF_PRECISION_100NS_TIMER: prometheus.CounterValue,
|
||||||
|
PERF_SAMPLE_FRACTION: prometheus.GaugeValue,
|
||||||
|
PERF_100NSEC_TIMER_INV: prometheus.CounterValue,
|
||||||
|
PERF_ELAPSED_TIME: prometheus.GaugeValue,
|
||||||
|
PERF_SAMPLE_BASE: prometheus.GaugeValue,
|
||||||
|
PERF_RAW_BASE: prometheus.GaugeValue,
|
||||||
|
PERF_LARGE_RAW_BASE: prometheus.GaugeValue,
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user