msmq: Use Performance Counter instead WMI (#1766)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2024-11-24 13:38:24 +01:00
committed by GitHub
parent e812584f27
commit 86ace68978
4 changed files with 67 additions and 84 deletions

View File

@@ -2,26 +2,22 @@
The msmq collector exposes metrics about the queues on a MSMQ server The msmq collector exposes metrics about the queues on a MSMQ server
||| | | |
-|- |---------------------|----------------------|
Metric name prefix | `msmq` | Metric name prefix | `msmq` |
Classes | `Win32_PerfRawData_MSMQ_MSMQQueue` | Spource | Performance Counters |
Enabled by default? | No | Enabled by default? | No |
## Flags ## Flags
### `--collector.msmq.msmq-where`
A WMI filter on which queues to include. `%` is a wildcard, and can be used to match on substrings.
## Metrics ## Metrics
Name | Description | Type | Labels | Name | Description | Type | Labels |
-----|-------------|------|------- |------------------------------------------|---------------------------------|-------|--------|
`windows_msmq_bytes_in_journal_queue` | Size of queue journal in bytes | gauge | `name` | `windows_msmq_bytes_in_journal_queue` | Size of queue journal in bytes | gauge | `name` |
`windows_msmq_bytes_in_queue` | Size of queue in bytes | gauge | `name` | `windows_msmq_bytes_in_queue` | Size of queue in bytes | gauge | `name` |
`windows_msmq_messages_in_journal_queue` | Count messages in queue journal | gauge | `name` | `windows_msmq_messages_in_journal_queue` | Count messages in queue journal | gauge | `name` |
`windows_msmq_messages_in_queue` | Count messages in queue | gauge | `name` | `windows_msmq_messages_in_queue` | Count messages in queue | gauge | `name` |
### Example metric ### Example metric
_This collector does not yet have explained examples, we would appreciate your help adding them!_ _This collector does not yet have explained examples, we would appreciate your help adding them!_

View File

@@ -0,0 +1,21 @@
// Copyright 2024 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package msmq
const (
BytesInJournalQueue = "Bytes in Journal Queue"
BytesInQueue = "Bytes in Queue"
MessagesInJournalQueue = "Messages in Journal Queue"
MessagesInQueue = "Messages in Queue"
)

View File

@@ -3,32 +3,26 @@
package msmq package msmq
import ( import (
"errors"
"fmt" "fmt"
"log/slog" "log/slog"
"strings"
"github.com/alecthomas/kingpin/v2" "github.com/alecthomas/kingpin/v2"
"github.com/prometheus-community/windows_exporter/internal/mi" "github.com/prometheus-community/windows_exporter/internal/mi"
"github.com/prometheus-community/windows_exporter/internal/perfdata"
"github.com/prometheus-community/windows_exporter/internal/types" "github.com/prometheus-community/windows_exporter/internal/types"
"github.com/prometheus-community/windows_exporter/internal/utils"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
) )
const Name = "msmq" const Name = "msmq"
type Config struct { type Config struct{}
QueryWhereClause *string `yaml:"query_where_clause"`
}
var ConfigDefaults = Config{ var ConfigDefaults = Config{}
QueryWhereClause: utils.ToPTR(""),
}
// A Collector is a Prometheus Collector for WMI Win32_PerfRawData_MSMQ_MSMQQueue metrics. // A Collector is a Prometheus Collector for WMI Win32_PerfRawData_MSMQ_MSMQQueue metrics.
type Collector struct { type Collector struct {
config Config config Config
miSession *mi.Session perfDataCollector *perfdata.Collector
bytesInJournalQueue *prometheus.Desc bytesInJournalQueue *prometheus.Desc
bytesInQueue *prometheus.Desc bytesInQueue *prometheus.Desc
@@ -41,10 +35,6 @@ func New(config *Config) *Collector {
config = &ConfigDefaults config = &ConfigDefaults
} }
if config.QueryWhereClause == nil {
config.QueryWhereClause = ConfigDefaults.QueryWhereClause
}
c := &Collector{ c := &Collector{
config: *config, config: *config,
} }
@@ -52,15 +42,11 @@ func New(config *Config) *Collector {
return c return c
} }
func NewWithFlags(app *kingpin.Application) *Collector { func NewWithFlags(_ *kingpin.Application) *Collector {
c := &Collector{ c := &Collector{
config: ConfigDefaults, config: ConfigDefaults,
} }
app.Flag("collector.msmq.msmq-where", "WQL 'where' clause to use in WMI metrics query. "+
"Limits the response to the msmqs you specify and reduces the size of the response.").
Default(*c.config.QueryWhereClause).StringVar(c.config.QueryWhereClause)
return c return c
} }
@@ -72,17 +58,17 @@ func (c *Collector) Close() error {
return nil return nil
} }
func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error { func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
logger = logger.With(slog.String("collector", Name)) var err error
if miSession == nil { c.perfDataCollector, err = perfdata.NewCollector("MSMQ Queue", perfdata.InstancesAll, []string{
return errors.New("miSession is nil") BytesInJournalQueue,
} BytesInQueue,
MessagesInJournalQueue,
c.miSession = miSession MessagesInQueue,
})
if *c.config.QueryWhereClause == "" { if err != nil {
logger.Warn("No where-clause specified for msmq collector. This will generate a very large number of metrics!") return fmt.Errorf("failed to create MSMQ Queue collector: %w", err)
} }
c.bytesInJournalQueue = prometheus.NewDesc( c.bytesInJournalQueue = prometheus.NewDesc(
@@ -113,61 +99,41 @@ func (c *Collector) Build(logger *slog.Logger, miSession *mi.Session) error {
return nil return nil
} }
type msmqQueue struct {
Name string `mi:"Name"`
BytesInJournalQueue uint64 `mi:"BytesInJournalQueue"`
BytesInQueue uint64 `mi:"BytesInQueue"`
MessagesInJournalQueue uint64 `mi:"MessagesInJournalQueue"`
MessagesInQueue uint64 `mi:"MessagesInQueue"`
}
// Collect sends the metric values for each metric // Collect sends the metric values for each metric
// to the provided prometheus Metric channel. // to the provided prometheus Metric channel.
func (c *Collector) Collect(ch chan<- prometheus.Metric) error { func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
var dst []msmqQueue perfData, err := c.perfDataCollector.Collect()
query := "SELECT * FROM Win32_PerfRawData_MSMQ_MSMQQueue"
if *c.config.QueryWhereClause != "" {
query += " WHERE " + *c.config.QueryWhereClause
}
queryExpression, err := mi.NewQuery(query)
if err != nil { if err != nil {
return fmt.Errorf("failed to create WMI query: %w", err) return fmt.Errorf("failed to collect MSMQ Queue metrics: %w", err)
} }
if err := c.miSession.Query(&dst, mi.NamespaceRootCIMv2, queryExpression); err != nil { for name, data := range perfData {
return fmt.Errorf("WMI query failed: %w", err)
}
for _, msmq := range dst {
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.bytesInJournalQueue, c.bytesInJournalQueue,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(msmq.BytesInJournalQueue), data[BytesInJournalQueue].FirstValue,
strings.ToLower(msmq.Name), name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.bytesInQueue, c.bytesInQueue,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(msmq.BytesInQueue), data[BytesInQueue].FirstValue,
strings.ToLower(msmq.Name), name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.messagesInJournalQueue, c.messagesInJournalQueue,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(msmq.MessagesInJournalQueue), data[MessagesInJournalQueue].FirstValue,
strings.ToLower(msmq.Name), name,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.messagesInQueue, c.messagesInQueue,
prometheus.GaugeValue, prometheus.GaugeValue,
float64(msmq.MessagesInQueue), data[MessagesInQueue].FirstValue,
strings.ToLower(msmq.Name), name,
) )
} }

View File

@@ -96,19 +96,19 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil, nil,
) )
c.writeRequests = prometheus.NewDesc( c.writeRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "server_shares_write_requests_count"), prometheus.BuildFQName(types.Namespace, Name, "server_shares_write_requests_count_total"),
"Writes requests on the SMB Server Share", "Writes requests on the SMB Server Share",
[]string{"share"}, []string{"share"},
nil, nil,
) )
c.readRequests = prometheus.NewDesc( c.readRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "server_shares_read_requests_count"), prometheus.BuildFQName(types.Namespace, Name, "server_shares_read_requests_count_total"),
"Read requests on the SMB Server Share", "Read requests on the SMB Server Share",
[]string{"share"}, []string{"share"},
nil, nil,
) )
c.metadataRequests = prometheus.NewDesc( c.metadataRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "server_shares_metadata_requests_count"), prometheus.BuildFQName(types.Namespace, Name, "server_shares_metadata_requests_count_total"),
"Metadata requests on the SMB Server Share", "Metadata requests on the SMB Server Share",
[]string{"share"}, []string{"share"},
nil, nil,
@@ -120,7 +120,7 @@ func (c *Collector) Build(_ *slog.Logger, _ *mi.Session) error {
nil, nil,
) )
c.filesOpened = prometheus.NewDesc( c.filesOpened = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "server_shares_filed_opened_count"), prometheus.BuildFQName(types.Namespace, Name, "server_shares_filed_opened_count_total"),
"Files opened on the SMB Server Share", "Files opened on the SMB Server Share",
[]string{"share"}, []string{"share"},
nil, nil,
@@ -160,21 +160,21 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.writeRequests, c.writeRequests,
prometheus.GaugeValue, prometheus.CounterValue,
data[writeRequests].FirstValue, data[writeRequests].FirstValue,
share, share,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.readRequests, c.readRequests,
prometheus.GaugeValue, prometheus.CounterValue,
data[readRequests].FirstValue, data[readRequests].FirstValue,
share, share,
) )
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.metadataRequests, c.metadataRequests,
prometheus.GaugeValue, prometheus.CounterValue,
data[metadataRequests].FirstValue, data[metadataRequests].FirstValue,
share, share,
) )
@@ -188,7 +188,7 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
ch <- prometheus.MustNewConstMetric( ch <- prometheus.MustNewConstMetric(
c.filesOpened, c.filesOpened,
prometheus.GaugeValue, prometheus.CounterValue,
data[filesOpened].FirstValue, data[filesOpened].FirstValue,
share, share,
) )