mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-08 05:56:37 +00:00
update: expose publish date of updates (#2050)
This commit is contained in:
@@ -26,17 +26,23 @@ Define the interval of scraping Windows Update information
|
||||
|
||||
## Metrics
|
||||
|
||||
| Name | Description | Type | Labels |
|
||||
|--------------------------------|-------------------------------------------------------------|-------|-------------------------------|
|
||||
| `windows_update_pending_info` | Expose information for a single pending update item | gauge | `category`,`severity`,`title` |
|
||||
| `windows_update_scrape_query_duration_seconds` | Duration of the last scrape query to the Windows Update API | gauge | |
|
||||
| `windows_update_scrape_timestamp_seconds` | Timestamp of the last scrape | gauge | |
|
||||
| Name | Description | Type | Labels |
|
||||
|------------------------------------------------|------------------------------------------------------------------|-------|-------------------------------|
|
||||
| `windows_update_pending_info` | Expose information for a single pending update item | gauge | `category`,`severity`,`title` |
|
||||
| `windows_update_pending_published_timestamp` | Expose last published timestamp for a single pending update item | gauge | `title` |
|
||||
| `windows_update_scrape_query_duration_seconds` | Duration of the last scrape query to the Windows Update API | gauge | |
|
||||
| `windows_update_scrape_timestamp_seconds` | Timestamp of the last scrape | gauge | |
|
||||
|
||||
### Example metrics
|
||||
```
|
||||
# HELP windows_update_pending Pending Windows Updates
|
||||
# TYPE windows_update_pending gauge
|
||||
windows_update_pending{category="Drivers",severity="",title="Intel Corporation - Bluetooth - 23.60.5.10"} 1
|
||||
# HELP windows_update_pending_info Expose information for a single pending update item
|
||||
# TYPE windows_update_pending_info gauge
|
||||
windows_update_pending_info{category="Definition Updates",id="a32ca1d0-ddd4-486b-b708-d941db4f1051",revision="204",severity="",title="Update for Windows Security platform - KB5007651 (Version 10.0.27840.1000)"} 1
|
||||
windows_update_pending_info{category="Definition Updates",id="b50a64de-a0bb-465b-9842-9963b6eee21e",revision="200",severity="",title="Security Intelligence Update for Microsoft Defender Antivirus - KB2267602 (Version 1.429.146.0) - Current Channel (Broad)"} 1
|
||||
# HELP windows_update_pending_published_timestamp Expose last published timestamp for a single pending update item
|
||||
# TYPE windows_update_pending_published_timestamp gauge
|
||||
windows_update_pending_published_timestamp{id="a32ca1d0-ddd4-486b-b708-d941db4f1051",revision="204"} 1.747872e+09
|
||||
windows_update_pending_published_timestamp{id="b50a64de-a0bb-465b-9842-9963b6eee21e",revision="200"} 1.7479584e+09
|
||||
# HELP windows_update_scrape_query_duration_seconds Duration of the last scrape query to the Windows Update API
|
||||
# TYPE windows_update_scrape_query_duration_seconds gauge
|
||||
windows_update_scrape_query_duration_seconds 2.8161838
|
||||
@@ -46,7 +52,12 @@ windows_update_scrape_timestamp_seconds 1.727539734e+09
|
||||
```
|
||||
|
||||
## Useful queries
|
||||
_This collector does not yet have any useful queries added, we would appreciate your help adding them!_
|
||||
|
||||
Add extended information like cmdline or owner to other process metrics.
|
||||
|
||||
```
|
||||
windows_update_pending_published_timestamp * on(id, revision) group_left(severity, title) windows_update_pending_info
|
||||
```
|
||||
|
||||
## Alerting examples
|
||||
_This collector does not yet have alerting examples, we would appreciate your help adding them!_
|
||||
|
||||
@@ -60,11 +60,14 @@ type Collector struct {
|
||||
mu sync.RWMutex
|
||||
ctxCancelFn context.CancelFunc
|
||||
|
||||
logger *slog.Logger
|
||||
|
||||
metricsBuf []prometheus.Metric
|
||||
|
||||
pendingUpdate *prometheus.Desc
|
||||
queryDurationSeconds *prometheus.Desc
|
||||
lastScrapeMetric *prometheus.Desc
|
||||
pendingUpdate *prometheus.Desc
|
||||
pendingUpdateLastPublished *prometheus.Desc
|
||||
queryDurationSeconds *prometheus.Desc
|
||||
lastScrapeMetric *prometheus.Desc
|
||||
}
|
||||
|
||||
func New(config *Config) *Collector {
|
||||
@@ -146,9 +149,9 @@ func (c *Collector) Close() error {
|
||||
}
|
||||
|
||||
func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
logger = logger.With(slog.String("collector", Name))
|
||||
c.logger = logger.With(slog.String("collector", Name))
|
||||
|
||||
logger.Info("update collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.")
|
||||
c.logger.Info("update collector is in an experimental state! The configuration and metrics may change in future. Please report any issues.")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
@@ -164,7 +167,14 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
|
||||
c.pendingUpdate = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "pending_info"),
|
||||
"Expose information for a single pending update item",
|
||||
[]string{"category", "severity", "title"},
|
||||
[]string{"id", "revision", "category", "severity", "title"},
|
||||
nil,
|
||||
)
|
||||
|
||||
c.pendingUpdateLastPublished = prometheus.NewDesc(
|
||||
prometheus.BuildFQName(types.Namespace, Name, "pending_published_timestamp"),
|
||||
"Expose last published timestamp for a single pending update item",
|
||||
[]string{"id", "revision"},
|
||||
nil,
|
||||
)
|
||||
|
||||
@@ -241,9 +251,16 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
|
||||
|
||||
defer musQueryInterface.Release()
|
||||
|
||||
_, err = oleutil.PutProperty(musQueryInterface, "UserLocale", 1033)
|
||||
if err != nil {
|
||||
initErrCh <- fmt.Errorf("failed to set ClientApplicationID: %w", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_, err = oleutil.PutProperty(musQueryInterface, "ClientApplicationID", "windows_exporter")
|
||||
if err != nil {
|
||||
initErrCh <- fmt.Errorf("put ClientApplicationID: %w", err)
|
||||
initErrCh <- fmt.Errorf("failed to set ClientApplicationID: %w", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -320,7 +337,7 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
|
||||
}
|
||||
|
||||
func (c *Collector) fetchUpdates(logger *slog.Logger, usd *ole.IDispatch) ([]prometheus.Metric, error) {
|
||||
metricsBuf := make([]prometheus.Metric, 0, len(c.metricsBuf))
|
||||
metricsBuf := make([]prometheus.Metric, 0, len(c.metricsBuf)*2+1)
|
||||
|
||||
timeStart := time.Now()
|
||||
|
||||
@@ -367,10 +384,22 @@ func (c *Collector) fetchUpdates(logger *slog.Logger, usd *ole.IDispatch) ([]pro
|
||||
c.pendingUpdate,
|
||||
prometheus.GaugeValue,
|
||||
1,
|
||||
update.identity,
|
||||
update.revision,
|
||||
update.category,
|
||||
update.severity,
|
||||
update.title,
|
||||
))
|
||||
|
||||
if update.lastPublished != (time.Time{}) {
|
||||
metricsBuf = append(metricsBuf, prometheus.MustNewConstMetric(
|
||||
c.pendingUpdateLastPublished,
|
||||
prometheus.GaugeValue,
|
||||
float64(update.lastPublished.Unix()),
|
||||
update.identity,
|
||||
update.revision,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
metricsBuf = append(metricsBuf, prometheus.MustNewConstMetric(
|
||||
@@ -383,9 +412,12 @@ func (c *Collector) fetchUpdates(logger *slog.Logger, usd *ole.IDispatch) ([]pro
|
||||
}
|
||||
|
||||
type windowsUpdate struct {
|
||||
category string
|
||||
severity string
|
||||
title string
|
||||
identity string
|
||||
revision string
|
||||
category string
|
||||
severity string
|
||||
title string
|
||||
lastPublished time.Time
|
||||
}
|
||||
|
||||
// getUpdateStatus retrieves the update status of the given item.
|
||||
@@ -423,10 +455,48 @@ func (c *Collector) getUpdateStatus(updd *ole.IDispatch, item int) (windowsUpdat
|
||||
return windowsUpdate{}, fmt.Errorf("get Title: %w", err)
|
||||
}
|
||||
|
||||
// Get the Identity object
|
||||
identityVariant, err := oleutil.GetProperty(updateItem, "Identity")
|
||||
if err != nil {
|
||||
return windowsUpdate{}, fmt.Errorf("get Identity: %w", err)
|
||||
}
|
||||
|
||||
identity := identityVariant.ToIDispatch()
|
||||
defer identity.Release()
|
||||
|
||||
// Read the UpdateID
|
||||
updateIDVariant, err := oleutil.GetProperty(identity, "UpdateID")
|
||||
if err != nil {
|
||||
return windowsUpdate{}, fmt.Errorf("get UpdateID: %w", err)
|
||||
}
|
||||
|
||||
revisionVariant, err := oleutil.GetProperty(identity, "RevisionNumber")
|
||||
if err != nil {
|
||||
return windowsUpdate{}, fmt.Errorf("get RevisionNumber: %w", err)
|
||||
}
|
||||
|
||||
lastPublished, err := oleutil.GetProperty(updateItem, "LastDeploymentChangeTime")
|
||||
if err != nil {
|
||||
return windowsUpdate{}, fmt.Errorf("get LastDeploymentChangeTime: %w", err)
|
||||
}
|
||||
|
||||
lastPublishedDate, err := ole.GetVariantDate(uint64(lastPublished.Val))
|
||||
if err != nil {
|
||||
c.logger.Debug("failed to convert LastDeploymentChangeTime",
|
||||
slog.String("title", title.ToString()),
|
||||
slog.Any("err", err),
|
||||
)
|
||||
|
||||
lastPublishedDate = time.Time{}
|
||||
}
|
||||
|
||||
return windowsUpdate{
|
||||
category: categoryName,
|
||||
severity: severity.ToString(),
|
||||
title: title.ToString(),
|
||||
identity: updateIDVariant.ToString(),
|
||||
revision: strconv.FormatInt(revisionVariant.Val, 10),
|
||||
category: categoryName,
|
||||
severity: severity.ToString(),
|
||||
title: title.ToString(),
|
||||
lastPublished: lastPublishedDate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user