9
9
10
10
if MYPY :
11
11
from typing import Any , Sequence
12
+ from sentry_sdk .tracing import Span
12
13
13
14
_SINGLE_KEY_COMMANDS = frozenset (
14
15
["decr" , "decrby" , "get" , "incr" , "incrby" , "pttl" , "set" , "setex" , "setnx" , "ttl" ]
19
20
_MAX_NUM_ARGS = 10
20
21
21
22
23
+ def _set_pipeline_data (
24
+ span , is_cluster , get_command_args_fn , is_transaction , command_stack
25
+ ):
26
+ # type: (Span, bool, Any, bool, Sequence[Any]) -> None
27
+ span .set_tag ("redis.is_cluster" , is_cluster )
28
+ transaction = is_transaction if not is_cluster else False
29
+ span .set_tag ("redis.transaction" , transaction )
30
+
31
+ commands = []
32
+ for i , arg in enumerate (command_stack ):
33
+ if i > _MAX_NUM_ARGS :
34
+ break
35
+ command_args = []
36
+ for j , command_arg in enumerate (get_command_args_fn (arg )):
37
+ if j > 0 :
38
+ command_arg = repr (command_arg )
39
+ command_args .append (command_arg )
40
+ commands .append (" " .join (command_args ))
41
+
42
+ span .set_data (
43
+ "redis.commands" ,
44
+ {"count" : len (command_stack ), "first_ten" : commands },
45
+ )
46
+
47
+
22
48
def patch_redis_pipeline (pipeline_cls , is_cluster , get_command_args_fn ):
23
49
# type: (Any, bool, Any) -> None
24
50
old_execute = pipeline_cls .execute
@@ -34,31 +60,47 @@ def sentry_patched_execute(self, *args, **kwargs):
34
60
op = OP .DB_REDIS , description = "redis.pipeline.execute"
35
61
) as span :
36
62
with capture_internal_exceptions ():
37
- span .set_tag ("redis.is_cluster" , is_cluster )
38
- transaction = self .transaction if not is_cluster else False
39
- span .set_tag ("redis.transaction" , transaction )
40
-
41
- commands = []
42
- for i , arg in enumerate (self .command_stack ):
43
- if i > _MAX_NUM_ARGS :
44
- break
45
- command_args = []
46
- for j , command_arg in enumerate (get_command_args_fn (arg )):
47
- if j > 0 :
48
- command_arg = repr (command_arg )
49
- command_args .append (command_arg )
50
- commands .append (" " .join (command_args ))
51
-
52
- span .set_data (
53
- "redis.commands" ,
54
- {"count" : len (self .command_stack ), "first_ten" : commands },
63
+ _set_pipeline_data (
64
+ span ,
65
+ is_cluster ,
66
+ get_command_args_fn ,
67
+ self .transaction ,
68
+ self .command_stack ,
55
69
)
56
70
57
71
return old_execute (self , * args , ** kwargs )
58
72
59
73
pipeline_cls .execute = sentry_patched_execute
60
74
61
75
76
+ def patch_redis_async_pipeline (pipeline_cls ):
77
+ # type: (Any) -> None
78
+ old_execute = pipeline_cls .execute
79
+
80
+ async def _sentry_execute (self , * args , ** kwargs ):
81
+ # type: (Any, *Any, **Any) -> Any
82
+ hub = Hub .current
83
+
84
+ if hub .get_integration (RedisIntegration ) is None :
85
+ return await old_execute (self , * args , ** kwargs )
86
+
87
+ with hub .start_span (
88
+ op = OP .DB_REDIS , description = "redis.pipeline.execute"
89
+ ) as span :
90
+ with capture_internal_exceptions ():
91
+ _set_pipeline_data (
92
+ span ,
93
+ False ,
94
+ _get_redis_command_args ,
95
+ self .is_transaction ,
96
+ self .command_stack ,
97
+ )
98
+
99
+ return await old_execute (self , * args , ** kwargs )
100
+
101
+ pipeline_cls .execute = _sentry_execute
102
+
103
+
62
104
def _get_redis_command_args (command ):
63
105
# type: (Any) -> Sequence[Any]
64
106
return command [0 ]
@@ -69,6 +111,37 @@ def _parse_rediscluster_command(command):
69
111
return command .args
70
112
71
113
114
+ def _patch_redis (redis ):
115
+ # type: (Any) -> None
116
+ patch_redis_client (redis .StrictRedis , is_cluster = False )
117
+ patch_redis_pipeline (redis .client .Pipeline , False , _get_redis_command_args )
118
+ try :
119
+ strict_pipeline = redis .client .StrictPipeline
120
+ except AttributeError :
121
+ pass
122
+ else :
123
+ patch_redis_pipeline (strict_pipeline , False , _get_redis_command_args )
124
+ try :
125
+ import redis .asyncio # type: ignore
126
+ except ImportError :
127
+ pass
128
+ else :
129
+ patch_redis_async_client (redis .asyncio .client .StrictRedis )
130
+ patch_redis_async_pipeline (redis .asyncio .client .Pipeline )
131
+
132
+
133
+ def _patch_rb ():
134
+ # type: () -> None
135
+ try :
136
+ import rb .clients # type: ignore
137
+ except ImportError :
138
+ pass
139
+ else :
140
+ patch_redis_client (rb .clients .FanoutClient , is_cluster = False )
141
+ patch_redis_client (rb .clients .MappingClient , is_cluster = False )
142
+ patch_redis_client (rb .clients .RoutingClient , is_cluster = False )
143
+
144
+
72
145
def _patch_rediscluster ():
73
146
# type: () -> None
74
147
try :
@@ -104,30 +177,46 @@ def setup_once():
104
177
except ImportError :
105
178
raise DidNotEnable ("Redis client not installed" )
106
179
107
- patch_redis_client (redis .StrictRedis , is_cluster = False )
108
- patch_redis_pipeline (redis .client .Pipeline , False , _get_redis_command_args )
109
- try :
110
- strict_pipeline = redis .client .StrictPipeline # type: ignore
111
- except AttributeError :
112
- pass
113
- else :
114
- patch_redis_pipeline (strict_pipeline , False , _get_redis_command_args )
115
-
116
- try :
117
- import rb .clients # type: ignore
118
- except ImportError :
119
- pass
120
- else :
121
- patch_redis_client (rb .clients .FanoutClient , is_cluster = False )
122
- patch_redis_client (rb .clients .MappingClient , is_cluster = False )
123
- patch_redis_client (rb .clients .RoutingClient , is_cluster = False )
180
+ _patch_redis (redis )
181
+ _patch_rb ()
124
182
125
183
try :
126
184
_patch_rediscluster ()
127
185
except Exception :
128
186
logger .exception ("Error occurred while patching `rediscluster` library" )
129
187
130
188
189
+ def _get_span_description (name , * args ):
190
+ # type: (str, *Any) -> str
191
+ description = name
192
+
193
+ with capture_internal_exceptions ():
194
+ description_parts = [name ]
195
+ for i , arg in enumerate (args ):
196
+ if i > _MAX_NUM_ARGS :
197
+ break
198
+
199
+ description_parts .append (repr (arg ))
200
+
201
+ description = " " .join (description_parts )
202
+
203
+ return description
204
+
205
+
206
+ def _set_client_data (span , is_cluster , name , * args ):
207
+ # type: (Span, bool, str, *Any) -> None
208
+ span .set_tag ("redis.is_cluster" , is_cluster )
209
+ if name :
210
+ span .set_tag ("redis.command" , name )
211
+
212
+ if name and args :
213
+ name_low = name .lower ()
214
+ if (name_low in _SINGLE_KEY_COMMANDS ) or (
215
+ name_low in _MULTI_KEY_COMMANDS and len (args ) == 1
216
+ ):
217
+ span .set_tag ("redis.key" , args [0 ])
218
+
219
+
131
220
def patch_redis_client (cls , is_cluster ):
132
221
# type: (Any, bool) -> None
133
222
"""
@@ -143,30 +232,32 @@ def sentry_patched_execute_command(self, name, *args, **kwargs):
143
232
if hub .get_integration (RedisIntegration ) is None :
144
233
return old_execute_command (self , name , * args , ** kwargs )
145
234
146
- description = name
235
+ description = _get_span_description ( name , * args )
147
236
148
- with capture_internal_exceptions ():
149
- description_parts = [name ]
150
- for i , arg in enumerate (args ):
151
- if i > _MAX_NUM_ARGS :
152
- break
237
+ with hub .start_span (op = OP .DB_REDIS , description = description ) as span :
238
+ _set_client_data (span , is_cluster , name , * args )
153
239
154
- description_parts . append ( repr ( arg ) )
240
+ return old_execute_command ( self , name , * args , ** kwargs )
155
241
156
- description = " " . join ( description_parts )
242
+ cls . execute_command = sentry_patched_execute_command
157
243
158
- with hub .start_span (op = OP .DB_REDIS , description = description ) as span :
159
- span .set_tag ("redis.is_cluster" , is_cluster )
160
- if name :
161
- span .set_tag ("redis.command" , name )
162
244
163
- if name and args :
164
- name_low = name .lower ()
165
- if (name_low in _SINGLE_KEY_COMMANDS ) or (
166
- name_low in _MULTI_KEY_COMMANDS and len (args ) == 1
167
- ):
168
- span .set_tag ("redis.key" , args [0 ])
245
+ def patch_redis_async_client (cls ):
246
+ # type: (Any) -> None
247
+ old_execute_command = cls .execute_command
169
248
170
- return old_execute_command (self , name , * args , ** kwargs )
249
+ async def _sentry_execute_command (self , name , * args , ** kwargs ):
250
+ # type: (Any, str, *Any, **Any) -> Any
251
+ hub = Hub .current
171
252
172
- cls .execute_command = sentry_patched_execute_command
253
+ if hub .get_integration (RedisIntegration ) is None :
254
+ return await old_execute_command (self , name , * args , ** kwargs )
255
+
256
+ description = _get_span_description (name , * args )
257
+
258
+ with hub .start_span (op = OP .DB_REDIS , description = description ) as span :
259
+ _set_client_data (span , False , name , * args )
260
+
261
+ return await old_execute_command (self , name , * args , ** kwargs )
262
+
263
+ cls .execute_command = _sentry_execute_command
0 commit comments