Skip to content

Commit

Permalink
Redis replica offset (open-telemetry#29565)
Browse files Browse the repository at this point in the history
**Description:** Adds missing metrics for `slave_repl_offset` and adds
an integration test to configure a cluster to test such

**Link to tracking Issue:**
[`6942`](open-telemetry#6942)

**Testing:** `cd receiver/redisreceiver && make mod-integration-test`

**Documentation:** (autogenerated from mdatagen)
  • Loading branch information
hughesjj authored and cparkins committed Feb 1, 2024
1 parent 7fc5f5f commit 3856df0
Show file tree
Hide file tree
Showing 17 changed files with 554 additions and 4 deletions.
27 changes: 27 additions & 0 deletions .chloggen/redis_replica_offset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Use this changelog template to create an entry for release notes.

# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
change_type: enhancement

# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
component: redisreciever

# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
note: adds metric for slave_repl_offset

# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
issues: [6942]

# (Optional) One or more lines of additional information to render under the primary note.
# These lines will be padded with 2 spaces and then inserted directly into the document.
# Use pipe (|) for multiline entries.
subtext: also adds a shell script to set up docker-compose integration test

# If your change doesn't affect end users or the exported elements of any package,
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
# Optional: The change log or logs in which this entry should be included.
# e.g. '[user]' or '[user, api]'
# Include 'user' if the change is relevant to end users.
# Include 'api' if there is a change to a library API.
# Default: '[user]'
change_logs: [user]
8 changes: 8 additions & 0 deletions receiver/redisreceiver/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,14 @@ The value of the maxmemory configuration directive
| ---- | ----------- | ---------- |
| By | Gauge | Int |

### redis.replication.replica_offset

Offset for redis replica

| Unit | Metric Type | Value Type |
| ---- | ----------- | ---------- |
| By | Gauge | Int |

### redis.role

Redis node's role
Expand Down
45 changes: 44 additions & 1 deletion receiver/redisreceiver/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ package redisreceiver

import (
"fmt"
"path/filepath"
"testing"
"time"

"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
Expand All @@ -20,7 +22,7 @@ import (

const redisPort = "6379"

func TestIntegration(t *testing.T) {
func TestIntegrationV6(t *testing.T) {
scraperinttest.NewIntegrationTest(
NewFactory(),
scraperinttest.WithContainerRequest(
Expand All @@ -46,5 +48,46 @@ func TestIntegration(t *testing.T) {
return redisPort
}),
),
scraperinttest.WithExpectedFile(filepath.Join("testdata", "integration", "expected-old.yaml")),
).Run(t)
}

func TestIntegrationV7Cluster(t *testing.T) {
scraperinttest.NewIntegrationTest(
NewFactory(),
scraperinttest.WithContainerRequest(testcontainers.ContainerRequest{
ExposedPorts: []string{
redisPort,
"6380",
"6381",
"6382",
"6383",
"6384",
"6385",
},
FromDockerfile: testcontainers.FromDockerfile{
Context: filepath.Join("testdata", "integration"),
Dockerfile: "Dockerfile.cluster",
},
WaitingFor: wait.ForListeningPort("6385").WithStartupTimeout(30 * time.Second),
}),
scraperinttest.WithCustomConfig(
func(t *testing.T, cfg component.Config, ci *scraperinttest.ContainerInfo) {
rCfg := cfg.(*Config)
// Strictly speaking this is non-deterministic and may not be the right port for one with repl offset
// However, we're using socat and some port forwarding in the Dockerfile to ensure this always points
// to a replica node, so in practice any failures due to cluster node role changes is unlikely
rCfg.Endpoint = fmt.Sprintf("%s:%s", ci.Host(t), ci.MappedPort(t, "6385"))
rCfg.MetricsBuilderConfig.Metrics.RedisReplicationReplicaOffset.Enabled = true
}),
scraperinttest.WithCompareOptions(
pmetrictest.IgnoreMetricValues(),
pmetrictest.IgnoreMetricDataPointsOrder(),
pmetrictest.IgnoreStartTimestamp(),
pmetrictest.IgnoreTimestamp(),
),
scraperinttest.WithExpectedFile(filepath.Join("testdata", "integration", "expected-cluster.yaml")),
scraperinttest.WithCreateContainerTimeout(time.Minute),
scraperinttest.WithCompareTimeout(time.Minute),
).Run(t)
}
4 changes: 4 additions & 0 deletions receiver/redisreceiver/internal/metadata/generated_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 57 additions & 0 deletions receiver/redisreceiver/internal/metadata/generated_metrics.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions receiver/redisreceiver/internal/metadata/generated_metrics_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions receiver/redisreceiver/internal/metadata/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ all_set:
enabled: true
redis.replication.offset:
enabled: true
redis.replication.replica_offset:
enabled: true
redis.role:
enabled: true
redis.slaves.connected:
Expand Down Expand Up @@ -140,6 +142,8 @@ none_set:
enabled: false
redis.replication.offset:
enabled: false
redis.replication.replica_offset:
enabled: false
redis.role:
enabled: false
redis.slaves.connected:
Expand Down
8 changes: 7 additions & 1 deletion receiver/redisreceiver/metadata.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,13 @@ metrics:
gauge:
value_type: int
attributes: [db]

# below are all disabled by default
redis.replication.replica_offset:
enabled: false
description: "Offset for redis replica"
unit: "By"
gauge:
value_type: int
tests:
config:
endpoint: localhost:6379
1 change: 1 addition & 0 deletions receiver/redisreceiver/metric_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func (rs *redisScraper) dataPointRecorders() map[string]any {
"rdb_changes_since_last_save": rs.mb.RecordRedisRdbChangesSinceLastSaveDataPoint,
"rejected_connections": rs.mb.RecordRedisConnectionsRejectedDataPoint,
"repl_backlog_first_byte_offset": rs.mb.RecordRedisReplicationBacklogFirstByteOffsetDataPoint,
"slave_repl_offset": rs.mb.RecordRedisReplicationReplicaOffsetDataPoint,
"total_commands_processed": rs.mb.RecordRedisCommandsProcessedDataPoint,
"total_connections_received": rs.mb.RecordRedisConnectionsReceivedDataPoint,
"total_net_input_bytes": rs.mb.RecordRedisNetInputDataPoint,
Expand Down
4 changes: 2 additions & 2 deletions receiver/redisreceiver/redis_scraper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ func TestRedisRunnable(t *testing.T) {
md, err := runner.Scrape(context.Background())
require.NoError(t, err)
// + 6 because there are two keyspace entries each of which has three metrics
// -1 because maxmemory is by default disabled, so recorder is there, but there won't be data point
assert.Equal(t, len(rs.dataPointRecorders())+6-1, md.DataPointCount())
// -2 because maxmemory and slave_repl_offset is by default disabled, so recorder is there, but there won't be data point
assert.Equal(t, len(rs.dataPointRecorders())+6-2, md.DataPointCount())
rm := md.ResourceMetrics().At(0)
ilm := rm.ScopeMetrics().At(0)
il := ilm.Scope()
Expand Down
31 changes: 31 additions & 0 deletions receiver/redisreceiver/testdata/integration/Dockerfile.cluster
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Use the official Redis image as the base
FROM redis:7.2.3

RUN apt update && apt install --assume-yes socat

# Seems to be an upstream issue with testcontainers or scraperint when using named nodes or clusters, so manually do it
COPY cluster.sh /usr/local/bin/cluster.sh
COPY configure-nodes.sh /usr/local/bin/configure-nodes.sh
COPY redis-cluster.conf /etc/redis-cluster.conf

RUN chown redis:redis /usr/local/bin/cluster.sh
RUN chmod +x /usr/local/bin/cluster.sh

RUN chown redis:redis /usr/local/bin/configure-nodes.sh
RUN chmod +x /usr/local/bin/configure-nodes.sh

RUN configure-nodes.sh
RUN chown redis:redis /etc/redis-cluster*.conf

RUN mkdir -p /var/log/redis
RUN chgrp redis /var/log/redis

EXPOSE 6379
EXPOSE 6380
EXPOSE 6381
EXPOSE 6382
EXPOSE 6383
EXPOSE 6384
EXPOSE 6385
ENTRYPOINT ["cluster.sh"]
CMD ["cluster.sh"]
43 changes: 43 additions & 0 deletions receiver/redisreceiver/testdata/integration/cluster.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/sh -eux
# Copyright The OpenTelemetry Authors
# SPDX-License-Identifier: Apache-2.0


redis-server /etc/redis-cluster-6379.conf && \
redis-server /etc/redis-cluster-6380.conf && \
redis-server /etc/redis-cluster-6381.conf && \
redis-server /etc/redis-cluster-6382.conf && \
redis-server /etc/redis-cluster-6383.conf && \
redis-server /etc/redis-cluster-6384.conf
redis-cli -p 6379 ping
redis-cli -p 6380 ping
redis-cli -p 6381 ping
redis-cli -p 6382 ping
redis-cli -p 6383 ping
redis-cli -p 6384 ping

redis-cli --cluster create localhost:6379 localhost:6380 localhost:6381 localhost:6382 localhost:6383 localhost:6384 --cluster-replicas 1 --cluster-yes
sleep 10s
while true; do
if redis-cli -p 6379 cluster info | grep -q "cluster_state:ok" ; then
break
fi
echo "awaiting for cluster to be ready"
sleep 2
done


# ensure a consistent mapping to a replica on port 6385
REPLICA_PORT=$(redis-cli -p 6379 cluster nodes | grep 'slave' | awk '{print $2}' | cut -d':' -f2 | head -n 1)
REPLICA_PORT=${REPLICA_PORT%@*}
if [ -n "$REPLICA_PORT" ]; then
echo "forwarding from port $REPLICA_PORT to 6385"
#ssh -fNL "6385:127.0.0.1:$REPLICA_PORT" 127.0.0.1
nohup socat tcp-listen:6385,fork,reuseaddr,forever,reuseaddr,keepalive,keepidle=10,keepintvl=10,keepcnt=2 tcp-connect:127.0.0.1:"$REPLICA_PORT" &
else
echo "could not find replica port" 1>&2
exit 1
fi

tail -f /dev/null
#ssh -fNL 6385:localhost:$REPLICA_PORT

0 comments on commit 3856df0

Please sign in to comment.