diff --git a/README.md b/README.md index 863b527ea..6ff36fa61 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Name | Description | Enabled by default [hyperv](docs/collector.hyperv.md) | Hyper-V hosts | [iis](docs/collector.iis.md) | IIS sites and applications | [logical_disk](docs/collector.logical_disk.md) | Logical disks, disk I/O | ✓ +[logon](docs/collector.logon.md) | User logon sessions | [memory](docs/collector.memory.md) | Memory usage metrics | [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 | diff --git a/collector/logon.go b/collector/logon.go new file mode 100644 index 000000000..009e5c100 --- /dev/null +++ b/collector/logon.go @@ -0,0 +1,199 @@ +// +build windows + +package collector + +import ( + "errors" + + "github.com/StackExchange/wmi" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/log" +) + +func init() { + Factories["logon"] = NewLogonCollector +} + +// A LogonCollector is a Prometheus collector for WMI metrics +type LogonCollector struct { + LogonType *prometheus.Desc +} + +// NewLogonCollector ... +func NewLogonCollector() (Collector, error) { + const subsystem = "logon" + + return &LogonCollector{ + LogonType: prometheus.NewDesc( + prometheus.BuildFQName(Namespace, subsystem, "logon_type"), + "Number of active logon sessions (LogonSession.LogonType)", + []string{"status"}, + nil, + ), + }, nil +} + +// Collect sends the metric values for each metric +// to the provided prometheus Metric channel. +func (c *LogonCollector) Collect(ctx *ScrapeContext, ch chan<- prometheus.Metric) error { + if desc, err := c.collect(ch); err != nil { + log.Error("failed collecting user metrics:", desc, err) + return err + } + return nil +} + +// Win32_LogonSession docs: +// - https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logonsession +type Win32_LogonSession struct { + LogonType uint32 +} + +func (c *LogonCollector) collect(ch chan<- prometheus.Metric) (*prometheus.Desc, error) { + var dst []Win32_LogonSession + q := queryAll(&dst) + if err := wmi.Query(q, &dst); err != nil { + return nil, err + } + if len(dst) == 0 { + return nil, errors.New("WMI query returned empty result set") + } + + // Init counters + system := 0 + interactive := 0 + network := 0 + batch := 0 + service := 0 + proxy := 0 + unlock := 0 + networkcleartext := 0 + newcredentials := 0 + remoteinteractive := 0 + cachedinteractive := 0 + cachedremoteinteractive := 0 + cachedunlock := 0 + + for _, entry := range dst { + switch entry.LogonType { + case 0: + system++ + case 2: + interactive++ + case 3: + network++ + case 4: + batch++ + case 5: + service++ + case 6: + proxy++ + case 7: + unlock++ + case 8: + networkcleartext++ + case 9: + newcredentials++ + case 10: + remoteinteractive++ + case 11: + cachedinteractive++ + case 12: + cachedremoteinteractive++ + case 13: + cachedunlock++ + } + } + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(system), + "system", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(interactive), + "interactive", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(network), + "network", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(batch), + "batch", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(service), + "service", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(proxy), + "proxy", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(unlock), + "unlock", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(networkcleartext), + "network_clear_text", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(newcredentials), + "new_credentials", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(remoteinteractive), + "remote_interactive", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(cachedinteractive), + "cached_interactive", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(remoteinteractive), + "cached_remote_interactive", + ) + + ch <- prometheus.MustNewConstMetric( + c.LogonType, + prometheus.GaugeValue, + float64(cachedunlock), + "cached_unlock", + ) + return nil, nil +} diff --git a/docs/collector.logon.md b/docs/collector.logon.md new file mode 100644 index 000000000..ca6f9d983 --- /dev/null +++ b/docs/collector.logon.md @@ -0,0 +1,34 @@ +# logon collector + +The logon collector exposes metrics detailing the active user logon sessions. + +||| +-|- +Metric name prefix | `logon` +Classes | [`Win32_LogonSession`](https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-logonsession) +Enabled by default? | No + +## Flags + +None + +## Metrics + +Name | Description | Type | Labels +-----|-------------|------|------- +`wmi_logon_logon_type` | Number of active user logon sessions | gauge | status + +### Example metric +Query the total number of interactive logon sessions +``` +wmi_logon_logon_type{status="interactive"} +``` + +## Useful queries +Query the total number of local and remote (I.E. Terminal Services) interactive sessions. +``` +wmi_logon_logon_type{status=~"interactive|remoteinteractive"} +``` + +## Alerting examples +_This collector does not yet have alerting examples, we would appreciate your help adding them!_