Repository: oliver006/redis_exporter

Issue:
Add option to only run check and counts on replicas
**Describe the problem**

redis-exporter has these arguments available for exporting the length of particular keys:

```
check-keys
check-single-keys
check-streams
check-single-streams
count-keys
```

It's described in the docs that these commands may not perform well on large databases, and that it can affect production environments.

My questions:
1. Would it make sense to have an option that only allows these to execute on replicas?
2. Can these be enhanced to gather the memory consumed by the keys too via [MEMORY USAGE](https://redis.io/docs/latest/commands/memory-usage/)?
3. Can both these problems be solved by using a custom lua script defined in `REDIS_EXPORTER_SCRIPT`?

**What version of redis_exporter are you running?**
Please run `redis_exporter --version` if you're not sure what version you're running.
[x] 1.6.2


**Running the exporter**
N/A

**Screenshots**
N/A


**Additional context**
N/A


Hints from issue comments:
@oliver006: Good questions!

1) what's your deployment setup? A redis_exporter sidecar with each redis instance? Becuase in that case you can just configure them differently and only run check-keys on the replica instances.

2) I have not looked into using `MEMORY USAGE` and no idea re: performance comparision but worth testing

3) You could certainly replicate the check-keys functionality with a lua script and see if e.g. `MEMORY USAGE` performs better. The lua script option works well when you have defined inputs and need to return only a single float so this could be a good option.

I don't have time to investigate option (2) but that could be an easy win if that performs a lot better than GET'ing each key. (the results wouldn't be equivalent cause MEMORY USAGE reports key + val size but it's still a god approximation and can be useful. I'd put that functionality on a cmd line flag and keep the current functionality by default for backwards compatibility)@jdheyburn: Thanks for taking a look @oliver006!

> what's your deployment setup? A redis_exporter sidecar with each redis instance? Becuase in that case you can just configure them differently and only run check-keys on the replica instances.

We use a fork of the DandyDeveloper redis-ha [helm-chart](https://github.com/DandyDeveloper/charts/blob/master/charts/redis-ha/templates/redis-ha-statefulset.yaml). Each pod in the statefulset has the same configuration, one of the pods will be a master and the rest would be replicas.

> I have not looked into using MEMORY USAGE and no idea re: performance comparision but worth testing

This frequently shows up in the slow log on workloads today where we execute it on our replicas (for troubleshooting high memory issues) - so I would avoid running it on a master


@oliver006: Interesting - so the master vs replica decision is made on the fly and not pre-determined? 
I guess we could add a flag that allows for skipping the check-keys metrics if role==master, defaulting to false.@jdheyburn: @oliver006 

> Interesting - so the master vs replica decision is made on the fly and not pre-determined?

Correct. On StatefulSet provision, the first ordinal pod would be the master (as there is nothing to replicate from). Subsequent pods would be instructed to replicate from the master.

However, we have AZ affinity in our set up, this ordinal pod may not be running in the desired AZ. For that we have a separate process to invoke a failover to the pod running in the desired AZ.

> I guess we could add a flag that allows for skipping the check-keys metrics if role==master, defaulting to false.

That would be ideal, I won't have time to pick it up until later this year though.
@oliver006: #985 introduces a flag to run check-keys related metrics only on instances where `role == "slave"` 

Solution patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fec0d3a..a2aff6a 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -96,9 +96,9 @@ jobs:
         run: go mod tidy
 
       - name: golangci-lint
-        uses: golangci/golangci-lint-action@v6
+        uses: golangci/golangci-lint-action@v7
         with:
-          version: v1.64
+          version: v2.1.5
           args: "--tests=false"
 
       - name: Run checks
diff --git a/.golangci.yaml b/.golangci.yaml
new file mode 100644
index 0000000..764c9ce
--- /dev/null
+++ b/.golangci.yaml
@@ -0,0 +1,8 @@
+version: "2"
+linters:
+  exclusions:
+    presets:
+      - comments
+      - std-error-handling
+      - common-false-positives
+      - legacy
diff --git a/README.md b/README.md
index 3ce0cd4..ec739ef 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
-# Prometheus ValKey & Redis Metrics Exporter
+# Prometheus Valkey & Redis Metrics Exporter
 
 [![Tests](https://github.com/oliver006/redis_exporter/actions/workflows/tests.yml/badge.svg)](https://github.com/oliver006/redis_exporter/actions/workflows/tests.yml)
  [![Coverage Status](https://coveralls.io/repos/github/oliver006/redis_exporter/badge.svg?branch=master)](https://coveralls.io/github/oliver006/redis_exporter?branch=master) [![codecov](https://codecov.io/gh/oliver006/redis_exporter/branch/master/graph/badge.svg)](https://codecov.io/gh/oliver006/redis_exporter) [![docker_pulls](https://img.shields.io/docker/pulls/oliver006/redis_exporter.svg)](https://img.shields.io/docker/pulls/oliver006/redis_exporter.svg) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
 
-Prometheus exporter for ValKey metrics (Redis-compatible).\
-Supports ValKey and Redis 2.x, 3.x, 4.x, 5.x, 6.x, and 7.x
+Prometheus exporter for Valkey metrics (Redis-compatible).\
+Supports Valkey and Redis 2.x, 3.x, 4.x, 5.x, 6.x, and 7.x
 
 #### Ukraine is still suffering from Russian aggression, [please consider supporting Ukraine with a donation](https://www.supportukraine.co/).
 
@@ -171,12 +171,12 @@ scrape_configs:
 | redis.user              | REDIS_USER                             | User name to use for authentication (Redis ACL for Redis 6.0 and newer).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
 | redis.password          | REDIS_PASSWORD                         | Password of the Redis instance, defaults to `""` (no password).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
 | redis.password-file     | REDIS_PASSWORD_FILE                    | Password file of the Redis instance to scrape, defaults to `""` (no password file).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
-| check-keys              | REDIS_EXPORTER_CHECK_KEYS              | Comma separated list of key patterns to export value and length/size, eg: `db3=user_count` will export key `user_count` from db `3`. db defaults to `0` if omitted. The key patterns specified with this flag will be found using [SCAN](https://redis.io/commands/scan).  Use this option if you need glob pattern matching; `check-single-keys` is faster for non-pattern keys. Warning: using `--check-keys` to match a very large number of keys can slow down the exporter to the point where it doesn't finish scraping the redis instance. --check-keys doesn't work in fluster mode as "SCAN" does not work across multiple instances. |
+| check-keys              | REDIS_EXPORTER_CHECK_KEYS              | Comma separated list of key patterns to export value and length/size, eg: `db3=user_count` will export key `user_count` from db `3`. db defaults to `0` if omitted. The key patterns specified with this flag will be found using [SCAN](https://valkey.io/commands/scan).  Use this option if you need glob pattern matching; `check-single-keys` is faster for non-pattern keys. Warning: using `--check-keys` to match a very large number of keys can slow down the exporter to the point where it doesn't finish scraping the redis instance. --check-keys doesn't work in fluster mode as "SCAN" does not work across multiple instances. |
 | check-single-keys       | REDIS_EXPORTER_CHECK_SINGLE_KEYS       | Comma separated list of keys to export value and length/size, eg: `db3=user_count` will export key `user_count` from db `3`. db defaults to `0` if omitted.  The keys specified with this flag will be looked up directly without any glob pattern matching.  Use this option if you don't need glob pattern matching;  it is faster than `check-keys`.                                                                                                                                                                                                                                                                                        |
 | check-streams           | REDIS_EXPORTER_CHECK_STREAMS           | Comma separated list of stream-patterns to export info about streams, groups and consumers. Syntax is the same as `check-keys`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
 | check-single-streams    | REDIS_EXPORTER_CHECK_SINGLE_STREAMS    | Comma separated list of streams to export info about streams, groups and consumers. The streams specified with this flag will be looked up directly without any glob pattern matching.  Use this option if you don't need glob pattern matching;  it is faster than `check-streams`.                                                                                                                                                                                                                                                                                                                                                           |
 | streams-exclude-consumer-metrics    | REDIS_EXPORTER_STREAMS_EXCLUDE_CONSUMER_METRICS    | Don't collect per consumer metrics for streams (decreases amount of metrics and cardinality).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
-| check-keys-batch-size   | REDIS_EXPORTER_CHECK_KEYS_BATCH_SIZE   | Approximate number of keys to process in each execution. This is basically the COUNT option that will be passed into the SCAN command as part of the execution of the key or key group metrics, see [COUNT option](https://redis.io/commands/scan#the-count-option). Larger value speeds up scanning. Still Redis is a single-threaded app, huge `COUNT` can affect production environment.                                                                                                                                                                                                                                                    |
+| check-keys-batch-size   | REDIS_EXPORTER_CHECK_KEYS_BATCH_SIZE   | Approximate number of keys to process in each execution. This is basically the COUNT option that will be passed into the SCAN command as part of the execution of the key or key group metrics, see [COUNT option](https://valkey.io/commands/scan#the-count-option). Larger value speeds up scanning. Still Redis is a single-threaded app, huge `COUNT` can affect production environment.                                                                                                                                                                                                                                                    |
 | count-keys              | REDIS_EXPORTER_COUNT_KEYS              | Comma separated list of patterns to count, eg: `db3=sessions:*` will count all keys with prefix `sessions:` from db `3`. db defaults to `0` if omitted. Warning: The exporter runs SCAN to count the keys. This might not perform well on large databases.                                                                                                                                                                                                                                                                                                                                                                                     |
 | script                  | REDIS_EXPORTER_SCRIPT                  | Comma separated list of path(s) to Redis Lua script(s) for gathering extra metrics.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
 | debug                   | REDIS_EXPORTER_DEBUG                   | Verbose debug output                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
@@ -288,13 +288,13 @@ To enable Tile38 support, run the exporter with `--is-tile38=true`.
 ## What's exported
 
 Most items from the INFO command are exported,
-see [Redis documentation](https://redis.io/commands/info) for details.\
+see [documentation](https://valkey.io/commands/info) for details.\
 In addition, for every database there are metrics for total keys, expiring keys and the average TTL for keys in the database.\
 You can also export values of keys by using the `-check-keys` (or related) flag. The exporter will also export the size (or, depending on the data type, the length) of the key.
 This can be used to export the number of elements in (sorted) sets, hashes, lists, streams, etc.
 If a key is in string format and matches with `--check-keys` (or related) then its string value will be exported as a label in the `key_value_as_string` metric.
 
-If you require custom metric collection, you can provide comma separated list of path(s) to [Redis Lua script(s)](https://redis.io/commands/eval) using the `-script` flag. If you pass only one script, you can omit comma. An example can be found [in the contrib folder](./contrib/sample_collect_script.lua).
+If you require custom metric collection, you can provide comma separated list of path(s) to [Redis Lua script(s)](https://valkey.io/commands/eval) using the `-script` flag. If you pass only one script, you can omit comma. An example can be found [in the contrib folder](./contrib/sample_collect_script.lua).
 
 
 ### The redis_memory_max_bytes metric
diff --git a/contrib/sample_collect_script.lua b/contrib/sample_collect_script.lua
index df9b20d..b925785 100644
--- a/contrib/sample_collect_script.lua
+++ b/contrib/sample_collect_script.lua
@@ -1,7 +1,7 @@
 -- Example collect script for -script option
 -- This returns a Lua table with alternating keys and values.
 -- Both keys and values must be strings, similar to a HGETALL result.
--- More info about Redis Lua scripting: https://redis.io/commands/eval
+-- More info about Redis Lua scripting: https://valkey.io/commands/eval
 
 local result = {}
 
diff --git a/exporter/exporter.go b/exporter/exporter.go
index 7a951d7..da9c84d 100644
--- a/exporter/exporter.go
+++ b/exporter/exporter.go
@@ -87,6 +87,7 @@ type Options struct {
 	BuildInfo                      BuildInfo
 	BasicAuthUsername              string
 	BasicAuthPassword              string
+	SkipCheckKeysForRoleMaster     bool
 }
 
 // NewRedisExporter returns a new exporter of Redis metrics.
@@ -197,7 +198,7 @@ func NewRedisExporter(uri string, opts Options) (*Exporter, error) {
 			"expired_stale_perc": "expired_stale_percentage",
 
 			// https://github.com/antirez/redis/blob/17bf0b25c1171486e3a1b089f3181fff2bc0d4f0/src/evict.c#L349-L352
-			// ... the sum of AOF and slaves buffer ....
+			// ... the sum of AOF and slaves buffer ...
 			"mem_not_counted_for_evict":           "mem_not_counted_for_eviction_bytes",
 			"mem_total_replication_buffers":       "mem_total_replication_buffers_bytes",       // Added in Redis 7.0
 			"mem_overhead_db_hashtable_rehashing": "mem_overhead_db_hashtable_rehashing_bytes", // Added in Redis 7.4
@@ -720,38 +721,36 @@ func (e *Exporter) scrapeRedisHost(ch chan<- prometheus.Metric) error {
 		}
 	} else if dbCount == 0 {
 		// in non-cluster mode, if dbCount is zero then "CONFIG" failed to retrieve a valid
-		// number of databases and we use the Redis config default which is 16
+		// number of databases, and we use the Redis config default which is 16
 
 		dbCount = 16
 	}
 
 	log.Debugf("dbCount: %d", dbCount)
 
-	e.extractInfoMetrics(ch, infoAll, dbCount)
+	role := e.extractInfoMetrics(ch, infoAll, dbCount)
 
 	if !e.options.ExcludeLatencyHistogramMetrics {
 		e.extractLatencyMetrics(ch, infoAll, c)
 	}
 
-	if e.options.IsCluster {
-		clusterClient, err := e.connectToRedisCluster()
-		if err != nil {
-			log.Errorf("Couldn't connect to redis cluster")
-			return err
+	// skip these metrics for master if SkipCheckKeysForRoleMaster is set
+	// (can help with reducing workload on the master node)
+	log.Infof("checkKeys metric collection for role: %s  flag: %#v", role, e.options.SkipCheckKeysForRoleMaster)
+	if role == InstanceRoleSlave || !e.options.SkipCheckKeysForRoleMaster {
+		if err := e.extractCheckKeyMetrics(ch, c); err != nil {
+			log.Errorf("extractCheckKeyMetrics() err: %s", err)
 		}
-		defer clusterClient.Close()
 
-		e.extractCheckKeyMetrics(ch, clusterClient)
+		e.extractCountKeysMetrics(ch, c)
+
+		e.extractStreamMetrics(ch, c)
 	} else {
-		e.extractCheckKeyMetrics(ch, c)
+		log.Infof("skipping checkKeys metrics, role: %s  flag: %#v", role, e.options.SkipCheckKeysForRoleMaster)
 	}
 
 	e.extractSlowLogMetrics(ch, c)
 
-	e.extractStreamMetrics(ch, c)
-
-	e.extractCountKeysMetrics(ch, c)
-
 	e.extractKeyGroupMetrics(ch, c, dbCount)
 
 	if strings.Contains(infoAll, "# Sentinel") {
diff --git a/exporter/info.go b/exporter/info.go
index 895aaa5..8de4970 100644
--- a/exporter/info.go
+++ b/exporter/info.go
@@ -33,8 +33,13 @@ var reMasterDirect = regexp.MustCompile(`^(master(_[0-9]+)?_(last_io_seconds_ago
 slave0:ip=10.254.11.1,port=6379,state=online,offset=1751844676,lag=0
 slave1:ip=10.254.11.2,port=6379,state=online,offset=1751844222,lag=0
 */
+
 var reSlave = regexp.MustCompile(`^slave\d+`)
 
+const (
+	InstanceRoleSlave = "slave"
+)
+
 func extractVal(s string) (val float64, err error) {
 	split := strings.Split(s, "=")
 	if len(split) != 2 {
@@ -60,7 +65,8 @@ func extractPercentileVal(s string) (percentile float64, val float64, err error)
 	return
 }
 
-func (e *Exporter) extractInfoMetrics(ch chan<- prometheus.Metric, info string, dbCount int) {
+// returns the role of the instance we're scraping (master or slave)
+func (e *Exporter) extractInfoMetrics(ch chan<- prometheus.Metric, info string, dbCount int) string {
 	keyValues := map[string]string{}
 	handledDBs := map[string]bool{}
 	cmdCount := map[string]uint64{}
@@ -161,8 +167,10 @@ func (e *Exporter) extractInfoMetrics(ch chan<- prometheus.Metric, info string,
 		}
 	}
 
+	instanceRole := keyValues["role"]
+
 	e.registerConstMetricGauge(ch, "instance_info", 1,
-		keyValues["role"],
+		instanceRole,
 		keyValues["redis_version"],
 		keyValues["redis_build_id"],
 		keyValues["redis_mode"],
@@ -174,12 +182,14 @@ func (e *Exporter) extractInfoMetrics(ch chan<- prometheus.Metric, info string,
 		keyValues["master_replid"],
 	)
 
-	if keyValues["role"] == "slave" {
+	if instanceRole == InstanceRoleSlave {
 		e.registerConstMetricGauge(ch, "slave_info", 1,
 			keyValues["master_host"],
 			keyValues["master_port"],
 			keyValues["slave_read_only"])
 	}
+
+	return instanceRole
 }
 
 func (e *Exporter) generateCommandLatencySummaries(ch chan<- prometheus.Metric, cmdLatencyMap map[string]map[float64]float64, cmdCount map[string]uint64, cmdSum map[string]float64) {
@@ -422,13 +432,13 @@ func parseMetricsCommandStats(fieldKey string, fieldValue string) (cmd string, c
 
 	rejectedCalls, err = extractVal(splitValue[3])
 	if err != nil {
-		errorOut = errors.New("Invalid rejected_calls while parsing splitValue[3]")
+		errorOut = errors.New("invalid rejected_calls while parsing splitValue[3]")
 		return
 	}
 
 	failedCalls, err = extractVal(splitValue[4])
 	if err != nil {
-		errorOut = errors.New("Invalid failed_calls while parsing splitValue[4]")
+		errorOut = errors.New("invalid failed_calls while parsing splitValue[4]")
 		return
 	}
 	extendedStats = true
@@ -465,20 +475,20 @@ func parseMetricsLatencyStats(fieldKey string, fieldValue string) (cmd string, p
 	percentileMap = map[float64]float64{}
 
 	if !strings.HasPrefix(fieldKey, cmdPrefix) {
-		errorOut = errors.New("Invalid fieldKey")
+		errorOut = errors.New("invalid fieldKey")
 		return
 	}
 	cmd = strings.TrimPrefix(fieldKey, cmdPrefix)
 	splitValue := strings.Split(fieldValue, ",")
 	splitLen := len(splitValue)
 	if splitLen < 1 {
-		errorOut = errors.New("Invalid fieldValue")
+		errorOut = errors.New("invalid fieldValue")
 		return
 	}
 	for pos, kv := range splitValue {
 		percentile, value, err := extractPercentileVal(kv)
 		if err != nil {
-			errorOut = fmt.Errorf("Invalid splitValue[%d]", pos)
+			errorOut = fmt.Errorf("invalid splitValue[%d]", pos)
 			return
 		}
 		percentileMap[percentile] = value
@@ -500,13 +510,13 @@ func parseMetricsErrorStats(fieldKey string, fieldValue string) (errorType strin
 	const prefix = "errorstat_"
 
 	if !strings.HasPrefix(fieldKey, prefix) {
-		errorOut = errors.New("Invalid fieldKey. errorstat_ prefix not present")
+		errorOut = errors.New("invalid fieldKey. errorstat_ prefix not present")
 		return
 	}
 	errorType = strings.TrimPrefix(fieldKey, prefix)
 	count, err := extractVal(fieldValue)
 	if err != nil {
-		errorOut = errors.New("Invalid error type on splitValue[0]")
+		errorOut = errors.New("invalid error type on splitValue[0]")
 		return
 	}
 	return
diff --git a/exporter/keys.go b/exporter/keys.go
index da10a2f..499a6d2 100644
--- a/exporter/keys.go
+++ b/exporter/keys.go
@@ -83,18 +83,28 @@ func (e *Exporter) getKeyInfo(ch chan<- prometheus.Metric, c redis.Conn, dbLabel
 	}
 }
 
-func (e *Exporter) extractCheckKeyMetrics(ch chan<- prometheus.Metric, c redis.Conn) {
+func (e *Exporter) extractCheckKeyMetrics(ch chan<- prometheus.Metric, redisClient redis.Conn) error {
+	c := redisClient
+
+	if e.options.IsCluster {
+		cc, err := e.connectToRedisCluster()
+		if err != nil {
+			return fmt.Errorf("Couldn't connect to redis cluster, err: %s", err)
+		}
+		defer cc.Close()
+
+		c = cc
+	}
+
 	keys, err := parseKeyArg(e.options.CheckKeys)
 	if err != nil {
-		log.Errorf("Couldn't parse check-keys: %#v", err)
-		return
+		return fmt.Errorf("Couldn't parse check-keys: %w", err)
 	}
 	log.Debugf("keys: %#v", keys)
 
 	singleKeys, err := parseKeyArg(e.options.CheckSingleKeys)
 	if err != nil {
-		log.Errorf("Couldn't parse check-single-keys: %#v", err)
-		return
+		return fmt.Errorf("Couldn't parse check-single-keys: %w", err)
 	}
 	log.Debugf("e.singleKeys: %#v", singleKeys)
 
@@ -119,6 +129,7 @@ func (e *Exporter) extractCheckKeyMetrics(ch chan<- prometheus.Metric, c redis.C
 	} else {
 		e.extractCheckKeyMetricsPipelined(ch, c, allKeys)
 	}
+	return nil
 }
 
 func (e *Exporter) extractCheckKeyMetricsPipelined(ch chan<- prometheus.Metric, c redis.Conn, allKeys []dbKeyPair) {
@@ -197,7 +208,7 @@ func (e *Exporter) extractCheckKeyMetricsPipelined(ch chan<- prometheus.Metric,
 			}
 			memUsageInBytes, err := redis.Int64(c.Receive())
 			if err != nil {
-				log.Errorf("key: [%s] - memUsageInBytes Receive() err: %s", keyName, err)
+				// log.Errorf("key: [%s] - memUsageInBytes Receive() err: %s", keyName, err)
 				continue
 			}
 
@@ -475,7 +486,7 @@ func parseKeyArg(keysArgString string) (keys []dbKeyPair, err error) {
 
 		number, err := strconv.Atoi(db)
 		if err != nil || number < 0 {
-			return keys, fmt.Errorf("Invalid database index for db \"%s\": %s", db, err)
+			return keys, fmt.Errorf("invalid database index for db \"%s\": %s", db, err)
 		}
 
 		keys = append(keys, dbKeyPair{db, key})
@@ -487,7 +498,7 @@ func parseKeyArg(keysArgString string) (keys []dbKeyPair, err error) {
 // This function was adapted from: https://github.com/reisinger/examples-redigo
 func scanKeys(c redis.Conn, pattern string, count int64) (keys []interface{}, err error) {
 	if pattern == "" {
-		return keys, fmt.Errorf("Pattern shouldn't be empty")
+		return keys, fmt.Errorf("pattern shouldn't be empty")
 	}
 
 	iter := 0
diff --git a/exporter/redis.go b/exporter/redis.go
index cbf4ff9..15bc694 100644
--- a/exporter/redis.go
+++ b/exporter/redis.go
@@ -120,20 +120,20 @@ func (e *Exporter) connectToRedisCluster() (redis.Conn, error) {
 	log.Debugf("Running refresh on cluster object")
 	if err := cluster.Refresh(); err != nil {
 		log.Errorf("Cluster refresh failed: %v", err)
-		return nil, fmt.Errorf("Cluster refresh failed: %w", err)
+		return nil, fmt.Errorf("cluster refresh failed: %w", err)
 	}
 
 	log.Debugf("Creating redis connection object")
 	conn, err := cluster.Dial()
 	if err != nil {
 		log.Errorf("Dial failed: %v", err)
-		return nil, fmt.Errorf("Dial failed: %w", err)
+		return nil, fmt.Errorf("dial failed: %w", err)
 	}
 
 	c, err := redisc.RetryConn(conn, 10, 100*time.Millisecond)
 	if err != nil {
 		log.Errorf("RetryConn failed: %v", err)
-		return nil, fmt.Errorf("RetryConn failed: %w", err)
+		return nil, fmt.Errorf("retryConn failed: %w", err)
 	}
 
 	return c, err
diff --git a/main.go b/main.go
index 1eac5f4..1b86645 100644
--- a/main.go
+++ b/main.go
@@ -99,7 +99,8 @@ 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")
-		skipTLSVerification            = flag.Bool("skip-tls-verification", getEnvBool("REDIS_EXPORTER_SKIP_TLS_VERIFICATION", false), "Whether to to skip TLS verification")
+		skipTLSVerification            = flag.Bool("skip-tls-verification", getEnvBool("REDIS_EXPORTER_SKIP_TLS_VERIFICATION", false), "Whether 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")
 		basicAuthPassword              = flag.String("basic-auth-password", getEnv("REDIS_EXPORTER_BASIC_AUTH_PASSWORD", ""), "Password for basic authentication")
 	)
@@ -188,6 +189,7 @@ func main() {
 			InclModulesMetrics:             *inclModulesMetrics,
 			ExportClientList:               *exportClientList,
 			ExportClientsInclPort:          *exportClientPort,
+			SkipCheckKeysForRoleMaster:     *skipCheckKeysForRoleMaster,
 			SkipTLSVerification:            *skipTLSVerification,
 			ClientCertFile:                 *tlsClientCertFile,
 			ClientKeyFile:                  *tlsClientKeyFile,



Test patch:
diff --git a/exporter/exporter_test.go b/exporter/exporter_test.go
index 9d8ddb4..1394bae 100644
--- a/exporter/exporter_test.go
+++ b/exporter/exporter_test.go
@@ -24,13 +24,12 @@ import (
 	log "github.com/sirupsen/logrus"
 )
 
-var (
-	dbNumStr           = "11"
-	altDBNumStr        = "12"
-	anotherAltDbNumStr = "14"
-
+const (
+	dbNumStr        = "11"
+	altDBNumStr     = "12"
 	invalidDBNumStr = "16"
-	dbNumStrFull    = fmt.Sprintf("db%s", dbNumStr)
+
+	anotherAltDbNumStr = "14"
 )
 
 const (
@@ -44,11 +43,6 @@ const (
 )
 
 var (
-	testKeySingleString string
-	testKeys            []string
-	testKeysExpiring    []string
-	testKeysList        []string
-
 	AllTestKeys = []string{
 		TestKeysSetName, TestKeysZSetName,
 		TestKeysStreamName,
@@ -57,6 +51,21 @@ var (
 	}
 )
 
+var (
+	testKeys         []string
+	testKeysExpiring []string
+	testKeysList     []string
+
+	dbNumStrFull = fmt.Sprintf("db%s", dbNumStr)
+)
+
+var (
+	TestKeyNameSingleString = "" // initialized with a timestamp at runtime
+	TestKeyNameSet          = "test-set"
+	TestKeyNameStream       = "test-stream"
+	TestKeyNameHll          = "test-hll"
+)
+
 func getTestExporter() *Exporter {
 	return getTestExporterWithOptions(Options{Namespace: "test", Registry: prometheus.NewRegistry()})
 }
@@ -111,30 +120,30 @@ func setupKeys(t *testing.T, c redis.Conn, dbNum string) error {
 		}
 	}
 
-	if _, err := doRedisCmd(c, "PFADD", TestKeysHllName, "val1"); err != nil {
+	if _, err := c.Do("PFADD", TestKeyNameHll, "val1"); err != nil {
 		t.Errorf("PFADD err: %s", err)
 		return err
 	}
-	if _, err := doRedisCmd(c, "PFADD", TestKeysHllName, "val22"); err != nil {
+	if _, err := c.Do("PFADD", TestKeyNameHll, "val22"); err != nil {
 		t.Errorf("PFADD err: %s", err)
 		return err
 	}
-	if _, err := doRedisCmd(c, "PFADD", TestKeysHllName, "val333"); err != nil {
+	if _, err := c.Do("PFADD", TestKeyNameHll, "val333"); err != nil {
 		t.Errorf("PFADD err: %s", err)
 		return err
 	}
 
-	if _, err := doRedisCmd(c, "SADD", TestKeysSetName, "test-val-1"); err != nil {
+	if _, err := c.Do("SADD", TestKeyNameSet, "test-val-1"); err != nil {
 		t.Errorf("SADD err: %s", err)
 		return err
 	}
-	if _, err := doRedisCmd(c, "SADD", TestKeysSetName, "test-val-2"); err != nil {
+	if _, err := c.Do("SADD", TestKeyNameSet, "test-val-2"); err != nil {
 		t.Errorf("SADD err: %s", err)
 		return err
 	}
 
-	if _, err := doRedisCmd(c, "ZADD", TestKeysZSetName, "12", "test-zzzval-1"); err != nil {
-		t.Errorf("ZADD err: %s", err)
+	if _, err := c.Do("SET", TestKeyNameSingleString, "this-is-a-string"); err != nil {
+		t.Errorf("PFADD err: %s", err)
 		return err
 	}
 	if _, err := doRedisCmd(c, "ZADD", TestKeysZSetName, "23", "test-zzzval-2"); err != nil {
@@ -146,8 +155,8 @@ func setupKeys(t *testing.T, c redis.Conn, dbNum string) error {
 		return err
 	}
 
-	if _, err := doRedisCmd(c, "SET", testKeySingleString, "this-is-a-string"); err != nil {
-		t.Errorf("SET %s err: %s", testKeySingleString, err)
+	if _, err := doRedisCmd(c, "SET", TestKeyNameSingleString, "this-is-a-string"); err != nil {
+		t.Errorf("SET %s err: %s", TestKeyNameSingleString, err)
 		return err
 	}
 
@@ -173,17 +182,15 @@ func setupKeys(t *testing.T, c redis.Conn, dbNum string) error {
 	}
 
 	// Create test streams
-	doRedisCmd(c, "XGROUP", "CREATE", TestKeysStreamName, TestKeyGroup1, "$", "MKSTREAM")
-	doRedisCmd(c, "XGROUP", "CREATE", TestKeysStreamName, TestKeyGroup2, "$", "MKSTREAM")
-	doRedisCmd(c, "XADD", TestKeysStreamName, TestStreamTimestamps[0], "field_1", "str_1")
-	doRedisCmd(c, "XADD", TestKeysStreamName, TestStreamTimestamps[1], "field_2", "str_2")
+	c.Do("XGROUP", "CREATE", TestKeyNameStream, "test_group_1", "$", "MKSTREAM")
+	c.Do("XGROUP", "CREATE", TestKeyNameStream, "test_group_2", "$", "MKSTREAM")
+	c.Do("XADD", TestKeyNameStream, TestStreamTimestamps[0], "field_1", "str_1")
+	c.Do("XADD", TestKeyNameStream, TestStreamTimestamps[1], "field_2", "str_2")
 
 	// Process messages to assign Consumers to their groups
-	doRedisCmd(c, "XREADGROUP", "GROUP", TestKeyGroup1, "test_consumer_1", "COUNT", "1", "STREAMS", TestKeysStreamName, ">")
-	doRedisCmd(c, "XREADGROUP", "GROUP", TestKeyGroup1, "test_consumer_2", "COUNT", "1", "STREAMS", TestKeysStreamName, ">")
-	doRedisCmd(c, "XREADGROUP", "GROUP", TestKeyGroup2, "test_consumer_1", "COUNT", "1", "STREAMS", TestKeysStreamName, "0")
-
-	t.Logf("setupKeys %s - DONE", dbNum)
+	c.Do("XREADGROUP", "GROUP", "test_group_1", "test_consumer_1", "COUNT", "1", "STREAMS", TestKeyNameStream, ">")
+	c.Do("XREADGROUP", "GROUP", "test_group_1", "test_consumer_2", "COUNT", "1", "STREAMS", TestKeyNameStream, ">")
+	c.Do("XREADGROUP", "GROUP", "test_group_2", "test_consumer_1", "COUNT", "1", "STREAMS", TestKeyNameStream, "0")
 
 	time.Sleep(time.Millisecond * 100)
 	return nil
@@ -198,6 +205,19 @@ func deleteKeys(c redis.Conn, dbNum string) {
 	for _, key := range AllTestKeys {
 		doRedisCmd(c, "DEL", key)
 	}
+
+	for _, key := range testKeysExpiring {
+		c.Do("DEL", key)
+	}
+
+	for _, key := range testKeysList {
+		c.Do("DEL", key)
+	}
+
+	c.Do("DEL", TestKeyNameHll)
+	c.Do("DEL", TestKeyNameSet)
+	c.Do("DEL", TestKeyNameStream)
+	c.Do("DEL", TestKeyNameSingleString)
 }
 
 func setupTestKeys(t *testing.T, uri string) {
@@ -273,10 +293,11 @@ func deleteTestKeys(t *testing.T, addr string) error {
 	return nil
 }
 
-func deleteTestKeysCluster(addr string) error {
+func deleteTestKeysCluster(t *testing.T, addr string) error {
 	e, _ := NewRedisExporter(addr, Options{})
 	c, err := e.connectToRedisCluster()
 	if err != nil {
+		t.Errorf("couldn't setup redis CLUSTER, err: %s ", err)
 		return err
 	}
 
@@ -433,15 +454,9 @@ func TestKeysReset(t *testing.T) {
 	setupTestKeys(t, os.Getenv("TEST_REDIS_URI"))
 	defer deleteTestKeys(t, os.Getenv("TEST_REDIS_URI"))
 
-	chM := make(chan prometheus.Metric, 10000)
-	go func() {
-		e.Collect(chM)
-		close(chM)
-	}()
-
 	body := downloadURL(t, ts.URL+"/metrics")
 	if !strings.Contains(body, testKeys[0]) {
-		t.Errorf("Did not found key %q\n%s", testKeys[0], body)
+		t.Errorf("Did not find key %q\n%s", testKeys[0], body)
 	}
 
 	deleteTestKeys(t, os.Getenv("TEST_REDIS_URI"))
@@ -538,15 +553,14 @@ func init() {
 		testKeys = append(testKeys, fmt.Sprintf("key_%s_%d", n, testTimestamp))
 	}
 
-	testKeySingleString = fmt.Sprintf("key_string_%d", testTimestamp)
-	AllTestKeys = append(AllTestKeys, testKeySingleString)
-
+	TestKeyNameSingleString = fmt.Sprintf("key_string_%d", testTimestamp)
 	testKeysList = append(testKeysList, "test_beatles_list")
 
 	for _, n := range []string{"A.J.", "Howie", "Nick", "Kevin", "Brian"} {
 		testKeysExpiring = append(testKeysExpiring, fmt.Sprintf("key_exp_%s_%d", n, testTimestamp))
 	}
 
+	AllTestKeys = append(AllTestKeys, TestKeyNameSingleString)
 	AllTestKeys = append(AllTestKeys, testKeys...)
 	AllTestKeys = append(AllTestKeys, testKeysList...)
 	AllTestKeys = append(AllTestKeys, testKeysExpiring...)
diff --git a/exporter/http_test.go b/exporter/http_test.go
index db0d0aa..fcbfd53 100644
--- a/exporter/http_test.go
+++ b/exporter/http_test.go
@@ -28,7 +28,7 @@ func TestHTTPScrapeMetricsEndpoints(t *testing.T) {
 	defer deleteTestKeys(t, os.Getenv("TEST_PWD_REDIS_URI"))
 
 	csk := dbNumStrFull + "=" + url.QueryEscape(testKeys[0]) // check-single-keys
-	css := dbNumStrFull + "=" + TestKeysStreamName           // check-single-streams
+	css := dbNumStrFull + "=" + TestKeyNameStream            // check-single-streams
 	cntk := dbNumStrFull + "=" + testKeys[0] + "*"           // count-keys
 
 	u, err := url.Parse(os.Getenv("TEST_REDIS_URI"))
@@ -240,7 +240,7 @@ func TestSimultaneousMetricsHttpRequests(t *testing.T) {
 		os.Getenv("TEST_REDIS6_URI"),
 		os.Getenv("TEST_REDIS_MODULES_URI"),
 
-		// tile38 & Cluster need to be last in this list so we can identify them when selected, down in line 229
+		// tile38 & Cluster need to be last in this list, so we can identify them when selected, down in line 229
 		os.Getenv("TEST_REDIS_CLUSTER_MASTER_URI"),
 		os.Getenv("TEST_REDIS_CLUSTER_SLAVE_URI"),
 		os.Getenv("TEST_TILE38_URI"),
@@ -262,7 +262,7 @@ func TestSimultaneousMetricsHttpRequests(t *testing.T) {
 				v.Add("target", target)
 
 				// not appending this param for Tile38 and cluster (the last two in the list)
-				// Tile38 & cluster don't support the SELECT command so this test will fail and spam the logs
+				// Tile38 & cluster don't support the SELECT command, so this test will fail and spam the logs
 				if uriIdx < len(uris)-3 {
 					v.Add("check-single-keys", dbNumStrFull+"="+url.QueryEscape(testKeys[0]))
 				}
@@ -360,7 +360,7 @@ func TestHttpDiscoverClusterNodesHandlers(t *testing.T) {
 		},
 		{
 			addr:      nonClusterAddr,
-			want:      "ouldn't connect to redis cluster: Cluster refresh failed",
+			want:      "ouldn't connect to redis cluster: cluster refresh failed",
 			isCluster: true,
 		},
 		{
@@ -370,7 +370,7 @@ func TestHttpDiscoverClusterNodesHandlers(t *testing.T) {
 		},
 		{
 			addr:      "doesnt-exist:9876",
-			want:      "Couldn't connect to redis cluster: Cluster refresh failed: redisc: all nodes failed",
+			want:      "Couldn't connect to redis cluster: cluster refresh failed: redisc: all nodes failed",
 			isCluster: true,
 		},
 	}
diff --git a/exporter/info_test.go b/exporter/info_test.go
index addf36b..df82454 100644
--- a/exporter/info_test.go
+++ b/exporter/info_test.go
@@ -141,12 +141,6 @@ func TestClusterMaster(t *testing.T) {
 	ts := httptest.NewServer(e)
 	defer ts.Close()
 
-	chM := make(chan prometheus.Metric, 10000)
-	go func() {
-		e.Collect(chM)
-		close(chM)
-	}()
-
 	body := downloadURL(t, ts.URL+"/metrics")
 	log.Debugf("master - body: %s", body)
 	for _, want := range []string{
@@ -159,6 +153,54 @@ func TestClusterMaster(t *testing.T) {
 	}
 }
 
+func TestClusterSkipCheckKeysIfMaster(t *testing.T) {
+	uriMaster := os.Getenv("TEST_REDIS_CLUSTER_MASTER_URI")
+	uriSlave := os.Getenv("TEST_REDIS_CLUSTER_SLAVE_URI")
+	if uriMaster == "" || uriSlave == "" {
+		t.Skipf("TEST_REDIS_CLUSTER_MASTER_URI or slave not set - skipping")
+	}
+
+	setupTestKeysCluster(t, uriMaster)
+	defer deleteTestKeysCluster(t, uriMaster)
+
+	for _, uri := range []string{uriMaster, uriSlave} {
+		for _, skip := range []bool{true, false} {
+			e, _ := NewRedisExporter(
+				uri,
+				Options{Namespace: "test",
+					Registry:                   prometheus.NewRegistry(),
+					CheckKeys:                  TestKeyNameHll,
+					SkipCheckKeysForRoleMaster: skip,
+					IsCluster:                  true,
+				})
+			ts := httptest.NewServer(e)
+
+			body := downloadURL(t, ts.URL+"/metrics")
+
+			expectedMetricPresent := true
+			if skip && uri == uriMaster {
+				expectedMetricPresent = false
+			}
+			t.Logf("skip: %#v  uri: %s    uri == uriMaster: %#v", skip, uri, uri == uriMaster)
+			t.Logf("expectedMetricPresent: %#v", expectedMetricPresent)
+
+			want := `test_key_size{db="db0",key="test-hll"} 3`
+
+			if expectedMetricPresent {
+				if !strings.Contains(body, want) {
+					t.Fatalf("expectedMetricPresent but missing. metric: %s   body: %s\n", want, body)
+				}
+			} else {
+				if strings.Contains(body, want) {
+					t.Fatalf("should have skipped it but found it, body:\n%s", body)
+				}
+			}
+
+			ts.Close()
+		}
+	}
+}
+
 func TestClusterSlave(t *testing.T) {
 	if os.Getenv("TEST_REDIS_CLUSTER_SLAVE_URI") == "" {
 		t.Skipf("TEST_REDIS_CLUSTER_SLAVE_URI not set - skipping")
@@ -169,12 +211,6 @@ func TestClusterSlave(t *testing.T) {
 	ts := httptest.NewServer(e)
 	defer ts.Close()
 
-	chM := make(chan prometheus.Metric, 10000)
-	go func() {
-		e.Collect(chM)
-		close(chM)
-	}()
-
 	body := downloadURL(t, ts.URL+"/metrics")
 	log.Debugf("slave - body: %s", body)
 	for _, want := range []string{
diff --git a/exporter/keys_test.go b/exporter/keys_test.go
index 55b4a81..3284555 100644
--- a/exporter/keys_test.go
+++ b/exporter/keys_test.go
@@ -35,12 +35,6 @@ func TestKeyValuesAndSizes(t *testing.T) {
 	setupTestKeys(t, os.Getenv("TEST_REDIS_URI"))
 	defer deleteTestKeys(t, os.Getenv("TEST_REDIS_URI"))
 
-	chM := make(chan prometheus.Metric, 10000)
-	go func() {
-		e.Collect(chM)
-		close(chM)
-	}()
-
 	body := downloadURL(t, ts.URL+"/metrics")
 	for _, want := range []string{
 		"test_key_size",
@@ -62,18 +56,12 @@ func TestKeyValuesAsLabel(t *testing.T) {
 			os.Getenv("TEST_REDIS_URI"),
 			Options{
 				Namespace:                 "test",
-				CheckSingleKeys:           dbNumStrFull + "=" + url.QueryEscape(testKeySingleString),
+				CheckSingleKeys:           dbNumStrFull + "=" + url.QueryEscape(TestKeyNameSingleString),
 				DisableExportingKeyValues: exc,
 				Registry:                  prometheus.NewRegistry()},
 		)
 		ts := httptest.NewServer(e)
 
-		chM := make(chan prometheus.Metric, 10000)
-		go func() {
-			e.Collect(chM)
-			close(chM)
-		}()
-
 		body := downloadURL(t, ts.URL+"/metrics")
 		for _, match := range []string{
 			"key_value_as_string",
@@ -95,7 +83,7 @@ func TestClusterKeyValuesAndSizes(t *testing.T) {
 		t.Skipf("Skipping TestClusterKeyValuesAndSizes, don't have env var TEST_REDIS_CLUSTER_MASTER_URI")
 	}
 	setupTestKeysCluster(t, clusterUri)
-	defer deleteTestKeysCluster(clusterUri)
+	defer deleteTestKeysCluster(t, clusterUri)
 
 	for _, disableExportingValues := range []bool{true, false} {
 		e, _ := NewRedisExporter(
@@ -105,7 +93,7 @@ func TestClusterKeyValuesAndSizes(t *testing.T) {
 				CheckSingleKeys: fmt.Sprintf(
 					"%s=%s,%s=%s",
 					dbNumStrFull, url.QueryEscape(testKeys[0]),
-					dbNumStrFull, url.QueryEscape(TestKeysSetName),
+					dbNumStrFull, url.QueryEscape(TestKeyNameSet),
 				),
 				IsCluster: true,
 			},
@@ -371,7 +359,7 @@ func TestScanKeys(t *testing.T) {
 		got, err := redis.Strings(scanKeys(c, pattern, count))
 		if err != nil {
 			t.Logf("\"Passed\" expected, got error: %#v", err)
-			if pattern == "" && err.Error() != "Pattern shouldn't be empty" {
+			if pattern == "" && err.Error() != "pattern shouldn't be empty" {
 				t.Errorf("\"Empty pattern\" error message expected, but got: %s", err.Error())
 			}
 		} else {
@@ -670,9 +658,9 @@ func TestCheckKeysMultipleDBs(t *testing.T) {
 		Options{Namespace: "test",
 			CheckSingleKeys: "single," +
 				dbNumStr + "=" + testKeys[0] + "," +
-				dbNumStr + "=" + testKeySingleString + "," +
+				dbNumStr + "=" + TestKeyNameSingleString + "," +
 				altDBNumStr + "=" + TestKeysHllName + "," +
-				altDBNumStr + "=" + testKeySingleString + "," +
+				altDBNumStr + "=" + TestKeyNameSingleString + "," +
 				anotherAltDbNumStr + "=" + testKeys[0],
 			CheckKeys:          dbNumStr + "=" + "test*",
 			CheckKeysBatchSize: 1000,
@@ -689,18 +677,18 @@ func TestCheckKeysMultipleDBs(t *testing.T) {
 	for _, k := range []string{
 		`test_key_size{db="db0",key="single"} 0`, // non-existent key
 
-		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 16`, dbNumStr, testKeySingleString),
-		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 3`, dbNumStr, TestKeysZSetName),
+		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 16`, dbNumStr, TestKeyNameSingleString),
+		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 2`, dbNumStr, TestKeysZSetName),
 		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 4`, dbNumStr, TestKeysHashName),
 		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 3`, altDBNumStr, TestKeysHllName),
-		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 16`, altDBNumStr, testKeySingleString),
+		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 16`, altDBNumStr, TestKeyNameSingleString),
 		fmt.Sprintf(`test_key_size{db="db%s",key="%s"} 7`, anotherAltDbNumStr, testKeys[0]),
 
 		fmt.Sprintf(`test_key_value{db="db%s",key="%s"} 1234.56`, dbNumStr, testKeys[0]),
 		fmt.Sprintf(`test_key_value{db="db%s",key="%s"} 1234.56`, anotherAltDbNumStr, testKeys[0]),
 
-		fmt.Sprintf(`key_memory_usage_bytes{db="db%s",key="%s"}`, dbNumStr, testKeySingleString),
-		fmt.Sprintf(`key_memory_usage_bytes{db="db%s",key="%s"}`, altDBNumStr, testKeySingleString),
+		fmt.Sprintf(`key_memory_usage_bytes{db="db%s",key="%s"}`, dbNumStr, TestKeyNameSingleString),
+		fmt.Sprintf(`key_memory_usage_bytes{db="db%s",key="%s"}`, altDBNumStr, TestKeyNameSingleString),
 		fmt.Sprintf(`key_memory_usage_bytes{db="db%s",key="%s"}`, anotherAltDbNumStr, testKeys[0]),
 	} {
 		if !strings.Contains(body, k) {
@@ -728,7 +716,7 @@ func TestClusterGetKeyInfo(t *testing.T) {
 	defer ts.Close()
 
 	setupTestKeysCluster(t, clusterUri)
-	defer deleteTestKeysCluster(clusterUri)
+	defer deleteTestKeysCluster(t, clusterUri)
 
 	body := downloadURL(t, ts.URL+"/metrics")
 	for _, want := range []string{
diff --git a/exporter/lua_test.go b/exporter/lua_test.go
index f47e28f..d3eb936 100644
--- a/exporter/lua_test.go
+++ b/exporter/lua_test.go
@@ -60,12 +60,6 @@ func TestLuaScript(t *testing.T) {
 			ts := httptest.NewServer(e)
 			defer ts.Close()
 
-			chM := make(chan prometheus.Metric, 10000)
-			go func() {
-				e.Collect(chM)
-				close(chM)
-			}()
-
 			body := downloadURL(t, ts.URL+"/metrics")
 
 			for _, want := range tst.Wants {
diff --git a/exporter/redis_test.go b/exporter/redis_test.go
index 9415453..db04a7c 100644
--- a/exporter/redis_test.go
+++ b/exporter/redis_test.go
@@ -92,12 +92,6 @@ func TestPasswordProtectedInstance(t *testing.T) {
 			ts := httptest.NewServer(e)
 			defer ts.Close()
 
-			chM := make(chan prometheus.Metric, 10000)
-			go func() {
-				e.Collect(chM)
-				close(chM)
-			}()
-
 			body := downloadURL(t, ts.URL+"/metrics")
 			if !strings.Contains(body, "test_up 1") {
 				t.Errorf(`%s - response to /metric doesn't contain "test_up 1"`, tst)
@@ -118,12 +112,6 @@ func TestPasswordInvalid(t *testing.T) {
 	ts := httptest.NewServer(e)
 	defer ts.Close()
 
-	chM := make(chan prometheus.Metric, 10000)
-	go func() {
-		e.Collect(chM)
-		close(chM)
-	}()
-
 	want := `test_exporter_last_scrape_error{err="dial redis: unknown network redis"} 1`
 	body := downloadURL(t, ts.URL+"/metrics")
 	if !strings.Contains(body, want) {
diff --git a/exporter/streams_test.go b/exporter/streams_test.go
index 976d2b1..cadec3e 100644
--- a/exporter/streams_test.go
+++ b/exporter/streams_test.go
@@ -56,7 +56,7 @@ func TestStreamsGetStreamInfo(t *testing.T) {
 	tsts := []scanStreamFixture{
 		{
 			name:   "Stream test",
-			stream: TestKeysStreamName,
+			stream: TestKeyNameStream,
 			streamInfo: streamInfo{
 				Length:         2,
 				RadixTreeKeys:  1,
@@ -123,7 +123,7 @@ func TestStreamsGetStreamInfoUsingValKey7(t *testing.T) {
 	tsts := []scanStreamFixture{
 		{
 			name:   "Stream test",
-			stream: TestKeysStreamName,
+			stream: TestKeyNameStream,
 			streamInfo: streamInfo{
 				Length:         2,
 				RadixTreeKeys:  1,
@@ -496,7 +496,7 @@ func TestStreamsExtractStreamMetrics(t *testing.T) {
 	addr := os.Getenv("TEST_REDIS_URI")
 	e, _ := NewRedisExporter(
 		addr,
-		Options{Namespace: "test", CheckSingleStreams: dbNumStrFull + "=" + TestKeysStreamName},
+		Options{Namespace: "test", CheckSingleStreams: dbNumStrFull + "=" + TestKeyNameStream},
 	)
 	c, err := redis.DialURL(addr)
 	if err != nil {
@@ -554,7 +554,7 @@ func TestStreamsExtractStreamMetricsExcludeConsumer(t *testing.T) {
 	addr := os.Getenv("TEST_REDIS_URI")
 	e, _ := NewRedisExporter(
 		addr,
-		Options{Namespace: "test", CheckSingleStreams: dbNumStrFull + "=" + TestKeysStreamName, StreamsExcludeConsumerMetrics: true},
+		Options{Namespace: "test", CheckSingleStreams: dbNumStrFull + "=" + TestKeyNameStream, StreamsExcludeConsumerMetrics: true},
 	)
 	c, err := redis.DialURL(addr)
 	if err != nil {