Skip to content

Commit b6acb83

Browse files
authored
feat(redis): Add counter for commands run (#5345)
1 parent e8e1135 commit b6acb83

File tree

5 files changed

+48
-11
lines changed

5 files changed

+48
-11
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

relay-redis/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ serde = { workspace = true }
3030
tokio = { workspace = true, features = ["time"] }
3131
thiserror = { workspace = true }
3232

33+
relay-statsd = { workspace = true, optional = true }
3334
relay-system = { workspace = true }
3435

3536
[features]
3637
default = []
37-
impl = ["dep:deadpool", "dep:deadpool-redis", "dep:redis"]
38+
impl = ["dep:deadpool", "dep:deadpool-redis", "dep:relay-statsd", "dep:redis"]

relay-redis/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ mod scripts;
2525
#[cfg(feature = "impl")]
2626
pub use self::scripts::*;
2727

28+
#[cfg(feature = "impl")]
29+
mod statsd;
30+
2831
#[cfg(not(feature = "impl"))]
2932
mod noop;
3033

relay-redis/src/pool.rs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ use crate::redis::cluster_async::ClusterConnection;
1010
use crate::redis::{
1111
Cmd, IntoConnectionInfo, Pipeline, RedisError, RedisFuture, RedisResult, Value,
1212
};
13+
use crate::statsd::RedisCounters;
14+
15+
use relay_statsd::metric;
1316

1417
/// A connection pool for Redis cluster deployments.
1518
pub type CustomClusterPool = Pool<CustomClusterManager, CustomClusterConnection>;
@@ -34,12 +37,13 @@ impl<C> TrackedConnection<C> {
3437
}
3538
}
3639

37-
/// Returns `true` when a [`RedisError`] should lead to the [`TrackedConnection`] being detached
40+
/// Returns `true` when the result of a Redis call should lead to the [`TrackedConnection`] being detached
3841
/// from the pool.
3942
///
40-
/// An error leads to the connection being detached if it is unrecoverable.
41-
fn should_be_detached(error: &RedisError) -> bool {
42-
error.is_unrecoverable_error()
43+
/// An `Ok` result never leads to the connection being detached.
44+
/// A [`RedisError`] leads to the connection being detached if it is unrecoverable.
45+
fn should_be_detached<T>(result: Result<T, &RedisError>) -> bool {
46+
result.is_err_and(|error| error.is_unrecoverable_error())
4347
}
4448
}
4549

@@ -48,9 +52,8 @@ impl<C: redis::aio::ConnectionLike + Send> redis::aio::ConnectionLike for Tracke
4852
async move {
4953
let result = self.connection.req_packed_command(cmd).await;
5054

51-
if let Err(error) = &result {
52-
self.detach = self.detach || Self::should_be_detached(error);
53-
}
55+
self.detach |= Self::should_be_detached(result.as_ref());
56+
emit_metrics(result.as_ref());
5457

5558
result
5659
}
@@ -69,9 +72,8 @@ impl<C: redis::aio::ConnectionLike + Send> redis::aio::ConnectionLike for Tracke
6972
.req_packed_commands(cmd, offset, count)
7073
.await;
7174

72-
if let Err(error) = &result {
73-
self.detach = self.detach || Self::should_be_detached(error);
74-
}
75+
self.detach |= Self::should_be_detached(result.as_ref());
76+
emit_metrics(result.as_ref());
7577

7678
result
7779
}
@@ -286,3 +288,16 @@ impl From<Object<CustomSingleManager>> for CustomSingleConnection {
286288
Self(conn)
287289
}
288290
}
291+
292+
fn emit_metrics<T>(result: Result<T, &RedisError>) {
293+
let result = match result {
294+
Ok(_) => "ok",
295+
Err(e) if e.is_timeout() => "timeout",
296+
Err(_) => "error",
297+
};
298+
299+
metric!(
300+
counter(RedisCounters::CommandExecuted) += 1,
301+
result = result,
302+
);
303+
}

relay-redis/src/statsd.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use relay_statsd::CounterMetric;
2+
3+
pub enum RedisCounters {
4+
/// Incremented every time a Redis command or pipeline is run.
5+
///
6+
/// This metric is tagged with:
7+
/// - `result`: The outcome (`ok`, `error`, `timeout`).
8+
CommandExecuted,
9+
}
10+
11+
impl CounterMetric for RedisCounters {
12+
fn name(&self) -> &'static str {
13+
match self {
14+
Self::CommandExecuted => "redis.command_executed",
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)