Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -216,6 +216,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
10 changes: 9 additions & 1 deletion exporter/exporter.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ type Options struct {
ExcludeLatencyHistogramMetrics bool
RedactConfigMetrics bool
InclSystemMetrics bool
InclRdbFileSizeMetric bool
SkipTLSVerification bool
SetClientName bool
IsTile38 bool
Expand Down Expand Up @@ -542,6 +543,7 @@ func NewRedisExporter(uri string, opts Options) (*Exporter, error) {
"master_sync_in_progress": {txt: "Master sync in progress", lbls: []string{"master_host", "master_port"}},
"module_info": {txt: "Information about loaded Redis module", lbls: []string{"name", "ver", "api", "filters", "usedby", "using"}},
"number_of_distinct_key_groups": {txt: `Number of distinct key groups`, lbls: []string{"db"}},
"rdb_current_size_bytes": {txt: "Current RDB file size in bytes"},
"script_result": {txt: "Result of the collect script evaluation", lbls: []string{"filename"}},
"script_values": {txt: "Values returned by the collect script", lbls: []string{"key", "filename"}},
"search_index_num_docs": {txt: "Number of documents in search index", lbls: []string{"index_name"}},
Expand Down Expand Up @@ -824,10 +826,12 @@ func (e *Exporter) scrapeRedisHost(ch chan<- prometheus.Metric) error {
}

dbCount := 0
var config []interface{}
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of the extra variable, call extractRdbFileSizeMetric() right up here, after line 839

if e.options.ConfigCommandName == "-" {
log.Debugf("Skipping extractConfigMetrics()")
} else {
if config, err := redis.Values(doRedisCmd(c, e.options.ConfigCommandName, "GET", "*")); err == nil {
if cfg, err := redis.Values(doRedisCmd(c, e.options.ConfigCommandName, "GET", "*")); err == nil {
config = cfg
dbCount, err = e.extractConfigMetrics(ch, config)
if err != nil {
log.Errorf("Redis extractConfigMetrics() err: %s", err)
Expand Down Expand Up @@ -936,5 +940,9 @@ func (e *Exporter) scrapeRedisHost(ch chan<- prometheus.Metric) error {
}
}

if e.options.ConfigCommandName != "-" && e.options.InclRdbFileSizeMetric && len(config) > 0 {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove the extra len(config) > 0 check here - extractRdbFileSizeMetric() handles that

e.extractRdbFileSizeMetric(ch, config)
}

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

import (
"os"
"path/filepath"
"strings"

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

func (e *Exporter) extractRdbFileSizeMetric(ch chan<- prometheus.Metric, config []interface{}) {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just simplified the config extraction anfd it's using a ma[string]string now which should make this code a lot simpler

#1109

for instance,m you don't need to iterate over the config map any longer but can simply look up filename and directory.

Please rebase and then use the config map.

if len(config) == 0 {
log.Debugf("Config is empty, cannot extract RDB file size")
return
}

// Validate config has even number of elements (key-value pairs)
if len(config)%2 != 0 {
log.Warnf("Invalid config format: odd number of elements (%d)", len(config))
return
}

// Parse config to find dir and dbfilename
configMap := make(map[string]string)
for i := 0; i < len(config); i += 2 {
key, err := redis.String(config[i], nil)
if err != nil {
log.Warnf("Failed to parse config key at index %d: %s", i, err)
continue
}
value, err := redis.String(config[i+1], nil)
if err != nil {
log.Warnf("Failed to parse config value for key '%s': %s", key, err)
continue
}
configMap[key] = value
}

dir, dirOk := configMap["dir"]
dbfilename, dbfilenameOk := configMap["dbfilename"]

if !dirOk || !dbfilenameOk {
log.Warnf("Failed to find 'dir' or 'dbfilename' in config")
return
}

// Basic path validation to prevent directory traversal
if strings.Contains(dbfilename, "..") {
log.Warnf("Invalid dbfilename contains '..': %s", dbfilename)
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
}
if os.IsPermission(err) {
log.Warnf("Permission denied accessing RDB file: %s", rdbPath)
return
}
log.Warnf("Failed to stat RDB file %s: %s", rdbPath, err)
return
}

// Verify it's a regular file
if !fileInfo.Mode().IsRegular() {
log.Warnf("RDB path is not a regular file: %s (mode: %s)", rdbPath, fileInfo.Mode())
return
}

fileSize := float64(fileInfo.Size())
log.Debugf("RDB file size: %d bytes", fileInfo.Size())
e.registerConstMetricGauge(ch, "rdb_current_size_bytes", fileSize)
}
Loading
Loading