2
2
3
3
from sentry_sdk import Hub
4
4
from sentry_sdk .consts import OP , SPANDATA
5
+ from sentry_sdk ._compat import text_type
5
6
from sentry_sdk .hub import _should_send_default_pii
7
+ from sentry_sdk .integrations import Integration , DidNotEnable
8
+ from sentry_sdk ._types import TYPE_CHECKING
6
9
from sentry_sdk .utils import (
7
10
SENSITIVE_DATA_SUBSTITUTE ,
8
11
capture_internal_exceptions ,
9
12
logger ,
10
13
)
11
- from sentry_sdk .integrations import Integration , DidNotEnable
12
-
13
- from sentry_sdk ._types import TYPE_CHECKING
14
14
15
15
if TYPE_CHECKING :
16
- from typing import Any , Sequence
16
+ from typing import Any , Dict , Sequence
17
17
from sentry_sdk .tracing import Span
18
18
19
19
_SINGLE_KEY_COMMANDS = frozenset (
20
- ["decr" , "decrby" , "get" , "incr" , "incrby" , "pttl" , "set" , "setex" , "setnx" , "ttl" ]
20
+ ["decr" , "decrby" , "get" , "incr" , "incrby" , "pttl" , "set" , "setex" , "setnx" , "ttl" ],
21
+ )
22
+ _MULTI_KEY_COMMANDS = frozenset (
23
+ ["del" , "touch" , "unlink" ],
21
24
)
22
- _MULTI_KEY_COMMANDS = frozenset (["del" , "touch" , "unlink" ])
23
-
24
25
_COMMANDS_INCLUDING_SENSITIVE_DATA = [
25
26
"auth" ,
26
27
]
27
-
28
28
_MAX_NUM_ARGS = 10 # Trim argument lists to this many values
29
29
_MAX_NUM_COMMANDS = 10 # Trim command lists to this many values
30
-
31
30
_DEFAULT_MAX_DATA_SIZE = 1024
32
31
33
32
@@ -59,6 +58,26 @@ def _get_safe_command(name, args):
59
58
return command
60
59
61
60
61
+ def _get_span_description (name , * args ):
62
+ # type: (str, *Any) -> str
63
+ description = name
64
+
65
+ with capture_internal_exceptions ():
66
+ description = _get_safe_command (name , args )
67
+
68
+ return description
69
+
70
+
71
+ def _get_redis_command_args (command ):
72
+ # type: (Any) -> Sequence[Any]
73
+ return command [0 ]
74
+
75
+
76
+ def _parse_rediscluster_command (command ):
77
+ # type: (Any) -> Sequence[Any]
78
+ return command .args
79
+
80
+
62
81
def _set_pipeline_data (
63
82
span , is_cluster , get_command_args_fn , is_transaction , command_stack
64
83
):
@@ -84,6 +103,38 @@ def _set_pipeline_data(
84
103
)
85
104
86
105
106
+ def _set_client_data (span , is_cluster , name , * args ):
107
+ # type: (Span, bool, str, *Any) -> None
108
+ span .set_tag ("redis.is_cluster" , is_cluster )
109
+ if name :
110
+ span .set_tag ("redis.command" , name )
111
+ span .set_tag (SPANDATA .DB_OPERATION , name )
112
+
113
+ if name and args :
114
+ name_low = name .lower ()
115
+ if (name_low in _SINGLE_KEY_COMMANDS ) or (
116
+ name_low in _MULTI_KEY_COMMANDS and len (args ) == 1
117
+ ):
118
+ span .set_tag ("redis.key" , args [0 ])
119
+
120
+
121
+ def _set_db_data (span , connection_params ):
122
+ # type: (Span, Dict[str, Any]) -> None
123
+ span .set_data (SPANDATA .DB_SYSTEM , "redis" )
124
+
125
+ db = connection_params .get ("db" )
126
+ if db is not None :
127
+ span .set_data (SPANDATA .DB_NAME , text_type (db ))
128
+
129
+ host = connection_params .get ("host" )
130
+ if host is not None :
131
+ span .set_data (SPANDATA .SERVER_ADDRESS , host )
132
+
133
+ port = connection_params .get ("port" )
134
+ if port is not None :
135
+ span .set_data (SPANDATA .SERVER_PORT , port )
136
+
137
+
87
138
def patch_redis_pipeline (pipeline_cls , is_cluster , get_command_args_fn ):
88
139
# type: (Any, bool, Any) -> None
89
140
old_execute = pipeline_cls .execute
@@ -99,28 +150,51 @@ def sentry_patched_execute(self, *args, **kwargs):
99
150
op = OP .DB_REDIS , description = "redis.pipeline.execute"
100
151
) as span :
101
152
with capture_internal_exceptions ():
153
+ _set_db_data (span , self .connection_pool .connection_kwargs )
102
154
_set_pipeline_data (
103
155
span ,
104
156
is_cluster ,
105
157
get_command_args_fn ,
106
158
self .transaction ,
107
159
self .command_stack ,
108
160
)
109
- span .set_data (SPANDATA .DB_SYSTEM , "redis" )
110
161
111
162
return old_execute (self , * args , ** kwargs )
112
163
113
164
pipeline_cls .execute = sentry_patched_execute
114
165
115
166
116
- def _get_redis_command_args (command ):
117
- # type: (Any) -> Sequence[Any]
118
- return command [0 ]
167
+ def patch_redis_client (cls , is_cluster ):
168
+ # type: (Any, bool) -> None
169
+ """
170
+ This function can be used to instrument custom redis client classes or
171
+ subclasses.
172
+ """
173
+ old_execute_command = cls .execute_command
119
174
175
+ def sentry_patched_execute_command (self , name , * args , ** kwargs ):
176
+ # type: (Any, str, *Any, **Any) -> Any
177
+ hub = Hub .current
178
+ integration = hub .get_integration (RedisIntegration )
120
179
121
- def _parse_rediscluster_command (command ):
122
- # type: (Any) -> Sequence[Any]
123
- return command .args
180
+ if integration is None :
181
+ return old_execute_command (self , name , * args , ** kwargs )
182
+
183
+ description = _get_span_description (name , * args )
184
+
185
+ data_should_be_truncated = (
186
+ integration .max_data_size and len (description ) > integration .max_data_size
187
+ )
188
+ if data_should_be_truncated :
189
+ description = description [: integration .max_data_size - len ("..." )] + "..."
190
+
191
+ with hub .start_span (op = OP .DB_REDIS , description = description ) as span :
192
+ _set_db_data (span , self .connection_pool .connection_kwargs )
193
+ _set_client_data (span , is_cluster , name , * args )
194
+
195
+ return old_execute_command (self , name , * args , ** kwargs )
196
+
197
+ cls .execute_command = sentry_patched_execute_command
124
198
125
199
126
200
def _patch_redis (StrictRedis , client ): # noqa: N803
@@ -206,61 +280,3 @@ def setup_once():
206
280
_patch_rediscluster ()
207
281
except Exception :
208
282
logger .exception ("Error occurred while patching `rediscluster` library" )
209
-
210
-
211
- def _get_span_description (name , * args ):
212
- # type: (str, *Any) -> str
213
- description = name
214
-
215
- with capture_internal_exceptions ():
216
- description = _get_safe_command (name , args )
217
-
218
- return description
219
-
220
-
221
- def _set_client_data (span , is_cluster , name , * args ):
222
- # type: (Span, bool, str, *Any) -> None
223
- span .set_data (SPANDATA .DB_SYSTEM , "redis" )
224
- span .set_tag ("redis.is_cluster" , is_cluster )
225
- if name :
226
- span .set_tag ("redis.command" , name )
227
- span .set_tag (SPANDATA .DB_OPERATION , name )
228
-
229
- if name and args :
230
- name_low = name .lower ()
231
- if (name_low in _SINGLE_KEY_COMMANDS ) or (
232
- name_low in _MULTI_KEY_COMMANDS and len (args ) == 1
233
- ):
234
- span .set_tag ("redis.key" , args [0 ])
235
-
236
-
237
- def patch_redis_client (cls , is_cluster ):
238
- # type: (Any, bool) -> None
239
- """
240
- This function can be used to instrument custom redis client classes or
241
- subclasses.
242
- """
243
- old_execute_command = cls .execute_command
244
-
245
- def sentry_patched_execute_command (self , name , * args , ** kwargs ):
246
- # type: (Any, str, *Any, **Any) -> Any
247
- hub = Hub .current
248
- integration = hub .get_integration (RedisIntegration )
249
-
250
- if integration is None :
251
- return old_execute_command (self , name , * args , ** kwargs )
252
-
253
- description = _get_span_description (name , * args )
254
-
255
- data_should_be_truncated = (
256
- integration .max_data_size and len (description ) > integration .max_data_size
257
- )
258
- if data_should_be_truncated :
259
- description = description [: integration .max_data_size - len ("..." )] + "..."
260
-
261
- with hub .start_span (op = OP .DB_REDIS , description = description ) as span :
262
- _set_client_data (span , is_cluster , name , * args )
263
-
264
- return old_execute_command (self , name , * args , ** kwargs )
265
-
266
- cls .execute_command = sentry_patched_execute_command
0 commit comments