os: add system installation date to metrics (#2284)

Co-authored-by: EisenbergD <dominik.eisenberg@beiersdorf.com>
This commit is contained in:
Dominik Eisenberg
2025-12-29 20:23:02 +01:00
committed by GitHub
parent 0c1336b845
commit 27186f7e78
3 changed files with 54 additions and 5 deletions

View File

@@ -15,9 +15,10 @@ None
## Metrics
| Name | Description | Type | Labels |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|------------------------------------------------------------------------|
|--------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------|-----------------------------------------------------------------------------------------------------------------|
| `windows_os_hostname` | Labelled system hostname information as provided by ComputerSystem.DNSHostName and ComputerSystem.Domain | gauge | `domain`, `fqdn`, `hostname` |
| `windows_os_info` | Contains full product name & version in labels. Note that the `major_version` for Windows 11 is "10"; a build number greater than 22000 represents Windows 11. | gauge | `product`, `version`, `major_version`, `minor_version`, `build_number`, `installation_type`|
| `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`, `revision`, `installation_type` |
| `windows_os_install_time_timestamp` | Unix timestamp of OS installation time | gauge | None |
### Example metric
@@ -27,7 +28,10 @@ None
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
windows_os_info{build_number="19045",installation_type="Client",major_version="10",minor_version="0",product="Windows 10 Pro",revision="4842",version="10.0.19045"} 1
# HELP windows_os_install_time_timestamp Unix timestamp of OS installation time
# TYPE windows_os_install_time_timestamp gauge
windows_os_install_time_timestamp 1.6725312e+09
```
## Useful queries

View File

@@ -44,8 +44,11 @@ var ConfigDefaults = Config{}
type Collector struct {
config Config
installTimeTimestamp float64
hostname *prometheus.Desc
osInformation *prometheus.Desc
installTime *prometheus.Desc
}
func New(config *Config) *Collector {
@@ -78,6 +81,13 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
return fmt.Errorf("failed to get Windows version: %w", err)
}
installTimeTimestamp, err := c.getInstallTime()
if err != nil {
return fmt.Errorf("failed to get install time: %w", err)
}
c.installTimeTimestamp = installTimeTimestamp
version := osversion.Get()
// Microsoft has decided to keep the major version as "10" for Windows 11, including the product name.
@@ -111,6 +121,13 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil,
)
c.installTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "install_time_timestamp"),
"Unix timestamp of OS installation time",
nil,
nil,
)
return nil
}
@@ -125,6 +142,12 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
1.0,
)
ch <- prometheus.MustNewConstMetric(
c.installTime,
prometheus.GaugeValue,
c.installTimeTimestamp,
)
if err := c.collectHostname(ch); err != nil {
errs = append(errs, fmt.Errorf("failed to collect hostname metrics: %w", err))
}
@@ -190,3 +213,23 @@ func (c *Collector) getWindowsVersion() (string, string, string, error) {
return strings.TrimSpace(productName), strconv.FormatUint(revision, 10), strings.TrimSpace(installationType), nil
}
func (c *Collector) getInstallTime() (float64, error) {
ntKey, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
if err != nil {
return 0, fmt.Errorf("failed to open registry key: %w", err)
}
defer func(ntKey registry.Key) {
_ = ntKey.Close()
}(ntKey)
installDate, _, err := ntKey.GetIntegerValue("InstallDate")
if errors.Is(err, registry.ErrNotExist) {
return 0, nil
} else if err != nil {
return 0, err
}
return float64(installDate), nil
}

View File

@@ -287,6 +287,8 @@ windows_exporter_collector_timeout{collector="udp"} 0
# TYPE windows_os_hostname gauge
# HELP windows_os_info Contains full product name & version in labels. Note that the "major_version" for Windows 11 is \\"10\\"; a build number greater than 22000 represents Windows 11.
# TYPE windows_os_info gauge
# HELP windows_os_install_time_timestamp Unix timestamp of OS installation time
# TYPE windows_os_install_time_timestamp gauge
# HELP windows_pagefile_free_bytes Number of bytes that can be mapped into the operating system paging files without causing any other pages to be swapped out
# TYPE windows_pagefile_free_bytes gauge
# HELP windows_pagefile_limit_bytes Number of bytes that can be stored in the operating system paging files. 0 (zero) indicates that there are no paging files