Compare commits

...

5 Commits

Author SHA1 Message Date
Jan-Otto Kröpke
d451acbd63 [0.30] fix: Avoid COINIT_MULTITHREADED in CoInitializeEx (#2066) (#2091) 2025-06-21 11:29:06 +02:00
Jan-Otto Kröpke
7c14a79ef2 [0.30] service: report invalid parameter errors as debug (#2051) (#2092) 2025-06-21 11:28:48 +02:00
Jan-Otto Kröpke
3d7b16d61d [0.30] fix: added count checks (#2083) (#2089) 2025-06-21 11:28:30 +02:00
Jan-Otto Kröpke
a3131dc087 [0.30] logical_disk: skip unmounted volumes (#2084) (#2090)
Co-authored-by: Nic Jansma <nic@nicj.net>
2025-06-21 11:28:16 +02:00
Karl Persson
93940569fa update: export properties so that they can be read from yaml file (#2054) 2025-05-22 16:33:56 +02:00
12 changed files with 39 additions and 18 deletions

View File

@@ -520,6 +520,8 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect DirectoryServices (AD) metrics: %w", err) return fmt.Errorf("failed to collect DirectoryServices (AD) metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect DirectoryServices (AD) metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -385,6 +385,8 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect ADFS metrics: %w", err) return fmt.Errorf("failed to collect ADFS metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect ADFS metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -288,6 +288,8 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect Cache metrics: %w", err) return fmt.Errorf("failed to collect Cache metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect Cache metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -403,6 +403,8 @@ func (c *Collector) collectServerMetrics(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect DHCP Server metrics: %w", err) return fmt.Errorf("failed to collect DHCP Server metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect DHCP Server metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -345,6 +345,8 @@ func (c *Collector) collectMetrics(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect DNS metrics: %w", err) return fmt.Errorf("failed to collect DNS metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect DNS metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -588,6 +588,11 @@ func getAllMountedVolumes() (map[string]string, error) {
break break
} }
if errors.Is(err, windows.ERROR_FILE_NOT_FOUND) {
// the volume is not mounted
break
}
if errors.Is(err, windows.ERROR_NO_MORE_FILES) { if errors.Is(err, windows.ERROR_NO_MORE_FILES) {
rootPathBuf = make([]uint16, (rootPathLen+1)/2) rootPathBuf = make([]uint16, (rootPathLen+1)/2)

View File

@@ -248,7 +248,7 @@ func getScheduledTasks() (ScheduledTasks, error) {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil { if err := ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE); err != nil {
var oleCode *ole.OleError var oleCode *ole.OleError
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != S_FALSE { if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != S_FALSE {
return nil, err return nil, err

View File

@@ -350,7 +350,9 @@ func (c *Collector) collectService(ch chan<- prometheus.Metric, serviceName stri
logLevel := slog.LevelWarn logLevel := slog.LevelWarn
if errors.Is(err, windows.ERROR_ACCESS_DENIED) { // ERROR_INVALID_PARAMETER returns when the process is not running. This can be happened
// if the service terminated after query the service API.
if errors.Is(err, windows.ERROR_ACCESS_DENIED) || errors.Is(err, windows.ERROR_INVALID_PARAMETER) {
logLevel = slog.LevelDebug logLevel = slog.LevelDebug
} }

View File

@@ -157,6 +157,8 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect System metrics: %w", err) return fmt.Errorf("failed to collect System metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect System metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -245,7 +245,9 @@ func (c *Collector) collectTime(ch chan<- prometheus.Metric) error {
func (c *Collector) collectNTP(ch chan<- prometheus.Metric) error { func (c *Collector) collectNTP(ch chan<- prometheus.Metric) error {
err := c.perfDataCollector.Collect(&c.perfDataObject) err := c.perfDataCollector.Collect(&c.perfDataObject)
if err != nil { if err != nil {
return fmt.Errorf("failed to collect time metrics: %w", err) return fmt.Errorf("failed to collect Windows Time Service metrics: %w", err)
} else if len(c.perfDataObject) == 0 {
return fmt.Errorf("failed to collect Windows Time Service metrics: %w", types.ErrNoDataUnexpected)
} }
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(

View File

@@ -37,14 +37,14 @@ import (
const Name = "update" const Name = "update"
type Config struct { type Config struct {
online bool `yaml:"online"` Online bool `yaml:"online"`
scrapeInterval time.Duration `yaml:"scrape_interval"` ScrapeInterval time.Duration `yaml:"scrape_interval"`
} }
//nolint:gochecknoglobals //nolint:gochecknoglobals
var ConfigDefaults = Config{ var ConfigDefaults = Config{
online: false, Online: false,
scrapeInterval: 6 * time.Hour, ScrapeInterval: 6 * time.Hour,
} }
var ( var (
@@ -85,12 +85,12 @@ func NewWithFlags(app *kingpin.Application) *Collector {
app.Flag( app.Flag(
"collector.updates.online", "collector.updates.online",
"Whether to search for updates online.", "Whether to search for updates online.",
).Default(strconv.FormatBool(ConfigDefaults.online)).BoolVar(&c.config.online) ).Default(strconv.FormatBool(ConfigDefaults.Online)).BoolVar(&c.config.Online)
app.Flag( app.Flag(
"collector.updates.scrape-interval", "collector.updates.scrape-interval",
"Define the interval of scraping Windows Update information.", "Define the interval of scraping Windows Update information.",
).Default(ConfigDefaults.scrapeInterval.String()).DurationVar(&c.config.scrapeInterval) ).Default(ConfigDefaults.ScrapeInterval.String()).DurationVar(&c.config.ScrapeInterval)
return c return c
} }
@@ -109,7 +109,7 @@ func (c *Collector) Build(logger *slog.Logger, _ *mi.Session) error {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
initErrCh := make(chan error, 1) initErrCh := make(chan error, 1)
go c.scheduleUpdateStatus(ctx, logger, initErrCh, c.config.online) go c.scheduleUpdateStatus(ctx, logger, initErrCh, c.config.Online)
c.ctxCancelFn = cancel c.ctxCancelFn = cancel
@@ -166,7 +166,7 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED); err != nil { if err := ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE); err != nil {
var oleCode *ole.OleError var oleCode *ole.OleError
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 { if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 {
initErrCh <- fmt.Errorf("CoInitializeEx: %w", err) initErrCh <- fmt.Errorf("CoInitializeEx: %w", err)
@@ -178,17 +178,17 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
defer ole.CoUninitialize() defer ole.CoUninitialize()
// Create a new instance of the WMI object // Create a new instance of the WMI object
mus, err := oleutil.CreateObject("Microsoft.Update.Session") sessionObj, err := oleutil.CreateObject("Microsoft.Update.Session")
if err != nil { if err != nil {
initErrCh <- fmt.Errorf("create Microsoft.Update.Session: %w", err) initErrCh <- fmt.Errorf("create Microsoft.Update.Session: %w", err)
return return
} }
defer mus.Release() defer sessionObj.Release()
// Query the IDispatch interface of the object // Query the IDispatch interface of the object
musQueryInterface, err := mus.QueryInterface(ole.IID_IDispatch) musQueryInterface, err := sessionObj.QueryInterface(ole.IID_IDispatch)
if err != nil { if err != nil {
initErrCh <- fmt.Errorf("IID_IDispatch: %w", err) initErrCh <- fmt.Errorf("IID_IDispatch: %w", err)
@@ -206,9 +206,9 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
// https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesession-createupdatesearcher // https://learn.microsoft.com/en-us/windows/win32/api/wuapi/nf-wuapi-iupdatesession-createupdatesearcher
us, err := oleutil.CallMethod(musQueryInterface, "CreateUpdateSearcher") us, err := oleutil.CallMethod(musQueryInterface, "CreateUpdateSearcher")
defer func(hc *ole.VARIANT) { defer func(us *ole.VARIANT) {
if us != nil { if us != nil {
_ = hc.Clear() _ = us.Clear()
} }
}(us) }(us)
@@ -268,7 +268,7 @@ func (c *Collector) scheduleUpdateStatus(ctx context.Context, logger *slog.Logge
c.mu.Unlock() c.mu.Unlock()
select { select {
case <-time.After(c.config.scrapeInterval): case <-time.After(c.config.ScrapeInterval):
case <-ctx.Done(): case <-ctx.Done():
return return
} }

View File

@@ -40,7 +40,7 @@ func (s *ScheduleService) Connect() error {
runtime.LockOSThread() runtime.LockOSThread()
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
if err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED|ole.COINIT_DISABLE_OLE1DDE); err != nil { if err := ole.CoInitializeEx(0, ole.COINIT_APARTMENTTHREADED|ole.COINIT_DISABLE_OLE1DDE); err != nil {
var oleCode *ole.OleError var oleCode *ole.OleError
if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 { if errors.As(err, &oleCode) && oleCode.Code() != ole.S_OK && oleCode.Code() != 0x00000001 {
return err return err