Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redis asyncio testing #881

Merged
merged 9 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions newrelic/hooks/datastore_aioredis.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,12 @@ def _nr_wrapper_AioRedis_method_(wrapped, instance, args, kwargs):
# Method will return synchronously without executing,
# it will be added to the command stack and run later.
aioredis_version = get_package_version_tuple("aioredis")
if aioredis_version and aioredis_version < (2,):
# This conditional is for versions of aioredis that are outside
# New Relic's supportability window but will still work. New
# Relic does not provide testing/support for this. In order to
# keep functionality without affecting coverage metrics, this
# segment is excluded from coverage analysis.
if aioredis_version and aioredis_version < (2,): # pragma: no cover
# AioRedis v1 uses a RedisBuffer instead of a real connection for queueing up pipeline commands
from aioredis.commands.transaction import _RedisBuffer

Expand Down Expand Up @@ -135,7 +140,12 @@ async def wrap_Connection_send_command(wrapped, instance, args, kwargs):
return await wrapped(*args, **kwargs)


def wrap_RedisConnection_execute(wrapped, instance, args, kwargs):
# This wrapper is for versions of aioredis that are outside
# New Relic's supportability window but will still work. New
# Relic does not provide testing/support for this. In order to
# keep functionality without affecting coverage metrics, this
# segment is excluded from coverage analysis.
def wrap_RedisConnection_execute(wrapped, instance, args, kwargs): # pragma: no cover
# RedisConnection in aioredis v1 returns a future instead of using coroutines
transaction = current_transaction()
if not transaction:
Expand Down Expand Up @@ -203,6 +213,11 @@ def instrument_aioredis_connection(module):
if hasattr(module.Connection, "send_command"):
wrap_function_wrapper(module, "Connection.send_command", wrap_Connection_send_command)

if hasattr(module, "RedisConnection"):
# This conditional is for versions of aioredis that are outside
# New Relic's supportability window but will still work. New
# Relic does not provide testing/support for this. In order to
# keep functionality without affecting coverage metrics, this
# segment is excluded from coverage analysis.
if hasattr(module, "RedisConnection"): # pragma: no cover
if hasattr(module.RedisConnection, "execute"):
wrap_function_wrapper(module, "RedisConnection.execute", wrap_RedisConnection_execute)
115 changes: 61 additions & 54 deletions newrelic/hooks/datastore_redis.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,65 @@
from newrelic.api.transaction import current_transaction
from newrelic.common.object_wrapper import function_wrapper, wrap_function_wrapper

_redis_client_sync_methods = {
"acl_dryrun",
"auth",
"bgrewriteaof",
"bitfield",
"blmpop",
"bzmpop",
"client",
"command",
"command_docs",
"command_getkeysandflags",
"command_info",
"debug_segfault",
"expiretime",
"failover",
"hello",
"latency_doctor",
"latency_graph",
"latency_histogram",
"lcs",
"lpop",
"lpos",
"memory_doctor",
"memory_help",
"monitor",
"pexpiretime",
"psetex",
"psync",
"pubsub",
"renamenx",
"rpop",
"script_debug",
"sentinel_ckquorum",
"sentinel_failover",
"sentinel_flushconfig",
"sentinel_get_master_addr_by_name",
"sentinel_master",
"sentinel_masters",
"sentinel_monitor",
"sentinel_remove",
"sentinel_reset",
"sentinel_sentinels",
"sentinel_set",
"sentinel_slaves",
"shutdown",
"sort",
"sort_ro",
"spop",
"srandmember",
"unwatch",
"watch",
"zlexcount",
"zrevrangebyscore",
}


_redis_client_methods = {
_redis_client_async_methods = {
"acl_cat",
"acl_deluser",
"acl_dryrun",
"acl_genpass",
"acl_getuser",
"acl_help",
Expand Down Expand Up @@ -51,11 +105,8 @@
"arrlen",
"arrpop",
"arrtrim",
"auth",
"bgrewriteaof",
"bgsave",
"bitcount",
"bitfield",
"bitfield_ro",
"bitop_and",
"bitop_not",
Expand All @@ -64,13 +115,11 @@
"bitop",
"bitpos",
"blmove",
"blmpop",
"blpop",
"brpop",
"brpoplpush",
"byrank",
"byrevrank",
"bzmpop",
"bzpopmax",
"bzpopmin",
"card",
Expand All @@ -91,7 +140,6 @@
"client_trackinginfo",
"client_unblock",
"client_unpause",
"client",
"cluster_add_slots",
"cluster_addslots",
"cluster_count_failure_report",
Expand All @@ -118,10 +166,7 @@
"cluster_slots",
"cluster",
"command_count",
"command_docs",
"command_getkeys",
"command_getkeysandflags",
"command_info",
"command_list",
"command",
"commit",
Expand All @@ -137,7 +182,6 @@
"createrule",
"dbsize",
"debug_object",
"debug_segfault",
"debug_sleep",
"debug",
"decr",
Expand All @@ -160,10 +204,8 @@
"exists",
"expire",
"expireat",
"expiretime",
"explain_cli",
"explain",
"failover",
"fcall_ro",
"fcall",
"flushall",
Expand Down Expand Up @@ -192,7 +234,6 @@
"getrange",
"getset",
"hdel",
"hello",
"hexists",
"hget",
"hgetall",
Expand Down Expand Up @@ -220,13 +261,9 @@
"insertnx",
"keys",
"lastsave",
"latency_doctor",
"latency_graph",
"latency_histogram",
"latency_history",
"latency_latest",
"latency_reset",
"lcs",
"lindex",
"linsert",
"list",
Expand All @@ -235,8 +272,6 @@
"lmpop",
"loadchunk",
"lolwut",
"lpop",
"lpos",
"lpush",
"lpushx",
"lrange",
Expand All @@ -245,8 +280,6 @@
"ltrim",
"madd",
"max",
"memory_doctor",
"memory_help",
"memory_malloc_stats",
"memory_purge",
"memory_stats",
Expand All @@ -261,7 +294,6 @@
"module_load",
"module_loadex",
"module_unload",
"monitor",
"move",
"mrange",
"mrevrange",
Expand All @@ -277,21 +309,17 @@
"persist",
"pexpire",
"pexpireat",
"pexpiretime",
"pfadd",
"pfcount",
"pfmerge",
"ping",
"profile",
"psetex",
"psubscribe",
"psync",
"pttl",
"publish",
"pubsub_channels",
"pubsub_numpat",
"pubsub_numsub",
"pubsub",
"punsubscribe",
"quantile",
"query",
Expand All @@ -303,7 +331,6 @@
"readonly",
"readwrite",
"rename",
"renamenx",
"replicaof",
"reserve",
"reset",
Expand All @@ -312,7 +339,6 @@
"revrange",
"revrank",
"role",
"rpop",
"rpoplpush",
"rpush",
"rpushx",
Expand All @@ -322,7 +348,6 @@
"scan",
"scandump",
"scard",
"script_debug",
"script_exists",
"script_flush",
"script_kill",
Expand All @@ -331,24 +356,11 @@
"sdiffstore",
"search",
"select",
"sentinel_ckquorum",
"sentinel_failover",
"sentinel_flushconfig",
"sentinel_get_master_addr_by_name",
"sentinel_master",
"sentinel_masters",
"sentinel_monitor",
"sentinel_remove",
"sentinel_reset",
"sentinel_sentinels",
"sentinel_set",
"sentinel_slaves",
"set",
"setbit",
"setex",
"setnx",
"setrange",
"shutdown",
"sinter",
"sintercard",
"sinterstore",
Expand All @@ -361,11 +373,7 @@
"smembers",
"smismember",
"smove",
"sort_ro",
"sort",
"spellcheck",
"spop",
"srandmember",
"srem",
"sscan_iter",
"sscan",
Expand Down Expand Up @@ -393,10 +401,8 @@
"type",
"unlink",
"unsubscribe",
"unwatch",
"wait",
"waitaof",
"watch",
"xack",
"xadd",
"xautoclaim",
Expand Down Expand Up @@ -432,7 +438,6 @@
"zinter",
"zintercard",
"zinterstore",
"zlexcount",
"zmpop",
"zmscore",
"zpopmax",
Expand All @@ -449,7 +454,6 @@
"zremrangebyscore",
"zrevrange",
"zrevrangebylex",
"zrevrangebyscore",
"zrevrank",
"zscan_iter",
"zscan",
Expand All @@ -458,6 +462,8 @@
"zunionstore",
}

_redis_client_methods = _redis_client_sync_methods.union(_redis_client_async_methods)

_redis_multipart_commands = set(["client", "cluster", "command", "config", "debug", "sentinel", "slowlog", "script"])

_redis_operation_re = re.compile(r"[-\s]+")
Expand Down Expand Up @@ -506,7 +512,6 @@ def _nr_wrapper_Redis_method_(wrapped, instance, args, kwargs):


def _wrap_asyncio_Redis_method_wrapper(module, instance_class_name, operation):

@function_wrapper
async def _nr_wrapper_asyncio_Redis_async_method_(wrapped, instance, args, kwargs):
transaction = current_transaction()
Expand All @@ -518,6 +523,7 @@ async def _nr_wrapper_asyncio_Redis_async_method_(wrapped, instance, args, kwarg

def _nr_wrapper_asyncio_Redis_method_(wrapped, instance, args, kwargs):
from redis.asyncio.client import Pipeline

if isinstance(instance, Pipeline):
return wrapped(*args, **kwargs)

Expand Down Expand Up @@ -592,10 +598,11 @@ def instrument_redis_client(module):
def instrument_asyncio_redis_client(module):
if hasattr(module, "Redis"):
class_ = getattr(module, "Redis")
for operation in _redis_client_methods:
for operation in _redis_client_async_methods:
if hasattr(class_, operation):
_wrap_asyncio_Redis_method_wrapper(module, "Redis", operation)


def instrument_redis_commands_core(module):
_instrument_redis_commands_module(module, "CoreCommands")

Expand Down
Loading
Loading