From dcb55eda210d949aa6a39151f6465fb85f4a29b8 Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Wed, 5 Jun 2024 15:35:48 +0200 Subject: [PATCH 1/3] fix(redis): Support multiple keys with cache_prefixes --- .../integrations/redis/modules/caches.py | 8 +++-- .../redis/test_redis_cache_module.py | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/sentry_sdk/integrations/redis/modules/caches.py b/sentry_sdk/integrations/redis/modules/caches.py index 754b2118b8..0335724f17 100644 --- a/sentry_sdk/integrations/redis/modules/caches.py +++ b/sentry_sdk/integrations/redis/modules/caches.py @@ -31,12 +31,14 @@ def _compile_cache_span_properties(redis_command, args, kwargs, integration): # type: (str, tuple[Any, ...], dict[str, Any], RedisIntegration) -> dict[str, Any] key = _get_safe_key(redis_command, args, kwargs) key_as_string = _key_as_string(key) + keys_as_string = key_as_string.split(", ") is_cache_key = False for prefix in integration.cache_prefixes: - if key_as_string.startswith(prefix): - is_cache_key = True - break + for kee in keys_as_string: + if kee.startswith(prefix): + is_cache_key = True + break value = None if redis_command.lower() in SET_COMMANDS: diff --git a/tests/integrations/redis/test_redis_cache_module.py b/tests/integrations/redis/test_redis_cache_module.py index 1fbc6dcf15..90b5ca48e7 100644 --- a/tests/integrations/redis/test_redis_cache_module.py +++ b/tests/integrations/redis/test_redis_cache_module.py @@ -198,6 +198,41 @@ def test_cache_data(sentry_init, capture_events): assert spans[5]["op"] == "db.redis" # we ignore db spans in this test. +def test_cache_prefixes(sentry_init, capture_events): + sentry_init( + integrations=[ + RedisIntegration( + cache_prefixes=["yes"], + ), + ], + traces_sample_rate=1.0, + ) + events = capture_events() + + connection = FakeStrictRedis() + with sentry_sdk.start_transaction(): + connection.mget("yes", "no") + connection.mget("no", 1, "yes") + connection.mget("no", "yes.1", "yes.2") + connection.mget("no.1", "no.2", "no.3") + connection.mget("no.1", "no.2", "no.actually.yes") + connection.mget(b"no.3", b"yes.5") + connection.mget(uuid.uuid4().bytes) + + (event,) = events + + spans = event["spans"] + assert len(spans) == 11 # 7 db spans + 4 cache spans + + cache_spans = [span for span in spans if span["op"] == "cache.get"] + assert len(cache_spans) == 4 + + assert cache_spans[0]["description"] == "yes, no" + assert cache_spans[1]["description"] == "no, 1, yes" + assert cache_spans[2]["description"] == "no, yes.1, yes.2" + assert cache_spans[3]["description"] == "no.3, yes.5" + + @pytest.mark.parametrize( "method_name,args,kwargs,expected_key", [ From 7deff9c9a57cbdf0fc0d2fca62e8741027f7001d Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Wed, 5 Jun 2024 15:38:08 +0200 Subject: [PATCH 2/3] early break --- sentry_sdk/integrations/redis/modules/caches.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sentry_sdk/integrations/redis/modules/caches.py b/sentry_sdk/integrations/redis/modules/caches.py index 0335724f17..8d3469d141 100644 --- a/sentry_sdk/integrations/redis/modules/caches.py +++ b/sentry_sdk/integrations/redis/modules/caches.py @@ -39,6 +39,8 @@ def _compile_cache_span_properties(redis_command, args, kwargs, integration): if kee.startswith(prefix): is_cache_key = True break + if is_cache_key: + break value = None if redis_command.lower() in SET_COMMANDS: From 7013f2c0784fbda49ed078ab5b77b5f4dd4112dc Mon Sep 17 00:00:00 2001 From: Ivana Kellyerova Date: Wed, 5 Jun 2024 15:45:26 +0200 Subject: [PATCH 3/3] more testing --- tests/integrations/redis/test_redis_cache_module.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/integrations/redis/test_redis_cache_module.py b/tests/integrations/redis/test_redis_cache_module.py index 90b5ca48e7..f118aa53f5 100644 --- a/tests/integrations/redis/test_redis_cache_module.py +++ b/tests/integrations/redis/test_redis_cache_module.py @@ -218,19 +218,21 @@ def test_cache_prefixes(sentry_init, capture_events): connection.mget("no.1", "no.2", "no.actually.yes") connection.mget(b"no.3", b"yes.5") connection.mget(uuid.uuid4().bytes) + connection.mget(uuid.uuid4().bytes, "yes") (event,) = events spans = event["spans"] - assert len(spans) == 11 # 7 db spans + 4 cache spans + assert len(spans) == 13 # 8 db spans + 5 cache spans cache_spans = [span for span in spans if span["op"] == "cache.get"] - assert len(cache_spans) == 4 + assert len(cache_spans) == 5 assert cache_spans[0]["description"] == "yes, no" assert cache_spans[1]["description"] == "no, 1, yes" assert cache_spans[2]["description"] == "no, yes.1, yes.2" assert cache_spans[3]["description"] == "no.3, yes.5" + assert cache_spans[4]["description"] == ", yes" @pytest.mark.parametrize(