-
Notifications
You must be signed in to change notification settings - Fork 505
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(integrations): add support for cluster clients from redis sdk
- Loading branch information
Showing
6 changed files
with
229 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import pytest | ||
|
||
pytest.importorskip("redis.cluster") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import pytest | ||
from sentry_sdk import capture_message | ||
from sentry_sdk.consts import SPANDATA | ||
from sentry_sdk.api import start_transaction | ||
from sentry_sdk.integrations.redis import RedisIntegration | ||
|
||
import redis | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def monkeypatch_rediscluster_class(reset_integrations): | ||
pipeline_cls = redis.cluster.ClusterPipeline | ||
redis.cluster.NodesManager.initialize = lambda *_, **__: None | ||
redis.RedisCluster.command = lambda *_: [] | ||
redis.RedisCluster.pipeline = lambda *_, **__: pipeline_cls(None, None) | ||
pipeline_cls.execute = lambda *_, **__: None | ||
redis.RedisCluster.execute_command = lambda *_, **__: None | ||
|
||
|
||
def test_rediscluster_basic(sentry_init, capture_events): | ||
sentry_init(integrations=[RedisIntegration()]) | ||
events = capture_events() | ||
|
||
rc = redis.RedisCluster(host="localhost", port=6379) | ||
rc.get("foobar") | ||
capture_message("hi") | ||
|
||
(event,) = events | ||
(crumb,) = event["breadcrumbs"]["values"] | ||
|
||
assert crumb == { | ||
"category": "redis", | ||
"message": "GET 'foobar'", | ||
"data": { | ||
"db.operation": "GET", | ||
"redis.key": "foobar", | ||
"redis.command": "GET", | ||
"redis.is_cluster": True, | ||
}, | ||
"timestamp": crumb["timestamp"], | ||
"type": "redis", | ||
} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"send_default_pii, expected_first_ten", | ||
[ | ||
(False, ["GET 'foo'", "SET 'bar' [Filtered]", "SET 'baz' [Filtered]"]), | ||
(True, ["GET 'foo'", "SET 'bar' 1", "SET 'baz' 2"]), | ||
], | ||
) | ||
def test_rediscluster_pipeline( | ||
sentry_init, capture_events, send_default_pii, expected_first_ten | ||
): | ||
sentry_init( | ||
integrations=[RedisIntegration()], | ||
traces_sample_rate=1.0, | ||
send_default_pii=send_default_pii, | ||
) | ||
events = capture_events() | ||
|
||
rc = redis.RedisCluster(host="localhost", port=6379) | ||
with start_transaction(): | ||
pipeline = rc.pipeline() | ||
pipeline.get("foo") | ||
pipeline.set("bar", 1) | ||
pipeline.set("baz", 2) | ||
pipeline.execute() | ||
|
||
(event,) = events | ||
(span,) = event["spans"] | ||
assert span["op"] == "db.redis" | ||
assert span["description"] == "redis.pipeline.execute" | ||
assert span["data"] == { | ||
"redis.commands": { | ||
"count": 3, | ||
"first_ten": expected_first_ten, | ||
}, | ||
SPANDATA.DB_SYSTEM: "redis", | ||
} | ||
assert span["tags"] == { | ||
"redis.transaction": False, # For Cluster, this is always False | ||
"redis.is_cluster": True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import pytest | ||
|
||
pytest.importorskip("redis.asyncio.cluster") |
96 changes: 96 additions & 0 deletions
96
tests/integrations/redis/cluster_asyncio/test_redis_cluster_asyncio.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import pytest | ||
|
||
from sentry_sdk import capture_message, start_transaction | ||
from sentry_sdk.integrations.redis import RedisIntegration | ||
|
||
import redis | ||
|
||
|
||
async def fake_initialize(*_, **__): | ||
return None | ||
|
||
|
||
async def fake_execute_command(*_, **__): | ||
return [] | ||
|
||
|
||
async def fake_execute(*_, **__): | ||
return None | ||
|
||
|
||
@pytest.fixture(autouse=True) | ||
def monkeypatch_rediscluster_asyncio_class(reset_integrations): | ||
pipeline_cls = redis.asyncio.cluster.ClusterPipeline | ||
redis.asyncio.cluster.NodesManager.initialize = fake_initialize | ||
redis.asyncio.RedisCluster.pipeline = lambda self, *_, **__: pipeline_cls(self) | ||
pipeline_cls.execute = fake_execute | ||
redis.asyncio.RedisCluster.execute_command = fake_execute_command | ||
|
||
|
||
@pytest.mark.asyncio | ||
async def test_async_basic(sentry_init, capture_events): | ||
sentry_init(integrations=[RedisIntegration()]) | ||
events = capture_events() | ||
|
||
connection = redis.asyncio.RedisCluster(host="localhost", port=6379) | ||
|
||
await connection.get("foobar") | ||
capture_message("hi") | ||
|
||
(event,) = events | ||
(crumb,) = event["breadcrumbs"]["values"] | ||
|
||
assert crumb == { | ||
"category": "redis", | ||
"message": "GET 'foobar'", | ||
"data": { | ||
"db.operation": "GET", | ||
"redis.key": "foobar", | ||
"redis.command": "GET", | ||
"redis.is_cluster": True, | ||
}, | ||
"timestamp": crumb["timestamp"], | ||
"type": "redis", | ||
} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"send_default_pii, expected_first_ten", | ||
[ | ||
(False, ["GET 'foo'", "SET 'bar' [Filtered]", "SET 'baz' [Filtered]"]), | ||
(True, ["GET 'foo'", "SET 'bar' 1", "SET 'baz' 2"]), | ||
], | ||
) | ||
@pytest.mark.asyncio | ||
async def test_async_redis_pipeline( | ||
sentry_init, capture_events, send_default_pii, expected_first_ten | ||
): | ||
sentry_init( | ||
integrations=[RedisIntegration()], | ||
traces_sample_rate=1.0, | ||
send_default_pii=send_default_pii, | ||
) | ||
events = capture_events() | ||
|
||
connection = redis.asyncio.RedisCluster(host="localhost", port=6379) | ||
with start_transaction(): | ||
pipeline = connection.pipeline() | ||
pipeline.get("foo") | ||
pipeline.set("bar", 1) | ||
pipeline.set("baz", 2) | ||
await pipeline.execute() | ||
|
||
(event,) = events | ||
(span,) = event["spans"] | ||
assert span["op"] == "db.redis" | ||
assert span["description"] == "redis.pipeline.execute" | ||
assert span["data"] == { | ||
"redis.commands": { | ||
"count": 3, | ||
"first_ten": expected_first_ten, | ||
} | ||
} | ||
assert span["tags"] == { | ||
"redis.transaction": False, | ||
"redis.is_cluster": True, | ||
} |