From c8a4cb3806071b651fc71c03a85e1ac15732d75d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= Date: Tue, 26 Aug 2025 20:52:09 +0200 Subject: [PATCH] mssql: expose correct patch level without restart (#2187) --- internal/collector/mssql/mssql_instance.go | 55 +++++++++++++++++----- internal/collector/mssql/types.go | 5 +- 2 files changed, 45 insertions(+), 15 deletions(-) diff --git a/internal/collector/mssql/mssql_instance.go b/internal/collector/mssql/mssql_instance.go index 10de2078..f524d921 100644 --- a/internal/collector/mssql/mssql_instance.go +++ b/internal/collector/mssql/mssql_instance.go @@ -18,34 +18,63 @@ package mssql import ( + "fmt" + "log/slog" + "github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus/client_golang/prometheus" + "golang.org/x/sys/windows/registry" ) type collectorInstance struct { - instances *prometheus.GaugeVec + instances *prometheus.Desc } func (c *Collector) buildInstance() error { - c.instances = prometheus.NewGaugeVec( - prometheus.GaugeOpts{ - Namespace: types.Namespace, - Subsystem: Name, - Name: "instance_info", - Help: "A metric with a constant '1' value labeled with mssql instance information", - }, + c.instances = prometheus.NewDesc( + prometheus.BuildFQName(types.Namespace, Name, "instance_info"), + "A metric with a constant '1' value labeled with mssql instance information", []string{"edition", "mssql_instance", "patch", "version"}, + nil, ) - for _, instance := range c.mssqlInstances { - c.instances.WithLabelValues(instance.edition, instance.name, instance.patchVersion, instance.majorVersion.String()).Set(1) - } - return nil } func (c *Collector) collectInstance(ch chan<- prometheus.Metric) error { - c.instances.Collect(ch) + for _, instance := range c.mssqlInstances { + regKeyName := fmt.Sprintf(`Software\Microsoft\Microsoft SQL Server\%s\Setup`, instance.instanceName) + + regKey, err := registry.OpenKey(registry.LOCAL_MACHINE, regKeyName, registry.QUERY_VALUE) + if err != nil { + c.logger.Debug(fmt.Sprintf("couldn't open registry %s:", regKeyName), + slog.Any("err", err), + ) + + continue + } + + patchVersion, _, err := regKey.GetStringValue("PatchLevel") + _ = regKey.Close() + + if err != nil { + c.logger.Debug("couldn't get version from registry", + slog.Any("err", err), + ) + + continue + } + + ch <- prometheus.MustNewConstMetric( + c.instances, + prometheus.GaugeValue, + 1, + instance.edition, + instance.name, + patchVersion, + instance.majorVersion.String(), + ) + } return nil } diff --git a/internal/collector/mssql/types.go b/internal/collector/mssql/types.go index 316f7e09..5d3e9474 100644 --- a/internal/collector/mssql/types.go +++ b/internal/collector/mssql/types.go @@ -26,8 +26,8 @@ import ( type mssqlInstance struct { name string + instanceName string majorVersion mssqlServerMajorVersion - patchVersion string edition string isFirstInstance bool } @@ -54,14 +54,15 @@ func newMssqlInstance(key, name string) (mssqlInstance, error) { return mssqlInstance{}, fmt.Errorf("couldn't get version from registry: %w", err) } + instanceName := name _, name, _ = strings.Cut(name, ".") return mssqlInstance{ edition: edition, name: name, majorVersion: newMajorVersion(patchVersion), - patchVersion: patchVersion, isFirstInstance: key == "MSSQLSERVER", + instanceName: instanceName, }, nil }