mssql: fix units and types of cumulative and current counters (#2723)

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
Jan-Otto Kröpke
2026-10-15 20:52:17 +02:00
committed by GitHub
parent 11aa13bb2f
commit 8c33aba631
12 changed files with 634 additions and 227 deletions
+13 -2
View File
@@ -3,7 +3,10 @@
The collector reads the SQL Server performance objects (`Access Methods`,
`Buffer Manager`, `Databases`, `Locks`, `Wait Statistics` and others) with
`pdh.CounterTypeRaw`, one PDH collector per SQL Server instance. It needs a
SQL Server Database Engine; CI does not provision one. These notes were
SQL Server Database Engine. CI provisions SQL Server Express (instance
`CISQL`, database `CIWindowsExporter`) and lists `mssql` in
`WINDOWS_EXPORTER_TEST_COLLECTORS`, so live tests must fail there instead of
skipping. Express has no availability groups. These notes were
recorded on Windows Server 2025 (build 26100) with SQL Server 2022 Developer
Edition (`PatchLevel` 16.0.1000.6), named instance `NONDEFAULT`.
@@ -35,7 +38,15 @@ Edition (`PatchLevel` 16.0.1000.6), named instance `NONDEFAULT`.
`Cumulative wait time (ms) per second`, `Waits in progress` and
`Waits started per second`. All counters are
`PERF_COUNTER_LARGE_RAWCOUNT`, so the meaning comes from the instance name.
All values stayed 0 over 10 seconds on this idle instance.
SQL Server recomputes every item about every 5 seconds over its last
interval. Under lock contention, `Waits started per second` showed 5 and
then 0 while `sys.dm_os_wait_stats` kept growing, so all items are gauges.
- `Buffer cache hit ratio` (`PERF_RAW_FRACTION`) is windowed as well: value
and base are the page lookups of the last refresh, so it is a gauge.
`Worktables From Cache Ratio` has a growing base and is a running total.
- `TestMetricTypesMatchCounterTypes` compares the published types with
`pdh.Collector.MetricType` against a live instance; deliberate exceptions
(`Log Growths`, `Log Shrinks`, `Log Truncations`) are listed there.
- Every `.../sec` counter, and several counters without `/sec` (for example
`Mars Deadlocks`, the `SOAP ...` and `Lob...Count` counters,
`Log Flush Wait Time`, `Group Commit Time`, `Transaction Delay`,
+318 -23
View File
@@ -18,51 +18,346 @@
package mssql
import (
"log/slog"
"os"
"slices"
"strings"
"testing"
"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
"github.com/stretchr/testify/require"
"golang.org/x/sys/windows/registry"
)
// emitCollector is an unchecked collector that publishes the metrics of emit.
type emitCollector func(ch chan<- prometheus.Metric)
func (emitCollector) Describe(chan<- *prometheus.Desc) {}
func (e emitCollector) Collect(ch chan<- prometheus.Metric) { e(ch) }
type wantMetric struct {
metricType dto.MetricType
value float64
}
func gatherFirstSeries(t *testing.T, collector prometheus.Collector) map[string]*dto.Metric {
t.Helper()
registry := prometheus.NewPedanticRegistry()
require.NoError(t, registry.Register(collector))
families, err := registry.Gather()
require.NoError(t, err)
series := make(map[string]*dto.Metric, len(families))
for _, family := range families {
require.NotEmpty(t, family.GetMetric())
series[family.GetName()] = family.GetMetric()[0]
}
return series
}
func metricValue(m *dto.Metric) (dto.MetricType, float64) {
if m.GetCounter() != nil {
return dto.MetricType_COUNTER, m.GetCounter().GetValue()
}
return dto.MetricType_GAUGE, m.GetGauge().GetValue()
}
func TestCounterUnitConversions(t *testing.T) {
t.Parallel()
c := New(nil)
c.logger = slog.New(slog.DiscardHandler)
// No SQL instances are needed to build the metric descriptors.
require.NoError(t, c.buildBufferManager())
require.NoError(t, c.buildDatabases())
require.NoError(t, c.buildDatabaseReplica())
require.NoError(t, c.buildGeneralStatistics())
require.NoError(t, c.buildLocks())
c.databasesPerfDataObject = []perfDataCounterValuesDatabases{{Name: "db", DatabasesXTPControllerDLCPeakLatency: 1000}}
c.dbReplicaPerfDataObject = []perfDataCounterValuesDBReplica{{Name: "replica", DbReplicaDatabaseFlowControlDelay: 1000, DbReplicaGroupCommitTime: 1000}}
c.locksPerfDataObject = []perfDataCounterValuesLocks{{Name: "locks", LocksAverageWaitTimeMSBase: 1000}}
require.NoError(t, c.buildTransactions())
require.NoError(t, c.buildWaitStats())
c.bufManPerfDataObject = []perfDataCounterValuesBufMan{{BufManReadaheadTimePerSec: 882}}
c.databasesPerfDataObject = []perfDataCounterValuesDatabases{{
Name: "db",
DatabasesLogFlushWaitTime: 4,
DatabasesLogFlushWriteTimeMS: 3,
DatabasesLogGrowths: 2,
DatabasesLogShrinks: 1,
DatabasesLogTruncations: 5,
DatabasesXTPControllerDLCLatencyPerFetch: 2500,
DatabasesXTPControllerDLCLatencyPerFetchBase: 5,
DatabasesXTPControllerDLCPeakLatency: 1000,
}}
c.dbReplicaPerfDataObject = []perfDataCounterValuesDBReplica{{
Name: "replica",
DbReplicaDatabaseFlowControlDelay: 1000,
DbReplicaGroupCommitTime: 1000,
DbReplicaTransactionDelay: 1500,
DbReplicaRecoveryQueue: 2,
DbReplicaRedoBytesRemaining: 3,
DbReplicaLogSendQueue: 4,
DbReplicaTotalLogRequiringUndo: 5,
DbReplicaLogRemainingForUndo: 6,
}}
c.genStatsPerfDataObject = []perfDataCounterValuesGenStats{{
GenStatsHTTPAuthenticatedRequests: 1,
GenStatsMarsDeadlocks: 2,
GenStatsSOAPEmptyRequests: 3,
GenStatsSOAPMethodInvocations: 4,
GenStatsSOAPSessionInitiateRequests: 5,
GenStatsSOAPSessionTerminateRequests: 6,
GenStatsSOAPSQLRequests: 7,
GenStatsSOAPWSDLRequests: 8,
GenStatsSQLTraceIOProviderLockWaits: 9,
GenStatsTempdbRecoveryUnitID: 10,
GenStatsTempdbRowsetID: 11,
}}
c.locksPerfDataObject = []perfDataCounterValuesLocks{{
Name: "locks",
LocksAverageWaitTimeMS: 499,
LocksAverageWaitTimeMSBase: 3,
LocksLockWaitTimeMS: 499,
}}
c.transactionsPerfDataObject = []perfDataCounterValuesTransactions{{
TransactionsNonSnapshotVersionTransactions: 1,
TransactionsSnapshotTransactions: 2,
TransactionsUpdateSnapshotTransactions: 3,
TransactionsUpdateconflictratio: 4,
TransactionsUpdateconflictratioBase: 8,
TransactionsVersionCleanuprateKBPers: 5,
TransactionsVersionGenerationrateKBPers: 6,
TransactionsVersionStoreunitcount: 7,
}}
c.waitStatsPerfDataObject = []perfDataCounterValuesWaitStats{{
Name: "Waits started per second",
WaitStatsNetworkIOWaits: 2194,
}}
instance := mssqlInstance{name: "test"}
metrics := make(chan prometheus.Metric, 200)
c.emitDatabasesMetrics(metrics, instance)
c.emitDatabaseReplicaMetrics(metrics, instance)
c.emitLocksMetrics(metrics, instance)
close(metrics)
series := gatherFirstSeries(t, emitCollector(func(ch chan<- prometheus.Metric) {
c.emitBufferManagerMetrics(ch, instance)
c.emitDatabasesMetrics(ch, instance)
c.emitDatabaseReplicaMetrics(ch, instance)
c.emitGeneralStatisticsMetrics(ch, instance)
c.emitLocksMetrics(ch, instance)
c.emitTransactionsMetrics(ch, instance)
c.emitWaitStatsMetrics(ch, instance)
}))
want := map[*prometheus.Desc]float64{
c.databasesXTPControllerDLCPeakLatency: 0.001,
c.dbReplicaDatabaseFlowControlDelay: 0.001,
c.dbReplicaGroupCommitTime: 0.001,
c.locksCount: 1000,
counter := dto.MetricType_COUNTER
gauge := dto.MetricType_GAUGE
want := map[string]wantMetric{
"windows_mssql_bufman_read_ahead_issuing_seconds": {counter, 882e-6},
"windows_mssql_databases_log_flush_wait_seconds_total": {counter, 0.004},
"windows_mssql_databases_log_flush_write_seconds_total": {counter, 0.003},
"windows_mssql_databases_log_growths_total": {counter, 2},
"windows_mssql_databases_log_shrinks_total": {counter, 1},
"windows_mssql_databases_log_truncations_total": {counter, 5},
"windows_mssql_databases_xtp_controller_dlc_fetch_latency_seconds_total": {counter, 0.0025},
"windows_mssql_databases_xtp_controller_dlc_fetches_total": {counter, 5},
"windows_mssql_databases_xtp_controller_dlc_peak_latency_seconds": {gauge, 0.001},
"windows_mssql_dbreplica_database_flow_control_wait_seconds_total": {counter, 0.001},
"windows_mssql_dbreplica_group_commit_stall_seconds_total": {counter, 0.001},
"windows_mssql_dbreplica_transaction_delay_seconds_total": {counter, 1.5},
"windows_mssql_dbreplica_recovery_queue_bytes": {gauge, 2048},
"windows_mssql_dbreplica_redo_remaining_bytes": {gauge, 3072},
"windows_mssql_dbreplica_log_send_queue_bytes": {gauge, 4096},
"windows_mssql_dbreplica_total_log_requiring_undo_bytes": {gauge, 5120},
"windows_mssql_dbreplica_log_remaining_for_undo_bytes": {gauge, 6144},
"windows_mssql_genstats_http_authenticated_requests_total": {counter, 1},
"windows_mssql_genstats_mars_deadlocks_total": {counter, 2},
"windows_mssql_genstats_soap_empty_requests_total": {counter, 3},
"windows_mssql_genstats_soap_method_invocations_total": {counter, 4},
"windows_mssql_genstats_soap_session_initiate_requests_total": {counter, 5},
"windows_mssql_genstats_soap_session_terminate_requests_total": {counter, 6},
"windows_mssql_genstats_soapsql_requests_total": {counter, 7},
"windows_mssql_genstats_soapwsdl_requests_total": {counter, 8},
"windows_mssql_genstats_sql_trace_io_provider_lock_waits_total": {counter, 9},
"windows_mssql_genstats_tempdb_recovery_unit_ids_generated_total": {counter, 10},
"windows_mssql_genstats_tempdb_rowset_ids_generated_total": {counter, 11},
"windows_mssql_locks_wait_time_seconds_total": {counter, 0.499},
"windows_mssql_locks_count_total": {counter, 3},
"windows_mssql_locks_lock_wait_seconds_total": {counter, 0.499},
"windows_mssql_transactions_nonsnapshot_version_active": {gauge, 1},
"windows_mssql_transactions_snapshot_active": {gauge, 2},
"windows_mssql_transactions_update_snapshot_active": {gauge, 3},
"windows_mssql_transactions_update_conflicts_total": {counter, 4},
"windows_mssql_transactions_update_snapshot_transactions_total": {counter, 8},
"windows_mssql_transactions_version_cleanup_bytes_total": {counter, 5120},
"windows_mssql_transactions_version_generation_bytes_total": {counter, 6144},
"windows_mssql_transactions_version_store_units": {gauge, 7},
"windows_mssql_waitstats_network_io_waits": {gauge, 2194},
"windows_mssql_waitstats_lock_waits": {gauge, 0},
}
found := make(map[*prometheus.Desc]bool)
for metric := range metrics {
expected, ok := want[metric.Desc()]
if !ok {
for name, expected := range want {
metric, ok := series[name]
require.True(t, ok, "metric %s not emitted", name)
metricType, value := metricValue(metric)
require.Equal(t, expected.metricType, metricType, name)
require.InDelta(t, expected.value, value, 1e-9, name)
}
for _, removed := range []string{
"windows_mssql_databases_log_flush_wait_seconds",
"windows_mssql_databases_log_growths",
"windows_mssql_databases_xtp_controller_dlc_fetch_latency_seconds",
"windows_mssql_dbreplica_recovery_queue_records",
"windows_mssql_dbreplica_log_send_queue",
"windows_mssql_locks_count",
"windows_mssql_transactions_snapshot_active_total",
"windows_mssql_transactions_version_cleanup_rate_bytes",
} {
require.NotContains(t, series, removed)
}
}
// TestMetricTypesMatchCounterTypes checks the published types of the metrics
// against the PDH counter types of a local SQL Server instance.
func TestMetricTypesMatchCounterTypes(t *testing.T) {
t.Parallel()
// Collectors provisioned by CI must not be skipped, see docs/ci-testing.md.
required := slices.Contains(strings.Split(os.Getenv("WINDOWS_EXPORTER_TEST_COLLECTORS"), ","), Name)
key, err := registry.OpenKey(registry.LOCAL_MACHINE, `Software\Microsoft\Microsoft SQL Server\Instance Names\SQL`, registry.QUERY_VALUE)
if err != nil {
require.False(t, required, "mssql is required but no SQL Server instance was found: %v", err)
t.Skipf("no SQL Server instance: %v", err)
}
_ = key.Close()
c := New(nil)
t.Cleanup(func() { require.NoError(t, c.Close()) })
require.NoError(t, c.Build(slog.New(slog.DiscardHandler), nil))
if len(c.mssqlInstances) == 0 {
require.False(t, required, "mssql is required but no SQL Server instance was discovered")
t.Skip("no SQL Server instance")
}
instance := c.mssqlInstances[0]
type check struct {
metric string
counter string
// cumulative marks PERF_COUNTER_LARGE_RAWCOUNT counters whose help text
// says they are running totals, which PDH reports as gauges.
cumulative bool
metricType func(counter string) (prometheus.ValueType, bool)
}
bufMan := c.bufManPerfDataCollectors[instance].MetricType
databases := c.databasesPerfDataCollectors[instance].MetricType
dbReplica := c.dbReplicaPerfDataCollectors[instance].MetricType
genStats := c.genStatsPerfDataCollectors[instance].MetricType
locks := c.locksPerfDataCollectors[instance].MetricType
transactions := c.transactionsPerfDataCollectors[instance].MetricType
waitStats := c.waitStatsPerfDataCollectors[instance].MetricType
checks := []check{
{"windows_mssql_bufman_read_ahead_issuing_seconds", "Readahead time/sec", false, bufMan},
{"windows_mssql_databases_log_flush_wait_seconds_total", "Log Flush Wait Time", false, databases},
{"windows_mssql_databases_log_flush_write_seconds_total", "Log Flush Write Time (ms)", false, databases},
{"windows_mssql_databases_log_growths_total", "Log Growths", true, databases},
{"windows_mssql_databases_log_shrinks_total", "Log Shrinks", true, databases},
{"windows_mssql_databases_log_truncations_total", "Log Truncations", true, databases},
{"windows_mssql_dbreplica_database_flow_control_wait_seconds_total", "Database Flow Control Delay", false, dbReplica},
{"windows_mssql_dbreplica_group_commit_stall_seconds_total", "Group Commit Time", false, dbReplica},
{"windows_mssql_dbreplica_transaction_delay_seconds_total", "Transaction Delay", false, dbReplica},
{"windows_mssql_dbreplica_recovery_queue_bytes", "Recovery Queue", false, dbReplica},
{"windows_mssql_dbreplica_redo_remaining_bytes", "Redo Bytes Remaining", false, dbReplica},
{"windows_mssql_genstats_http_authenticated_requests_total", "HTTP Authenticated Requests", false, genStats},
{"windows_mssql_genstats_mars_deadlocks_total", "Mars Deadlocks", false, genStats},
{"windows_mssql_genstats_soap_empty_requests_total", "SOAP Empty Requests", false, genStats},
{"windows_mssql_genstats_soap_method_invocations_total", "SOAP Method Invocations", false, genStats},
{"windows_mssql_genstats_soap_session_initiate_requests_total", "SOAP Session Initiate Requests", false, genStats},
{"windows_mssql_genstats_soap_session_terminate_requests_total", "SOAP Session Terminate Requests", false, genStats},
{"windows_mssql_genstats_soapsql_requests_total", "SOAP SQL Requests", false, genStats},
{"windows_mssql_genstats_soapwsdl_requests_total", "SOAP WSDL Requests", false, genStats},
{"windows_mssql_genstats_sql_trace_io_provider_lock_waits_total", "SQL Trace IO Provider Lock Waits", false, genStats},
{"windows_mssql_genstats_tempdb_recovery_unit_ids_generated_total", "Tempdb recovery unit id", false, genStats},
{"windows_mssql_genstats_tempdb_rowset_ids_generated_total", "Tempdb rowset id", false, genStats},
{"windows_mssql_locks_lock_wait_seconds_total", "Lock Wait Time (ms)", false, locks},
{"windows_mssql_transactions_nonsnapshot_version_active", "NonSnapshot Version Transactions", false, transactions},
{"windows_mssql_transactions_snapshot_active", "Snapshot Transactions", false, transactions},
{"windows_mssql_transactions_update_snapshot_active", "Update Snapshot Transactions", false, transactions},
{"windows_mssql_transactions_version_cleanup_bytes_total", "Version Cleanup rate (KB/s)", false, transactions},
{"windows_mssql_transactions_version_generation_bytes_total", "Version Generation rate (KB/s)", false, transactions},
{"windows_mssql_transactions_version_store_units", "Version Store unit count", false, transactions},
{"windows_mssql_waitstats_lock_waits", "Lock waits", false, waitStats},
{"windows_mssql_waitstats_network_io_waits", "Network IO waits", false, waitStats},
}
metrics := make(chan prometheus.Metric)
collected := make([]prometheus.Metric, 0, 1024)
done := make(chan struct{})
go func() {
defer close(done)
for metric := range metrics {
collected = append(collected, metric)
}
}()
collectErr := c.Collect(metrics, 0)
close(metrics)
<-done
require.NoError(t, collectErr)
series := gatherFirstSeries(t, emitCollector(func(ch chan<- prometheus.Metric) {
for _, metric := range collected {
ch <- metric
}
}))
for _, check := range checks {
pdhType, ok := check.metricType(check.counter)
require.True(t, ok, "counter %s not found", check.counter)
if check.cumulative {
require.Equal(t, prometheus.GaugeValue, pdhType, check.counter)
pdhType = prometheus.CounterValue
}
want := dto.MetricType_GAUGE
if pdhType == prometheus.CounterValue {
want = dto.MetricType_COUNTER
}
metric, ok := series[check.metric]
if !ok && strings.HasPrefix(check.metric, "windows_mssql_dbreplica_") {
// Database Replica has only _Total without availability groups.
t.Logf("metric %s not emitted on this instance", check.metric)
continue
}
var value dto.Metric
require.NoError(t, metric.Write(&value))
require.InDelta(t, expected, value.GetGauge().GetValue(), 1e-9)
require.True(t, ok, "metric %s not emitted", check.metric)
found[metric.Desc()] = true
metricType, _ := metricValue(metric)
require.Equal(t, want, metricType, check.metric)
}
require.Len(t, found, len(want))
}
@@ -119,8 +119,10 @@ type perfDataCounterValuesAccessMethods struct {
AccessMethodsUsedTreePageCookie float64 `perfdata:"Used tree page cookie"`
AccessMethodsWorkfilesCreatedPerSec float64 `perfdata:"Workfiles Created/sec"`
AccessMethodsWorktablesCreatedPerSec float64 `perfdata:"Worktables Created/sec"`
AccessMethodsWorktablesFromCacheRatio float64 `perfdata:"Worktables From Cache Ratio"`
AccessMethodsWorktablesFromCacheRatioBase float64 `perfdata:"Worktables From Cache Ratio,secondvalue"`
// PERF_LARGE_RAW_FRACTION, but SQL Server keeps both values as running totals since
// the instance started, unlike Buffer cache hit ratio. Published as counters.
AccessMethodsWorktablesFromCacheRatio float64 `perfdata:"Worktables From Cache Ratio"`
AccessMethodsWorktablesFromCacheRatioBase float64 `perfdata:"Worktables From Cache Ratio,secondvalue"`
}
func (c *Collector) buildAccessMethods() error {
@@ -56,7 +56,9 @@ type collectorBufferManager struct {
}
type perfDataCounterValuesBufMan struct {
BufManBackgroundWriterPagesPerSec float64 `perfdata:"Background writer pages/sec"`
BufManBackgroundWriterPagesPerSec float64 `perfdata:"Background writer pages/sec"`
// PERF_LARGE_RAW_FRACTION. SQL Server refreshes value and base every few seconds with the
// hits and lookups of the last interval, so both are gauges.
BufManBufferCacheHitRatio float64 `perfdata:"Buffer cache hit ratio"`
BufManBufferCacheHitRatioBase float64 `perfdata:"Buffer cache hit ratio,secondvalue"`
BufManCheckpointPagesPerSec float64 `perfdata:"Checkpoint pages/sec"`
@@ -222,7 +224,7 @@ func (c *Collector) buildBufferManager() error {
)
c.bufManReadaheadtime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "bufman_read_ahead_issuing_seconds"),
"(BufferManager.Readaheadtime)",
"(BufferManager.Readaheadtime) Total time spent issuing read-ahead, in seconds",
[]string{"mssql_instance"},
nil,
)
@@ -246,6 +248,12 @@ func (c *Collector) collectBufferManagerInstance(ch chan<- prometheus.Metric, sq
return fmt.Errorf("failed to collect %s metrics: %w", c.mssqlGetPerfObjectName(sqlInstance, "Buffer Manager"), err)
}
c.emitBufferManagerMetrics(ch, sqlInstance)
return nil
}
func (c *Collector) emitBufferManagerMetrics(ch chan<- prometheus.Metric, sqlInstance mssqlInstance) {
for _, data := range c.bufManPerfDataObject {
ch <- prometheus.MustNewConstMetric(
c.bufManBackgroundwriterpages,
@@ -397,7 +405,7 @@ func (c *Collector) collectBufferManagerInstance(ch chan<- prometheus.Metric, sq
ch <- prometheus.MustNewConstMetric(
c.bufManReadaheadtime,
prometheus.CounterValue,
data.BufManReadaheadTimePerSec,
data.BufManReadaheadTimePerSec/1e6, // microseconds
sqlInstance.name,
)
@@ -408,8 +416,6 @@ func (c *Collector) collectBufferManagerInstance(ch chan<- prometheus.Metric, sq
sqlInstance.name,
)
}
return nil
}
func (c *Collector) closeBufferManager() {
+38 -22
View File
@@ -77,6 +77,7 @@ type collectorDatabases struct {
databasesTransactions *prometheus.Desc
databasesWriteTransactions *prometheus.Desc
databasesXTPControllerDLCLatencyPerFetch *prometheus.Desc
databasesXTPControllerDLCFetches *prometheus.Desc
databasesXTPControllerDLCPeakLatency *prometheus.Desc
databasesXTPControllerLogProcessed *prometheus.Desc
databasesXTPMemoryUsedKB *prometheus.Desc
@@ -129,9 +130,11 @@ type perfDataCounterValuesDatabases struct {
DatabasesTransactionsPerSec float64 `perfdata:"Transactions/sec"`
DatabasesWriteTransactionsPerSec float64 `perfdata:"Write Transactions/sec"`
DatabasesXTPControllerDLCLatencyPerFetch float64 `perfdata:"XTP Controller DLC Latency/Fetch"`
DatabasesXTPControllerDLCPeakLatency float64 `perfdata:"XTP Controller DLC Peak Latency"`
DatabasesXTPControllerLogProcessedPerSec float64 `perfdata:"XTP Controller Log Processed/sec"`
DatabasesXTPMemoryUsedKB float64 `perfdata:"XTP Memory Used (KB)"`
// PERF_AVERAGE_BULK: the base is the number of fetches.
DatabasesXTPControllerDLCLatencyPerFetchBase float64 `perfdata:"XTP Controller DLC Latency/Fetch,secondvalue"`
DatabasesXTPControllerDLCPeakLatency float64 `perfdata:"XTP Controller DLC Peak Latency"`
DatabasesXTPControllerLogProcessedPerSec float64 `perfdata:"XTP Controller Log Processed/sec"`
DatabasesXTPMemoryUsedKB float64 `perfdata:"XTP Memory Used (KB)"`
}
type perfDataCounterValuesDatabases2019 struct {
@@ -264,20 +267,20 @@ func (c *Collector) buildDatabases() error {
nil,
)
c.databasesLogFlushWaitTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_log_flush_wait_seconds"),
"(Databases.LogFlushWaitTime)",
prometheus.BuildFQName(types.Namespace, Name, "databases_log_flush_wait_seconds_total"),
"(Databases.LogFlushWaitTime) Total time commits waited for log flushes, in seconds",
[]string{"mssql_instance", "database"},
nil,
)
c.databasesLogFlushWriteTimeMS = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_log_flush_write_seconds"),
"(Databases.LogFlushWriteTimems)",
prometheus.BuildFQName(types.Namespace, Name, "databases_log_flush_write_seconds_total"),
"(Databases.LogFlushWriteTimems) Total time spent writing log flushes, in seconds",
[]string{"mssql_instance", "database"},
nil,
)
c.databasesLogGrowths = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_log_growths"),
"(Databases.LogGrowths)",
prometheus.BuildFQName(types.Namespace, Name, "databases_log_growths_total"),
"(Databases.LogGrowths) Total number of log growths for this database",
[]string{"mssql_instance", "database"},
nil,
)
@@ -372,14 +375,14 @@ func (c *Collector) buildDatabases() error {
nil,
)
c.databasesLogShrinks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_log_shrinks"),
"(Databases.LogShrinks)",
prometheus.BuildFQName(types.Namespace, Name, "databases_log_shrinks_total"),
"(Databases.LogShrinks) Total number of log shrinks for this database",
[]string{"mssql_instance", "database"},
nil,
)
c.databasesLogTruncations = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_log_truncations"),
"(Databases.LogTruncations)",
prometheus.BuildFQName(types.Namespace, Name, "databases_log_truncations_total"),
"(Databases.LogTruncations) Total number of log truncations for this database",
[]string{"mssql_instance", "database"},
nil,
)
@@ -426,8 +429,14 @@ func (c *Collector) buildDatabases() error {
nil,
)
c.databasesXTPControllerDLCLatencyPerFetch = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_xtp_controller_dlc_fetch_latency_seconds"),
"(Databases.XTPControllerDLCLatencyPerFetch)",
prometheus.BuildFQName(types.Namespace, Name, "databases_xtp_controller_dlc_fetch_latency_seconds_total"),
"(Databases.XTPControllerDLCLatencyPerFetch) Total latency of fetches from the Direct Log Consumer by the XTP controller, in seconds",
[]string{"mssql_instance", "database"},
nil,
)
c.databasesXTPControllerDLCFetches = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "databases_xtp_controller_dlc_fetches_total"),
"(Databases.XTPControllerDLCLatencyBase) Total number of fetches from the Direct Log Consumer by the XTP controller",
[]string{"mssql_instance", "database"},
nil,
)
@@ -587,21 +596,21 @@ func (c *Collector) emitDatabasesMetrics(ch chan<- prometheus.Metric, sqlInstanc
ch <- prometheus.MustNewConstMetric(
c.databasesLogFlushWaitTime,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DatabasesLogFlushWaitTime/1000.0,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.databasesLogFlushWriteTimeMS,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DatabasesLogFlushWriteTimeMS/1000.0,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.databasesLogGrowths,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DatabasesLogGrowths,
sqlInstance.name, data.Name,
)
@@ -713,14 +722,14 @@ func (c *Collector) emitDatabasesMetrics(ch chan<- prometheus.Metric, sqlInstanc
ch <- prometheus.MustNewConstMetric(
c.databasesLogShrinks,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DatabasesLogShrinks,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.databasesLogTruncations,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DatabasesLogTruncations,
sqlInstance.name, data.Name,
)
@@ -776,8 +785,15 @@ func (c *Collector) emitDatabasesMetrics(ch chan<- prometheus.Metric, sqlInstanc
ch <- prometheus.MustNewConstMetric(
c.databasesXTPControllerDLCLatencyPerFetch,
prometheus.GaugeValue,
data.DatabasesXTPControllerDLCLatencyPerFetch,
prometheus.CounterValue,
data.DatabasesXTPControllerDLCLatencyPerFetch/1e6, // microseconds
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.databasesXTPControllerDLCFetches,
prometheus.CounterValue,
data.DatabasesXTPControllerDLCLatencyPerFetchBase,
sqlInstance.name, data.Name,
)
@@ -100,8 +100,8 @@ func (c *Collector) buildDatabaseReplica() error {
// Win32_PerfRawData_{instance}_SQLServerDatabaseReplica
c.dbReplicaDatabaseFlowControlDelay = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_database_flow_control_wait_seconds"),
"(DatabaseReplica.DatabaseFlowControlDelay)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_database_flow_control_wait_seconds_total"),
"(DatabaseReplica.DatabaseFlowControlDelay) Total time spent in database flow control wait, in seconds",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -124,8 +124,8 @@ func (c *Collector) buildDatabaseReplica() error {
nil,
)
c.dbReplicaGroupCommitTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_group_commit_stall_seconds"),
"(DatabaseReplica.GroupCommitTime)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_group_commit_stall_seconds_total"),
"(DatabaseReplica.GroupCommitTime) Total time transactions waited for group commit, in seconds",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -184,14 +184,14 @@ func (c *Collector) buildDatabaseReplica() error {
nil,
)
c.dbReplicaLogremainingforundo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_log_remaining_for_undo"),
"(DatabaseReplica.Logremainingforundo)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_log_remaining_for_undo_bytes"),
"(DatabaseReplica.Logremainingforundo) Log remaining to finish the undo phase, in bytes",
[]string{"mssql_instance", "replica"},
nil,
)
c.dbReplicaLogSendQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_log_send_queue"),
"(DatabaseReplica.LogSendQueue)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_log_send_queue_bytes"),
"(DatabaseReplica.LogSendQueue) Log waiting to be sent to the database replica, in bytes",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -202,8 +202,8 @@ func (c *Collector) buildDatabaseReplica() error {
nil,
)
c.dbReplicaRecoveryQueue = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_recovery_queue_records"),
"(DatabaseReplica.RecoveryQueue)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_recovery_queue_bytes"),
"(DatabaseReplica.RecoveryQueue) Hardened log waiting to be redone on the secondary, in bytes",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -215,7 +215,7 @@ func (c *Collector) buildDatabaseReplica() error {
)
c.dbReplicaRedoBytesRemaining = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_redo_remaining_bytes"),
"(DatabaseReplica.RedoBytesRemaining)",
"(DatabaseReplica.RedoBytesRemaining) Log remaining to be redone to finish the reverting phase, in bytes",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -232,14 +232,14 @@ func (c *Collector) buildDatabaseReplica() error {
nil,
)
c.dbReplicaTotalLogrequiringundo = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_total_log_requiring_undo"),
"(DatabaseReplica.TotalLogrequiringundo)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_total_log_requiring_undo_bytes"),
"(DatabaseReplica.TotalLogrequiringundo) Log that needs to be undone, in bytes",
[]string{"mssql_instance", "replica"},
nil,
)
c.dbReplicaTransactionDelay = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_transaction_delay_seconds"),
"(DatabaseReplica.TransactionDelay)",
prometheus.BuildFQName(types.Namespace, Name, "dbreplica_transaction_delay_seconds_total"),
"(DatabaseReplica.TransactionDelay) Total time transaction termination waited for acknowledgement, in seconds",
[]string{"mssql_instance", "replica"},
nil,
)
@@ -266,7 +266,7 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
for _, data := range c.dbReplicaPerfDataObject {
ch <- prometheus.MustNewConstMetric(
c.dbReplicaDatabaseFlowControlDelay,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DbReplicaDatabaseFlowControlDelay/1e6,
sqlInstance.name, data.Name,
)
@@ -294,7 +294,7 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
ch <- prometheus.MustNewConstMetric(
c.dbReplicaGroupCommitTime,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DbReplicaGroupCommitTime/1e6,
sqlInstance.name, data.Name,
)
@@ -365,14 +365,14 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
ch <- prometheus.MustNewConstMetric(
c.dbReplicaLogremainingforundo,
prometheus.GaugeValue,
data.DbReplicaLogRemainingForUndo,
data.DbReplicaLogRemainingForUndo*1024,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.dbReplicaLogSendQueue,
prometheus.GaugeValue,
data.DbReplicaLogSendQueue,
data.DbReplicaLogSendQueue*1024,
sqlInstance.name, data.Name,
)
@@ -386,7 +386,7 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
ch <- prometheus.MustNewConstMetric(
c.dbReplicaRecoveryQueue,
prometheus.GaugeValue,
data.DbReplicaRecoveryQueue,
data.DbReplicaRecoveryQueue*1024,
sqlInstance.name, data.Name,
)
@@ -400,7 +400,7 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
ch <- prometheus.MustNewConstMetric(
c.dbReplicaRedoBytesRemaining,
prometheus.GaugeValue,
data.DbReplicaRedoBytesRemaining,
data.DbReplicaRedoBytesRemaining*1024,
sqlInstance.name, data.Name,
)
@@ -421,13 +421,13 @@ func (c *Collector) emitDatabaseReplicaMetrics(ch chan<- prometheus.Metric, sqlI
ch <- prometheus.MustNewConstMetric(
c.dbReplicaTotalLogrequiringundo,
prometheus.GaugeValue,
data.DbReplicaTotalLogRequiringUndo,
data.DbReplicaTotalLogRequiringUndo*1024,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.dbReplicaTransactionDelay,
prometheus.GaugeValue,
prometheus.CounterValue,
data.DbReplicaTransactionDelay/1000.0,
sqlInstance.name, data.Name,
)
@@ -116,7 +116,7 @@ func (c *Collector) buildGeneralStatistics() error {
nil,
)
c.genStatsHTTPAuthenticatedRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_http_authenticated_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_http_authenticated_requests_total"),
"(GeneralStatistics.HTTPAuthenticatedRequests)",
[]string{"mssql_instance"},
nil,
@@ -140,7 +140,7 @@ func (c *Collector) buildGeneralStatistics() error {
nil,
)
c.genStatsMarsDeadlocks = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_mars_deadlocks"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_mars_deadlocks_total"),
"(GeneralStatistics.MarsDeadlocks)",
[]string{"mssql_instance"},
nil,
@@ -158,55 +158,55 @@ func (c *Collector) buildGeneralStatistics() error {
nil,
)
c.genStatsSOAPEmptyRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_empty_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_empty_requests_total"),
"(GeneralStatistics.SOAPEmptyRequests)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSOAPMethodInvocations = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_method_invocations"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_method_invocations_total"),
"(GeneralStatistics.SOAPMethodInvocations)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSOAPSessionInitiateRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_session_initiate_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_session_initiate_requests_total"),
"(GeneralStatistics.SOAPSessionInitiateRequests)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSOAPSessionTerminateRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_session_terminate_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soap_session_terminate_requests_total"),
"(GeneralStatistics.SOAPSessionTerminateRequests)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSOAPSQLRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soapsql_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soapsql_requests_total"),
"(GeneralStatistics.SOAPSQLRequests)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSOAPWSDLRequests = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_soapwsdl_requests"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_soapwsdl_requests_total"),
"(GeneralStatistics.SOAPWSDLRequests)",
[]string{"mssql_instance"},
nil,
)
c.genStatsSQLTraceIOProviderLockWaits = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_sql_trace_io_provider_lock_waits"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_sql_trace_io_provider_lock_waits_total"),
"(GeneralStatistics.SQLTraceIOProviderLockWaits)",
[]string{"mssql_instance"},
nil,
)
c.genStatsTempDBRecoveryUnitID = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_tempdb_recovery_unit_ids_generated"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_tempdb_recovery_unit_ids_generated_total"),
"(GeneralStatistics.Tempdbrecoveryunitid)",
[]string{"mssql_instance"},
nil,
)
c.genStatsTempDBrowSetID = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "genstats_tempdb_rowset_ids_generated"),
prometheus.BuildFQName(types.Namespace, Name, "genstats_tempdb_rowset_ids_generated_total"),
"(GeneralStatistics.Tempdbrowsetid)",
[]string{"mssql_instance"},
nil,
@@ -255,6 +255,12 @@ func (c *Collector) collectGeneralStatisticsInstance(ch chan<- prometheus.Metric
return fmt.Errorf("failed to collect %s metrics: %w", c.mssqlGetPerfObjectName(sqlInstance, "General Statistics"), err)
}
c.emitGeneralStatisticsMetrics(ch, sqlInstance)
return nil
}
func (c *Collector) emitGeneralStatisticsMetrics(ch chan<- prometheus.Metric, sqlInstance mssqlInstance) {
ch <- prometheus.MustNewConstMetric(
c.genStatsActiveTempTables,
prometheus.GaugeValue,
@@ -278,7 +284,7 @@ func (c *Collector) collectGeneralStatisticsInstance(ch chan<- prometheus.Metric
ch <- prometheus.MustNewConstMetric(
c.genStatsHTTPAuthenticatedRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsHTTPAuthenticatedRequests,
sqlInstance.name,
)
@@ -306,7 +312,7 @@ func (c *Collector) collectGeneralStatisticsInstance(ch chan<- prometheus.Metric
ch <- prometheus.MustNewConstMetric(
c.genStatsMarsDeadlocks,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsMarsDeadlocks,
sqlInstance.name,
)
@@ -327,63 +333,63 @@ func (c *Collector) collectGeneralStatisticsInstance(ch chan<- prometheus.Metric
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPEmptyRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPEmptyRequests,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPMethodInvocations,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPMethodInvocations,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPSessionInitiateRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPSessionInitiateRequests,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPSessionTerminateRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPSessionTerminateRequests,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPSQLRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPSQLRequests,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSOAPWSDLRequests,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSOAPWSDLRequests,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsSQLTraceIOProviderLockWaits,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsSQLTraceIOProviderLockWaits,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsTempDBRecoveryUnitID,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsTempdbRecoveryUnitID,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.genStatsTempDBrowSetID,
prometheus.GaugeValue,
prometheus.CounterValue,
c.genStatsPerfDataObject[0].GenStatsTempdbRowsetID,
sqlInstance.name,
)
@@ -422,8 +428,6 @@ func (c *Collector) collectGeneralStatisticsInstance(ch chan<- prometheus.Metric
c.genStatsPerfDataObject[0].GenStatsUserConnections,
sqlInstance.name,
)
return nil
}
func (c *Collector) closeGeneralStatistics() {
+9 -9
View File
@@ -68,14 +68,14 @@ func (c *Collector) buildLocks() error {
}
c.locksWaitTime = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "locks_wait_time_seconds"),
"(Locks.AverageWaitTimems Total time in seconds which locks have been holding resources)",
prometheus.BuildFQName(types.Namespace, Name, "locks_wait_time_seconds_total"),
"(Locks.AverageWaitTimems) Total time lock requests waited, in seconds. Numerator of Average Wait Time (ms)",
[]string{"mssql_instance", "resource"},
nil,
)
c.locksCount = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "locks_count"),
"(Locks.AverageWaitTimems_Base count of how often requests have run into locks)",
prometheus.BuildFQName(types.Namespace, Name, "locks_count_total"),
"(Locks.AverageWaitTimems_Base) Total number of lock requests that waited. Base of Average Wait Time (ms)",
[]string{"mssql_instance", "resource"},
nil,
)
@@ -104,8 +104,8 @@ func (c *Collector) buildLocks() error {
nil,
)
c.locksLockWaitTimeMS = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "locks_lock_wait_seconds"),
"(Locks.LockWaitTimems)",
prometheus.BuildFQName(types.Namespace, Name, "locks_lock_wait_seconds_total"),
"(Locks.LockWaitTimems) Total time lock requests waited, in seconds",
[]string{"mssql_instance", "resource"},
nil,
)
@@ -138,14 +138,14 @@ func (c *Collector) emitLocksMetrics(ch chan<- prometheus.Metric, sqlInstance ms
for _, data := range c.locksPerfDataObject {
ch <- prometheus.MustNewConstMetric(
c.locksWaitTime,
prometheus.GaugeValue,
prometheus.CounterValue,
data.LocksAverageWaitTimeMS/1000.0,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.locksCount,
prometheus.GaugeValue,
prometheus.CounterValue,
data.LocksAverageWaitTimeMSBase,
sqlInstance.name, data.Name,
)
@@ -180,7 +180,7 @@ func (c *Collector) emitLocksMetrics(ch chan<- prometheus.Metric, sqlInstance ms
ch <- prometheus.MustNewConstMetric(
c.locksLockWaitTimeMS,
prometheus.GaugeValue,
prometheus.CounterValue,
data.LocksLockWaitTimeMS/1000.0,
sqlInstance.name, data.Name,
)
+49 -30
View File
@@ -32,13 +32,14 @@ type collectorTransactions struct {
transactionsTempDbFreeSpaceBytes *prometheus.Desc
transactionsLongestTransactionRunningSeconds *prometheus.Desc
transactionsNonSnapshotVersionActiveTotal *prometheus.Desc
transactionsSnapshotActiveTotal *prometheus.Desc
transactionsNonSnapshotVersionActive *prometheus.Desc
transactionsSnapshotActive *prometheus.Desc
transactionsActive *prometheus.Desc
transactionsUpdateConflictsTotal *prometheus.Desc
transactionsUpdateSnapshotActiveTotal *prometheus.Desc
transactionsVersionCleanupRateBytes *prometheus.Desc
transactionsVersionGenerationRateBytes *prometheus.Desc
transactionsUpdateSnapshotTotal *prometheus.Desc
transactionsUpdateSnapshotActive *prometheus.Desc
transactionsVersionCleanupBytes *prometheus.Desc
transactionsVersionGenerationBytes *prometheus.Desc
transactionsVersionStoreSizeBytes *prometheus.Desc
transactionsVersionStoreUnits *prometheus.Desc
transactionsVersionStoreCreationUnits *prometheus.Desc
@@ -52,6 +53,7 @@ type perfDataCounterValuesTransactions struct {
TransactionsSnapshotTransactions float64 `perfdata:"Snapshot Transactions"`
TransactionsTransactions float64 `perfdata:"Transactions"`
TransactionsUpdateconflictratio float64 `perfdata:"Update conflict ratio"`
TransactionsUpdateconflictratioBase float64 `perfdata:"Update conflict ratio,secondvalue"`
TransactionsUpdateSnapshotTransactions float64 `perfdata:"Update Snapshot Transactions"`
TransactionsVersionCleanuprateKBPers float64 `perfdata:"Version Cleanup rate (KB/s)"`
TransactionsVersionGenerationrateKBPers float64 `perfdata:"Version Generation rate (KB/s)"`
@@ -86,14 +88,14 @@ func (c *Collector) buildTransactions() error {
[]string{"mssql_instance"},
nil,
)
c.transactionsNonSnapshotVersionActiveTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_nonsnapshot_version_active_total"),
c.transactionsNonSnapshotVersionActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_nonsnapshot_version_active"),
"(Transactions.NonSnapshotVersionTransactions)",
[]string{"mssql_instance"},
nil,
)
c.transactionsSnapshotActiveTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_snapshot_active_total"),
c.transactionsSnapshotActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_snapshot_active"),
"(Transactions.SnapshotTransactions)",
[]string{"mssql_instance"},
nil,
@@ -106,25 +108,31 @@ func (c *Collector) buildTransactions() error {
)
c.transactionsUpdateConflictsTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_update_conflicts_total"),
"(Transactions.UpdateConflictRatio)",
"(Transactions.UpdateConflictRatio) Total number of update snapshot transactions that had an update conflict",
[]string{"mssql_instance"},
nil,
)
c.transactionsUpdateSnapshotActiveTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_update_snapshot_active_total"),
c.transactionsUpdateSnapshotTotal = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_update_snapshot_transactions_total"),
"(Transactions.UpdateConflictRatio_Base) Total number of update snapshot transactions",
[]string{"mssql_instance"},
nil,
)
c.transactionsUpdateSnapshotActive = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_update_snapshot_active"),
"(Transactions.UpdateSnapshotTransactions)",
[]string{"mssql_instance"},
nil,
)
c.transactionsVersionCleanupRateBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_version_cleanup_rate_bytes"),
"(Transactions.VersionCleanupRateKBs)",
c.transactionsVersionCleanupBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_version_cleanup_bytes_total"),
"(Transactions.VersionCleanupRateKBs) Total size of row versions removed from the version store, in bytes",
[]string{"mssql_instance"},
nil,
)
c.transactionsVersionGenerationRateBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_version_generation_rate_bytes"),
"(Transactions.VersionGenerationRateKBs)",
c.transactionsVersionGenerationBytes = prometheus.NewDesc(
prometheus.BuildFQName(types.Namespace, Name, "transactions_version_generation_bytes_total"),
"(Transactions.VersionGenerationRateKBs) Total size of row versions added to the version store, in bytes",
[]string{"mssql_instance"},
nil,
)
@@ -168,6 +176,12 @@ func (c *Collector) collectTransactionsInstance(ch chan<- prometheus.Metric, sql
return fmt.Errorf("failed to collect %s metrics: %w", c.mssqlGetPerfObjectName(sqlInstance, "Transactions"), err)
}
c.emitTransactionsMetrics(ch, sqlInstance)
return nil
}
func (c *Collector) emitTransactionsMetrics(ch chan<- prometheus.Metric, sqlInstance mssqlInstance) {
ch <- prometheus.MustNewConstMetric(
c.transactionsTempDbFreeSpaceBytes,
prometheus.GaugeValue,
@@ -183,15 +197,15 @@ func (c *Collector) collectTransactionsInstance(ch chan<- prometheus.Metric, sql
)
ch <- prometheus.MustNewConstMetric(
c.transactionsNonSnapshotVersionActiveTotal,
prometheus.CounterValue,
c.transactionsNonSnapshotVersionActive,
prometheus.GaugeValue,
c.transactionsPerfDataObject[0].TransactionsNonSnapshotVersionTransactions,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.transactionsSnapshotActiveTotal,
prometheus.CounterValue,
c.transactionsSnapshotActive,
prometheus.GaugeValue,
c.transactionsPerfDataObject[0].TransactionsSnapshotTransactions,
sqlInstance.name,
)
@@ -211,22 +225,29 @@ func (c *Collector) collectTransactionsInstance(ch chan<- prometheus.Metric, sql
)
ch <- prometheus.MustNewConstMetric(
c.transactionsUpdateSnapshotActiveTotal,
c.transactionsUpdateSnapshotTotal,
prometheus.CounterValue,
c.transactionsPerfDataObject[0].TransactionsUpdateconflictratioBase,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.transactionsUpdateSnapshotActive,
prometheus.GaugeValue,
c.transactionsPerfDataObject[0].TransactionsUpdateSnapshotTransactions,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.transactionsVersionCleanupRateBytes,
prometheus.GaugeValue,
c.transactionsVersionCleanupBytes,
prometheus.CounterValue,
c.transactionsPerfDataObject[0].TransactionsVersionCleanuprateKBPers*1024,
sqlInstance.name,
)
ch <- prometheus.MustNewConstMetric(
c.transactionsVersionGenerationRateBytes,
prometheus.GaugeValue,
c.transactionsVersionGenerationBytes,
prometheus.CounterValue,
c.transactionsPerfDataObject[0].TransactionsVersionGenerationrateKBPers*1024,
sqlInstance.name,
)
@@ -240,7 +261,7 @@ func (c *Collector) collectTransactionsInstance(ch chan<- prometheus.Metric, sql
ch <- prometheus.MustNewConstMetric(
c.transactionsVersionStoreUnits,
prometheus.CounterValue,
prometheus.GaugeValue,
c.transactionsPerfDataObject[0].TransactionsVersionStoreunitcount,
sqlInstance.name,
)
@@ -258,8 +279,6 @@ func (c *Collector) collectTransactionsInstance(ch chan<- prometheus.Metric, sql
c.transactionsPerfDataObject[0].TransactionsVersionStoreunittruncation,
sqlInstance.name,
)
return nil
}
func (c *Collector) closeTransactions() {
+23 -14
View File
@@ -161,93 +161,102 @@ func (c *Collector) collectWaitStatsInstance(ch chan<- prometheus.Metric, sqlIns
return fmt.Errorf("failed to collect %s metrics: %w", c.mssqlGetPerfObjectName(sqlInstance, "Wait Statistics"), err)
}
c.emitWaitStatsMetrics(ch, sqlInstance)
return nil
}
// emitWaitStatsMetrics publishes every wait statistic as a gauge. The instance
// (label "item") names the statistic: "Average wait time (ms)",
// "Cumulative wait time (ms) per second", "Waits in progress" and
// "Waits started per second". SQL Server computes them over its most recent
// sampling interval, so none of them only grows.
func (c *Collector) emitWaitStatsMetrics(ch chan<- prometheus.Metric, sqlInstance mssqlInstance) {
for _, data := range c.waitStatsPerfDataObject {
ch <- prometheus.MustNewConstMetric(
c.waitStatsLockWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsLockWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsMemoryGrantQueueWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsMemoryGrantQueueWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsThreadSafeMemoryObjectsWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsThreadSafeMemoryObjectsWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsLogWriteWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsLogWriteWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsLogBufferWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsLogBufferWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsNetworkIOWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsNetworkIOWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsPageIOLatchWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsPageIOLatchWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsPageLatchWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsPageLatchWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsNonPageLatchWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsNonpageLatchWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsWaitForTheWorkerWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsWaitForTheWorkerWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsWorkspaceSynchronizationWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsWorkspaceSynchronizationWaits,
sqlInstance.name, data.Name,
)
ch <- prometheus.MustNewConstMetric(
c.waitStatsTransactionOwnershipWaits,
prometheus.CounterValue,
prometheus.GaugeValue,
data.WaitStatsTransactionOwnershipWaits,
sqlInstance.name, data.Name,
)
}
return nil
}
func (c *Collector) closeWaitStats() {