Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ P.S. Consider using `-append-instance-role-label` option to easily distinguish m
| include-go-runtime-metrics | REDIS_EXPORTER_INCLUDE_GO_RUNTIME_METRICS | Whether to include Go runtime metrics, defaults to false. |
| include-config-metrics | REDIS_EXPORTER_INCL_CONFIG_METRICS | Whether to include all config settings as metrics, defaults to false. |
| include-system-metrics | REDIS_EXPORTER_INCL_SYSTEM_METRICS | Whether to include system metrics like `total_system_memory_bytes`, defaults to false. |
| include-rdb-file-size-metric | REDIS_EXPORTER_INCL_RDB_FILE_SIZE_METRIC | Whether to include RDB file size metric (requires filesystem access to RDB file), defaults to false. |
| include-modules-metrics | REDIS_EXPORTER_INCL_MODULES_METRICS | Whether to collect Redis Modules metrics, defaults to false. |
| include-search-indexes-metrics | REDIS_EXPORTER_INCL_SEARCH_INDEXES_METRICS | Whether to collect Redis Search indexes metrics, defaults to false. |
| check-search-indexes | REDIS_EXPORTER_CHECK_SEARCH_INDEXES | Regex pattern for Redis Search indexes to export metrics from FT.INFO command, defaults to ".*". |
Expand Down
6 changes: 6 additions & 0 deletions exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type Options struct {
ExcludeLatencyHistogramMetrics bool
RedactConfigMetrics bool
InclSystemMetrics bool
InclRdbFileSizeMetric bool
SkipTLSVerification bool
SetClientName bool
IsTile38 bool
Expand Down Expand Up @@ -606,6 +607,7 @@ func NewRedisExporter(uri string, opts Options) (*Exporter, error) {
"stream_radix_tree_keys": {txt: `Radix tree keys count"`, lbls: []string{"db", "stream"}},
"stream_radix_tree_nodes": {txt: `Radix tree nodes count`, lbls: []string{"db", "stream"}},
"up": {txt: "Information about the Redis instance"},
"rdb_current_size_bytes": {txt: "Current RDB file size in bytes"},
} {
if e.options.AppendInstanceRoleLabel {
desc.lbls = append(desc.lbls, "instance_role") // append instance_role label to all metrics
Expand Down Expand Up @@ -932,5 +934,9 @@ func (e *Exporter) scrapeRedisHost(ch chan<- prometheus.Metric) error {
}
}

if e.options.ConfigCommandName != "-" && e.options.InclRdbFileSizeMetric {
e.extractRdbFileSizeMetric(ch, c)
}

return nil
}
48 changes: 48 additions & 0 deletions exporter/rdb.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package exporter

import (
"os"
"path/filepath"

"github.com/gomodule/redigo/redis"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
)

func (e *Exporter) extractRdbFileSizeMetric(ch chan<- prometheus.Metric, c redis.Conn) {
result, err := redis.Values(doRedisCmd(c, e.options.ConfigCommandName, "GET", "dir", "dbfilename"))
if err != nil || len(result) < 4 {
log.Debugf("Failed to get RDB config from CONFIG GET dir dbfilename: %s", err)
return
}

dir, err := redis.String(result[1], nil)
if err != nil {
log.Debugf("Failed to parse RDB directory: %s", err)
return
}
dbfilename, err := redis.String(result[3], nil)
if err != nil {
log.Debugf("Failed to parse RDB filename: %s", err)
return
}

rdbPath := filepath.Join(dir, dbfilename)
log.Debugf("RDB file path: %s", rdbPath)

fileInfo, err := os.Stat(rdbPath)
if err != nil {
if os.IsNotExist(err) {
log.Debugf("RDB file does not exist: %s", rdbPath)
// File doesn't exist, report 0
e.registerConstMetricGauge(ch, "rdb_current_size_bytes", 0)
return
}
log.Debugf("Failed to stat RDB file %s: %s", rdbPath, err)
return
}

fileSize := float64(fileInfo.Size())
log.Debugf("RDB file size: %d bytes", fileInfo.Size())
e.registerConstMetricGauge(ch, "rdb_current_size_bytes", fileSize)
}
117 changes: 117 additions & 0 deletions exporter/rdb_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package exporter

import (
"os"
"strings"
"testing"

"github.com/prometheus/client_golang/prometheus"
dto "github.com/prometheus/client_model/go"
)

func TestExtractRdbFileSizeMetric(t *testing.T) {
if os.Getenv("TEST_REDIS_URI") == "" {
t.Skipf("TEST_REDIS_URI not set - skipping")
}

addr := os.Getenv("TEST_REDIS_URI")
e, err := NewRedisExporter(addr, Options{
Namespace: "test",
InclRdbFileSizeMetric: true,
ConfigCommandName: "CONFIG",
})
if err != nil {
t.Fatalf("NewRedisExporter() failed: %s", err)
}

c, err := e.connectToRedis()
if err != nil {
t.Fatalf("connectToRedis() failed: %s", err)
}
defer c.Close()

ch := make(chan prometheus.Metric, 100)
e.extractRdbFileSizeMetric(ch, c)
close(ch)

found := false
for m := range ch {
if strings.Contains(m.Desc().String(), "rdb_current_size_bytes") {
found = true
d := &dto.Metric{}
if err := m.Write(d); err == nil && d.GetGauge() != nil {
metricValue := d.GetGauge().GetValue()
if metricValue < 0 {
t.Errorf("rdb_current_size_bytes should not be negative, got %f", metricValue)
}
}
break
}
}

if !found {
t.Error("rdb_current_size_bytes metric should be present")
}
}

func TestExtractRdbFileSizeMetricDisabled(t *testing.T) {
if os.Getenv("TEST_REDIS_URI") == "" {
t.Skipf("TEST_REDIS_URI not set - skipping")
}

addr := os.Getenv("TEST_REDIS_URI")

e, err := NewRedisExporter(addr, Options{
Namespace: "test",
InclRdbFileSizeMetric: false,
ConfigCommandName: "CONFIG",
})
if err != nil {
t.Fatalf("NewRedisExporter() failed: %s", err)
}

ch := make(chan prometheus.Metric, 100)
go func() {
e.Collect(ch)
close(ch)
}()

for m := range ch {
if strings.Contains(m.Desc().String(), "rdb_current_size_bytes") {
t.Error("rdb_current_size_bytes metric should NOT be present when disabled")
}
}
}

func TestExtractRdbFileSizeMetricConfigDisabled(t *testing.T) {
if os.Getenv("TEST_REDIS_URI") == "" {
t.Skipf("TEST_REDIS_URI not set - skipping")
}

addr := os.Getenv("TEST_REDIS_URI")

e, err := NewRedisExporter(addr, Options{
Namespace: "test",
InclRdbFileSizeMetric: true,
ConfigCommandName: "-",
})
if err != nil {
t.Fatalf("NewRedisExporter() failed: %s", err)
}

c, err := e.connectToRedis()
if err != nil {
t.Fatalf("connectToRedis() failed: %s", err)
}
defer c.Close()

ch := make(chan prometheus.Metric, 100)
e.extractRdbFileSizeMetric(ch, c)
close(ch)

for m := range ch {
if strings.Contains(m.Desc().String(), "rdb_current_size_bytes") {
t.Error("rdb_current_size_bytes metric should NOT be present when CONFIG command is disabled")
}
}
}
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ func main() {
excludeLatencyHistogramMetrics = flag.Bool("exclude-latency-histogram-metrics", getEnvBool("REDIS_EXPORTER_EXCLUDE_LATENCY_HISTOGRAM_METRICS", false), "Do not try to collect latency histogram metrics")
redactConfigMetrics = flag.Bool("redact-config-metrics", getEnvBool("REDIS_EXPORTER_REDACT_CONFIG_METRICS", true), "Whether to redact config settings that include potentially sensitive information like passwords")
inclSystemMetrics = flag.Bool("include-system-metrics", getEnvBool("REDIS_EXPORTER_INCL_SYSTEM_METRICS", false), "Whether to include system metrics like e.g. redis_total_system_memory_bytes")
inclRdbFileSizeMetric = flag.Bool("include-rdb-file-size-metric", getEnvBool("REDIS_EXPORTER_INCL_RDB_FILE_SIZE_METRIC", false), "Whether to include RDB file size metric (requires filesystem access to RDB file)")
skipTLSVerification = flag.Bool("skip-tls-verification", getEnvBool("REDIS_EXPORTER_SKIP_TLS_VERIFICATION", false), "Whether to to skip TLS verification")
skipCheckKeysForRoleMaster = flag.Bool("skip-checkkeys-for-role-master", getEnvBool("REDIS_EXPORTER_SKIP_CHECKKEYS_FOR_ROLE_MASTER", false), "Whether to skip gathering the check-keys metrics (size, val) when the instance is of type master (reduce load on master nodes)")
basicAuthUsername = flag.String("basic-auth-username", getEnv("REDIS_EXPORTER_BASIC_AUTH_USERNAME", ""), "Username for basic authentication")
Expand Down Expand Up @@ -272,6 +273,7 @@ func main() {
CountKeys: *countKeys,
LuaScript: ls,
InclSystemMetrics: *inclSystemMetrics,
InclRdbFileSizeMetric: *inclRdbFileSizeMetric,
InclConfigMetrics: *inclConfigMetrics,
DisableExportingKeyValues: *disableExportingKeyValues,
ExcludeLatencyHistogramMetrics: *excludeLatencyHistogramMetrics,
Expand Down
Loading