22
33from sentry_sdk import Hub
44from sentry_sdk .consts import OP , SPANDATA
5+ from sentry_sdk ._compat import text_type
56from sentry_sdk .hub import _should_send_default_pii
7+ from sentry_sdk .integrations import Integration , DidNotEnable
8+ from sentry_sdk ._types import TYPE_CHECKING
69from sentry_sdk .utils import (
710 SENSITIVE_DATA_SUBSTITUTE ,
811 capture_internal_exceptions ,
912 logger ,
1013)
11- from sentry_sdk .integrations import Integration , DidNotEnable
12-
13- from sentry_sdk ._types import TYPE_CHECKING
1414
1515if TYPE_CHECKING :
16- from typing import Any , Sequence
16+ from typing import Any , Dict , Sequence
1717 from sentry_sdk .tracing import Span
1818
1919_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" ],
2124)
22- _MULTI_KEY_COMMANDS = frozenset (["del" , "touch" , "unlink" ])
23-
2425_COMMANDS_INCLUDING_SENSITIVE_DATA = [
2526 "auth" ,
2627]
27-
2828_MAX_NUM_ARGS = 10 # Trim argument lists to this many values
2929_MAX_NUM_COMMANDS = 10 # Trim command lists to this many values
30-
3130_DEFAULT_MAX_DATA_SIZE = 1024
3231
3332
@@ -59,6 +58,26 @@ def _get_safe_command(name, args):
5958 return command
6059
6160
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+
6281def _set_pipeline_data (
6382 span , is_cluster , get_command_args_fn , is_transaction , command_stack
6483):
@@ -84,6 +103,38 @@ def _set_pipeline_data(
84103 )
85104
86105
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+
87138def patch_redis_pipeline (pipeline_cls , is_cluster , get_command_args_fn ):
88139 # type: (Any, bool, Any) -> None
89140 old_execute = pipeline_cls .execute
@@ -99,28 +150,51 @@ def sentry_patched_execute(self, *args, **kwargs):
99150 op = OP .DB_REDIS , description = "redis.pipeline.execute"
100151 ) as span :
101152 with capture_internal_exceptions ():
153+ _set_db_data (span , self .connection_pool .connection_kwargs )
102154 _set_pipeline_data (
103155 span ,
104156 is_cluster ,
105157 get_command_args_fn ,
106158 self .transaction ,
107159 self .command_stack ,
108160 )
109- span .set_data (SPANDATA .DB_SYSTEM , "redis" )
110161
111162 return old_execute (self , * args , ** kwargs )
112163
113164 pipeline_cls .execute = sentry_patched_execute
114165
115166
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
119174
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 )
120179
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
124198
125199
126200def _patch_redis (StrictRedis , client ): # noqa: N803
@@ -206,61 +280,3 @@ def setup_once():
206280 _patch_rediscluster ()
207281 except Exception :
208282 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