Skip to content

Commit 1be16b7

Browse files
Add support for Redis v4. (#443)
* Add commands instrumentation point. * Fix redis instance info tests and update test matrix. * [Mega-Linter] Apply linters fixes * Add instrumentation point for redis 4.1.0. * [Mega-Linter] Apply linters fixes * Update rb versions. * Apply suggestions from code review Co-authored-by: umaannamalai <[email protected]> Co-authored-by: Timothy Pansino <[email protected]>
1 parent d555320 commit 1be16b7

File tree

4 files changed

+273
-130
lines changed

4 files changed

+273
-130
lines changed

newrelic/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,10 @@ def _process_module_builtin_defaults():
26312631
)
26322632
_process_module_definition("redis.client", "newrelic.hooks.datastore_redis", "instrument_redis_client")
26332633

2634+
_process_module_definition(
2635+
"redis.commands.core", "newrelic.hooks.datastore_redis", "instrument_redis_commands_core"
2636+
)
2637+
26342638
_process_module_definition("motor", "newrelic.hooks.datastore_motor", "patch_motor")
26352639

26362640
_process_module_definition(

newrelic/hooks/datastore_redis.py

Lines changed: 202 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -18,71 +18,200 @@
1818
from newrelic.api.transaction import current_transaction
1919
from newrelic.common.object_wrapper import wrap_function_wrapper
2020

21-
_redis_client_methods = ('bgrewriteaof', 'bgsave', 'client_kill',
22-
'client_list', 'client_getname', 'client_setname', 'config_get',
23-
'config_set', 'config_resetstat', 'config_rewrite', 'dbsize',
24-
'debug_object', 'echo', 'flushall', 'flushdb', 'info', 'lastsave',
25-
'object', 'ping', 'save', 'sentinel', 'sentinel_get_master_addr_by_name',
26-
'sentinel_master', 'sentinel_masters', 'sentinel_monitor',
27-
'sentinel_remove', 'sentinel_sentinels', 'sentinel_set',
28-
'sentinel_slaves', 'shutdown', 'slaveof', 'slowlog_get',
29-
'slowlog_reset', 'time', 'append', 'bitcount', 'bitop', 'bitpos',
30-
'decr', 'delete', 'dump', 'exists', 'expire', 'expireat', 'get',
31-
'getbit', 'getrange', 'getset', 'incr', 'incrby', 'incrbyfloat',
32-
'keys', 'mget', 'mset', 'msetnx', 'move', 'persist', 'pexpire',
33-
'pexpireat', 'psetex', 'pttl', 'randomkey', 'rename', 'renamenx',
34-
'restore', 'set', 'setbit', 'setex', 'setnx', 'setrange', 'strlen',
35-
'substr', 'ttl', 'type', 'watch', 'unwatch', 'blpop', 'brpop',
36-
'brpoplpush', 'lindex', 'linsert', 'llen', 'lpop', 'lpush',
37-
'lpushx', 'lrange', 'lrem', 'lset', 'ltrim', 'rpop', 'rpoplpush',
38-
'rpush', 'rpushx', 'sort', 'scan', 'scan_iter', 'sscan',
39-
'sscan_iter', 'hscan', 'hscan_inter', 'zscan', 'zscan_iter', 'sadd',
40-
'scard', 'sdiff', 'sdiffstore', 'sinter', 'sinterstore',
41-
'sismember', 'smembers', 'smove', 'spop', 'srandmember', 'srem',
42-
'sunion', 'sunionstore', 'zadd', 'zcard', 'zcount', 'zincrby',
43-
'zinterstore', 'zlexcount', 'zrange', 'zrangebylex',
44-
'zrangebyscore', 'zrank', 'zrem', 'zremrangebylex',
45-
'zremrangebyrank', 'zremrangebyscore', 'zrevrange',
46-
'zrevrangebyscore', 'zrevrank', 'zscore', 'zunionstore', 'pfadd',
47-
'pfcount', 'pfmerge', 'hdel', 'hexists', 'hget', 'hgetall',
48-
'hincrby', 'hincrbyfloat', 'hkeys', 'hlen', 'hset', 'hsetnx',
49-
'hmset', 'hmget', 'hvals', 'publish', 'eval', 'evalsha',
50-
'script_exists', 'script_flush', 'script_kill', 'script_load',
51-
'setex', 'lrem', 'zadd')
52-
53-
_redis_multipart_commands = set(['client', 'cluster', 'command', 'config',
54-
'debug', 'sentinel', 'slowlog', 'script'])
55-
56-
_redis_operation_re = re.compile(r'[-\s]+')
21+
_redis_client_methods = (
22+
"bgrewriteaof",
23+
"bgsave",
24+
"client_kill",
25+
"client_list",
26+
"client_getname",
27+
"client_setname",
28+
"config_get",
29+
"config_set",
30+
"config_resetstat",
31+
"config_rewrite",
32+
"dbsize",
33+
"debug_object",
34+
"echo",
35+
"flushall",
36+
"flushdb",
37+
"info",
38+
"lastsave",
39+
"object",
40+
"ping",
41+
"save",
42+
"sentinel",
43+
"sentinel_get_master_addr_by_name",
44+
"sentinel_master",
45+
"sentinel_masters",
46+
"sentinel_monitor",
47+
"sentinel_remove",
48+
"sentinel_sentinels",
49+
"sentinel_set",
50+
"sentinel_slaves",
51+
"shutdown",
52+
"slaveof",
53+
"slowlog_get",
54+
"slowlog_reset",
55+
"time",
56+
"append",
57+
"bitcount",
58+
"bitop",
59+
"bitpos",
60+
"decr",
61+
"delete",
62+
"dump",
63+
"exists",
64+
"expire",
65+
"expireat",
66+
"get",
67+
"getbit",
68+
"getrange",
69+
"getset",
70+
"incr",
71+
"incrby",
72+
"incrbyfloat",
73+
"keys",
74+
"mget",
75+
"mset",
76+
"msetnx",
77+
"move",
78+
"persist",
79+
"pexpire",
80+
"pexpireat",
81+
"psetex",
82+
"pttl",
83+
"randomkey",
84+
"rename",
85+
"renamenx",
86+
"restore",
87+
"set",
88+
"setbit",
89+
"setex",
90+
"setnx",
91+
"setrange",
92+
"strlen",
93+
"substr",
94+
"ttl",
95+
"type",
96+
"watch",
97+
"unwatch",
98+
"blpop",
99+
"brpop",
100+
"brpoplpush",
101+
"lindex",
102+
"linsert",
103+
"llen",
104+
"lpop",
105+
"lpush",
106+
"lpushx",
107+
"lrange",
108+
"lrem",
109+
"lset",
110+
"ltrim",
111+
"rpop",
112+
"rpoplpush",
113+
"rpush",
114+
"rpushx",
115+
"sort",
116+
"scan",
117+
"scan_iter",
118+
"sscan",
119+
"sscan_iter",
120+
"hscan",
121+
"hscan_inter",
122+
"zscan",
123+
"zscan_iter",
124+
"sadd",
125+
"scard",
126+
"sdiff",
127+
"sdiffstore",
128+
"sinter",
129+
"sinterstore",
130+
"sismember",
131+
"smembers",
132+
"smove",
133+
"spop",
134+
"srandmember",
135+
"srem",
136+
"sunion",
137+
"sunionstore",
138+
"zadd",
139+
"zcard",
140+
"zcount",
141+
"zincrby",
142+
"zinterstore",
143+
"zlexcount",
144+
"zrange",
145+
"zrangebylex",
146+
"zrangebyscore",
147+
"zrank",
148+
"zrem",
149+
"zremrangebylex",
150+
"zremrangebyrank",
151+
"zremrangebyscore",
152+
"zrevrange",
153+
"zrevrangebyscore",
154+
"zrevrank",
155+
"zscore",
156+
"zunionstore",
157+
"pfadd",
158+
"pfcount",
159+
"pfmerge",
160+
"hdel",
161+
"hexists",
162+
"hget",
163+
"hgetall",
164+
"hincrby",
165+
"hincrbyfloat",
166+
"hkeys",
167+
"hlen",
168+
"hset",
169+
"hsetnx",
170+
"hmset",
171+
"hmget",
172+
"hvals",
173+
"publish",
174+
"eval",
175+
"evalsha",
176+
"script_exists",
177+
"script_flush",
178+
"script_kill",
179+
"script_load",
180+
"setex",
181+
"lrem",
182+
"zadd",
183+
)
184+
185+
_redis_multipart_commands = set(["client", "cluster", "command", "config", "debug", "sentinel", "slowlog", "script"])
186+
187+
_redis_operation_re = re.compile(r"[-\s]+")
188+
57189

58190
def _conn_attrs_to_dict(connection):
59191
return {
60-
'host': getattr(connection, 'host', None),
61-
'port': getattr(connection, 'port', None),
62-
'path': getattr(connection, 'path', None),
63-
'db': getattr(connection, 'db', None),
192+
"host": getattr(connection, "host", None),
193+
"port": getattr(connection, "port", None),
194+
"path": getattr(connection, "path", None),
195+
"db": getattr(connection, "db", None),
64196
}
65197

198+
66199
def _instance_info(kwargs):
67-
host = kwargs.get('host') or 'localhost'
68-
port_path_or_id = str(kwargs.get('port') or kwargs.get('path', 'unknown'))
69-
db = str(kwargs.get('db') or 0)
200+
host = kwargs.get("host") or "localhost"
201+
port_path_or_id = str(kwargs.get("port") or kwargs.get("path", "unknown"))
202+
db = str(kwargs.get("db") or 0)
70203

71204
return (host, port_path_or_id, db)
72205

73-
def _wrap_Redis_method_wrapper_(module, instance_class_name, operation):
74206

207+
def _wrap_Redis_method_wrapper_(module, instance_class_name, operation):
75208
def _nr_wrapper_Redis_method_(wrapped, instance, args, kwargs):
76209
transaction = current_transaction()
77210

78211
if transaction is None:
79212
return wrapped(*args, **kwargs)
80213

81-
dt = DatastoreTrace(
82-
product='Redis',
83-
target=None,
84-
operation=operation
85-
)
214+
dt = DatastoreTrace(product="Redis", target=None, operation=operation)
86215

87216
transaction._nr_datastore_instance_info = (None, None, None)
88217

@@ -96,19 +225,31 @@ def _nr_wrapper_Redis_method_(wrapped, instance, args, kwargs):
96225

97226
return result
98227

99-
name = '%s.%s' % (instance_class_name, operation)
228+
name = "%s.%s" % (instance_class_name, operation)
100229
wrap_function_wrapper(module, name, _nr_wrapper_Redis_method_)
101230

231+
102232
def instrument_redis_client(module):
103-
if hasattr(module, 'StrictRedis'):
233+
if hasattr(module, "StrictRedis"):
104234
for name in _redis_client_methods:
105235
if name in vars(module.StrictRedis):
106-
_wrap_Redis_method_wrapper_(module, 'StrictRedis', name)
236+
_wrap_Redis_method_wrapper_(module, "StrictRedis", name)
107237

108-
if hasattr(module, 'Redis'):
238+
if hasattr(module, "Redis"):
109239
for name in _redis_client_methods:
110240
if name in vars(module.Redis):
111-
_wrap_Redis_method_wrapper_(module, 'Redis', name)
241+
_wrap_Redis_method_wrapper_(module, "Redis", name)
242+
243+
244+
def instrument_redis_commands_core(module):
245+
for name in _redis_client_methods:
246+
if hasattr(module, "CoreCommands"):
247+
if hasattr(module.CoreCommands, name):
248+
_wrap_Redis_method_wrapper_(module, "CoreCommands", name)
249+
if hasattr(module, "DataAccessCommands"):
250+
if hasattr(module.DataAccessCommands, name):
251+
_wrap_Redis_method_wrapper_(module, "DataAccessCommands", name)
252+
112253

113254
def _nr_Connection_send_command_wrapper_(wrapped, instance, args, kwargs):
114255
transaction = current_transaction()
@@ -120,8 +261,7 @@ def _nr_Connection_send_command_wrapper_(wrapped, instance, args, kwargs):
120261

121262
try:
122263
dt = transaction.settings.datastore_tracer
123-
if (dt.instance_reporting.enabled or
124-
dt.database_name_reporting.enabled):
264+
if dt.instance_reporting.enabled or dt.database_name_reporting.enabled:
125265
conn_kwargs = _conn_attrs_to_dict(instance)
126266
host, port_path_or_id, db = _instance_info(conn_kwargs)
127267
except:
@@ -144,19 +284,15 @@ def _nr_Connection_send_command_wrapper_(wrapped, instance, args, kwargs):
144284
# Convert multi args to single arg string
145285

146286
if operation in _redis_multipart_commands and len(args) > 1:
147-
operation = '%s %s' % (operation, args[1].strip().lower())
287+
operation = "%s %s" % (operation, args[1].strip().lower())
148288

149-
operation = _redis_operation_re.sub('_', operation)
289+
operation = _redis_operation_re.sub("_", operation)
150290

151291
with DatastoreTrace(
152-
product='Redis',
153-
target=None,
154-
operation=operation,
155-
host=host,
156-
port_path_or_id=port_path_or_id,
157-
database_name=db):
292+
product="Redis", target=None, operation=operation, host=host, port_path_or_id=port_path_or_id, database_name=db
293+
):
158294
return wrapped(*args, **kwargs)
159295

296+
160297
def instrument_redis_connection(module):
161-
wrap_function_wrapper(module, 'Connection.send_command',
162-
_nr_Connection_send_command_wrapper_)
298+
wrap_function_wrapper(module, "Connection.send_command", _nr_Connection_send_command_wrapper_)

0 commit comments

Comments
 (0)