From 88b48e2e7c08a6b76777e62285eea4dad7ffd6e7 Mon Sep 17 00:00:00 2001 From: Mohammad Alhussan Date: Fri, 5 Jan 2024 13:41:36 +0100 Subject: [PATCH] Support additional labels for per database metrics --- collector.go | 199 ++++++++++++++++++++++++++++++++++++--------------- readme.md | 7 +- 2 files changed, 147 insertions(+), 59 deletions(-) diff --git a/collector.go b/collector.go index 948d86a..0ae78e0 100644 --- a/collector.go +++ b/collector.go @@ -13,6 +13,11 @@ const ( subsystem = "" ) +type metricInfo struct { + Value float64 + Labels prometheus.Labels +} + type exporter struct { up prometheus.Gauge workingSet prometheus.Gauge @@ -25,12 +30,11 @@ type exporter struct { mapReduceIndexMappedTotal prometheus.Counter mapReduceIndexReducedTotal prometheus.Counter - databaseDocuments *prometheus.GaugeVec - databaseIndexes *prometheus.GaugeVec - databaseStaleIndexes *prometheus.GaugeVec - databaseSize *prometheus.GaugeVec - databaseInactiveTasks *prometheus.GaugeVec - databaseActiveTasks *prometheus.GaugeVec + databaseDocuments *prometheus.GaugeVec + databaseIndexes *prometheus.GaugeVec + databaseStaleIndexes *prometheus.GaugeVec + databaseSize *prometheus.GaugeVec + databaseTasks *prometheus.GaugeVec databaseRequestTotal *prometheus.CounterVec databaseDocumentPutTotal *prometheus.CounterVec @@ -53,12 +57,11 @@ func newExporter() *exporter { mapReduceIndexMappedTotal: createCounter("mapreduceindex_mapped_total", "Server-wide map-reduce index mapped count"), mapReduceIndexReducedTotal: createCounter("mapreduceindex_reduced_total", "Server-wide map-reduce index reduced count"), - databaseDocuments: createDatabaseGaugeVec("database_documents", "Count of documents in a database"), - databaseIndexes: createDatabaseGaugeVec("database_indexes", "Count of indexes in a database"), - databaseStaleIndexes: createDatabaseGaugeVec("database_stale_indexes", "Count of stale indexes in a database"), - databaseSize: createDatabaseGaugeVec("database_size_bytes", "Database size in bytes"), - databaseInactiveTasks: createDatabaseGaugeVec("database_inactive_tasks", "Count of inactive tasks in a database"), - databaseActiveTasks: createDatabaseGaugeVec("database_active_tasks", "Count of active tasks in a database"), + databaseDocuments: createDatabaseGaugeVec("database_documents", "Count of documents in a database"), + databaseIndexes: createDatabaseGaugeVec("database_indexes", "Count of indexes in a database"), + databaseStaleIndexes: createDatabaseGaugeVec("database_stale_indexes", "Count of stale indexes in a database"), + databaseSize: createDatabaseGaugeVec("database_size_bytes", "Database size in bytes"), + databaseTasks: createDatabaseGaugeVec("database_tasks", "Tasks in a database", "name", "type", "connection_status"), databaseRequestTotal: createDatabaseCounterVec("database_request_total", "Database request count"), databaseDocumentPutTotal: createDatabaseCounterVec("database_document_put_total", "Database document puts count"), @@ -85,8 +88,7 @@ func (e *exporter) Describe(ch chan<- *prometheus.Desc) { e.databaseIndexes.Describe(ch) e.databaseStaleIndexes.Describe(ch) e.databaseSize.Describe(ch) - e.databaseInactiveTasks.Describe(ch) - e.databaseActiveTasks.Describe(ch) + e.databaseTasks.Describe(ch) e.databaseRequestTotal.Describe(ch) e.databaseDocumentPutTotal.Describe(ch) @@ -138,8 +140,7 @@ func (e *exporter) Collect(ch chan<- prometheus.Metric) { collectPerDatabaseGauge(stats, e.databaseIndexes, getDatabaseIndexes, ch) collectPerDatabaseGauge(stats, e.databaseStaleIndexes, getDatabaseStaleIndexes, ch) collectPerDatabaseGauge(stats, e.databaseSize, getDatabaseSize, ch) - collectPerDatabaseGauge(stats, e.databaseInactiveTasks, getDatabaseInactiveTasks, ch) - collectPerDatabaseGauge(stats, e.databaseActiveTasks, getDatabaseActiveTasks, ch) + collectPerDatabaseGauge(stats, e.databaseTasks, getDatabaseTasks, ch) collectPerDatabaseCounter(stats, e.databaseRequestTotal, getDatabaseRequestTotal, ch) collectPerDatabaseCounter(stats, e.databaseDocumentPutBytes, getDatabaseDocumentPutBytes, ch) @@ -152,16 +153,24 @@ func (e *exporter) Collect(ch chan<- prometheus.Metric) { } } -func collectPerDatabaseGauge(stats *stats, vec *prometheus.GaugeVec, collectFunc func(*dbStats) float64, ch chan<- prometheus.Metric) { +func collectPerDatabaseGauge(stats *stats, vec *prometheus.GaugeVec, collectFunc func(*dbStats) []metricInfo, ch chan<- prometheus.Metric) { for _, dbs := range stats.dbStats { - vec.WithLabelValues(dbs.database).Set(collectFunc(dbs)) + metricInfos := collectFunc(dbs) + + for _, metricInfo := range metricInfos { + vec.With(metricInfo.Labels).Set(metricInfo.Value) + } } vec.Collect(ch) } -func collectPerDatabaseCounter(stats *stats, vec *prometheus.CounterVec, collectFunc func(*dbStats) float64, ch chan<- prometheus.Metric) { +func collectPerDatabaseCounter(stats *stats, vec *prometheus.CounterVec, collectFunc func(*dbStats) []metricInfo, ch chan<- prometheus.Metric) { for _, dbs := range stats.dbStats { - vec.WithLabelValues(dbs.database).Set(collectFunc(dbs)) + metricInfos := collectFunc(dbs) + + for _, metricInfo := range metricInfos { + vec.With(metricInfo.Labels).Set(metricInfo.Value) + } } vec.Collect(ch) } @@ -218,37 +227,56 @@ func getMapReduceIndexReducedTotal(stats *stats) float64 { return value } -func getDatabaseDocuments(dbStats *dbStats) float64 { +func getDatabaseDocuments(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.databaseStats, "CountOfDocuments") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseIndexes(dbStats *dbStats) float64 { +func getDatabaseIndexes(dbStats *dbStats) []metricInfo { + var mi []metricInfo value, _ := jp.GetFloat(dbStats.databaseStats, "CountOfIndexes") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func countDatabaseTasksByStatus(data []byte, status string) int { - count := 0 - jp.ArrayEach(data, func(value []byte, dataType jp.ValueType, offset int, err error) { - if taskConnectionStatus, _ := jp.GetString(value, "TaskConnectionStatus"); taskConnectionStatus == status { - count++ - } - }, "OngoingTasksList") +func getDatabaseTasks(dbStats *dbStats) []metricInfo { + var mi []metricInfo - return count -} + // Required for compatibility with versions 5 and 6 + onGoingTasksKey := "OngoingTasks" + _, _, _, err := jp.Get(dbStats.tasks, onGoingTasksKey) + if err != nil { + onGoingTasksKey = "OngoingTasksList" + } -func getDatabaseInactiveTasks(dbStats *dbStats) float64 { - return float64(countDatabaseTasksByStatus(dbStats.tasks, "NotActive")) + jp.ArrayEach(dbStats.tasks, func(value []byte, dataType jp.ValueType, offset int, err error) { + taskName, _ := jp.GetString(value, "TaskName") + taskType, _ := jp.GetString(value, "TaskType") + connectionStatus, _ := jp.GetString(value, "TaskConnectionStatus") -} + labels := generateDatabaseLabels(dbStats, map[string]string{ + "name": taskName, + "type": taskType, + "connection_status": connectionStatus, + }) + + mi = appendMetricInfo(mi, 1, labels) + }, onGoingTasksKey) -func getDatabaseActiveTasks(dbStats *dbStats) float64 { - return float64(countDatabaseTasksByStatus(dbStats.tasks, "Active")) + return mi } -func getDatabaseStaleIndexes(dbStats *dbStats) float64 { +func getDatabaseStaleIndexes(dbStats *dbStats) []metricInfo { + var mi []metricInfo + + labels := generateDatabaseLabels(dbStats, nil) count := 0 jp.ArrayEach(dbStats.databaseStats, func(value []byte, dataType jp.ValueType, offset int, err error) { if isStale, _ := jp.GetBoolean(value, "IsStale"); isStale { @@ -256,42 +284,78 @@ func getDatabaseStaleIndexes(dbStats *dbStats) float64 { } }, "Indexes") - return float64(count) + mi = appendMetricInfo(mi, float64(count), labels) + return mi } -func getDatabaseSize(dbStats *dbStats) float64 { +func getDatabaseSize(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.databaseStats, "SizeOnDisk", "SizeInBytes") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseRequestTotal(dbStats *dbStats) float64 { +func getDatabaseRequestTotal(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "Requests", "RequestsPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseDocumentPutTotal(dbStats *dbStats) float64 { +func getDatabaseDocumentPutTotal(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "Docs", "PutsPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseDocumentPutBytes(dbStats *dbStats) float64 { +func getDatabaseDocumentPutBytes(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "Docs", "BytesPutsPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseMapIndexIndexedTotal(dbStats *dbStats) float64 { +func getDatabaseMapIndexIndexedTotal(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "MapIndexes", "IndexedPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseMapReduceIndexMappedTotal(dbStats *dbStats) float64 { +func getDatabaseMapReduceIndexMappedTotal(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "MapIndexes", "MappedPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } -func getDatabaseMapReduceIndexReducedTotal(dbStats *dbStats) float64 { +func getDatabaseMapReduceIndexReducedTotal(dbStats *dbStats) []metricInfo { + var mi []metricInfo + value, _ := jp.GetFloat(dbStats.metrics, "MapIndexes", "ReducedPerSec", "Count") - return value + labels := generateDatabaseLabels(dbStats, nil) + mi = appendMetricInfo(mi, value, labels) + + return mi } func createGauge(name string, help string) prometheus.Gauge { @@ -303,13 +367,13 @@ func createGauge(name string, help string) prometheus.Gauge { }) } -func createDatabaseGaugeVec(name string, help string) *prometheus.GaugeVec { +func createDatabaseGaugeVec(name string, help string, labels ...string) *prometheus.GaugeVec { return prometheus.NewGaugeVec(prometheus.GaugeOpts{ Namespace: namespace, Subsystem: subsystem, Name: name, Help: help, - }, []string{"database"}) + }, append([]string{"database"}, labels...)) } func createCounter(name string, help string) prometheus.Counter { @@ -321,13 +385,13 @@ func createCounter(name string, help string) prometheus.Counter { }) } -func createDatabaseCounterVec(name string, help string) *prometheus.CounterVec { +func createDatabaseCounterVec(name string, help string, labels ...string) *prometheus.CounterVec { return prometheus.NewCounterVec(prometheus.CounterOpts{ Namespace: namespace, Subsystem: subsystem, Name: name, Help: help, - }, []string{"database"}) + }, append([]string{"database"}, labels...)) } var timespanRegex = regexp.MustCompile(`((?P\d+)\.)?(?P\d{2}):(?P\d{2}):(?P\d{2})(\.(?P\d{7}))?`) @@ -372,3 +436,22 @@ func matchNamedGroups(regex *regexp.Regexp, text string) map[string]string { } return results } + +func generateDatabaseLabels(dbStats *dbStats, additionalLabels map[string]string) prometheus.Labels { + labels := prometheus.Labels{ + "database": dbStats.database, + } + + for key, value := range additionalLabels { + labels[key] = value + } + + return labels +} + +func appendMetricInfo(tasks []metricInfo, value float64, labels prometheus.Labels) []metricInfo { + return append(tasks, metricInfo{ + Value: value, + Labels: labels, + }) +} diff --git a/readme.md b/readme.md index 35e142b..0318fea 100644 --- a/readme.md +++ b/readme.md @@ -86,6 +86,11 @@ ravendb_database_size_bytes{database="Demo"} 6.35568128e+08 # HELP ravendb_database_stale_indexes Count of stale indexes in a database # TYPE ravendb_database_stale_indexes gauge ravendb_database_stale_indexes{database="Demo"} 0 +# HELP ravendb_database_tasks Tasks in a database +# TYPE ravendb_database_tasks gauge +ravendb_database_tasks{connection_status="Active",database="Demo",name="backup",type="Backup"} 1 +ravendb_database_tasks{connection_status="NotActive",database="Demo",name="DemoSubscriptionTask",type="Subscription"} 1 +ravendb_database_tasks{connection_status="NotActive",database="Demo",name="DemoSubscriptionTask2",type="Subscription"} 1 # HELP ravendb_document_put_bytes_total Server-wide document put bytes # TYPE ravendb_document_put_bytes_total counter ravendb_document_put_bytes_total 0 @@ -119,7 +124,7 @@ ravendb_working_set_bytes 1.651195904e+09 ### 0.5.0 -* Added two database gauge metrics: `ravendb_database_active_tasks` and `ravendb_database_inactive_tasks` +* Added database gauge metric: `ravendb_database_tasks` ### 0.4.0