-
Notifications
You must be signed in to change notification settings - Fork 537
/
Copy pathutils.py
144 lines (112 loc) · 3.87 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from sentry_sdk._types import TYPE_CHECKING
from sentry_sdk.consts import SPANDATA
from sentry_sdk.integrations.redis.consts import (
_COMMANDS_INCLUDING_SENSITIVE_DATA,
_MAX_NUM_ARGS,
_MAX_NUM_COMMANDS,
_MULTI_KEY_COMMANDS,
_SINGLE_KEY_COMMANDS,
)
from sentry_sdk.scope import should_send_default_pii
from sentry_sdk.utils import SENSITIVE_DATA_SUBSTITUTE
if TYPE_CHECKING:
from typing import Any, Optional, Sequence
from sentry_sdk.tracing import Span
def _get_safe_command(name, args):
# type: (str, Sequence[Any]) -> str
command_parts = [name]
for i, arg in enumerate(args):
if i > _MAX_NUM_ARGS:
break
name_low = name.lower()
if name_low in _COMMANDS_INCLUDING_SENSITIVE_DATA:
command_parts.append(SENSITIVE_DATA_SUBSTITUTE)
continue
arg_is_the_key = i == 0
if arg_is_the_key:
command_parts.append(repr(arg))
else:
if should_send_default_pii():
command_parts.append(repr(arg))
else:
command_parts.append(SENSITIVE_DATA_SUBSTITUTE)
command = " ".join(command_parts)
return command
def _safe_decode(key):
# type: (Any) -> str
if isinstance(key, bytes):
try:
return key.decode()
except UnicodeDecodeError:
return ""
return str(key)
def _key_as_string(key):
# type: (Any) -> str
if isinstance(key, (dict, list, tuple)):
key = ", ".join(_safe_decode(x) for x in key)
elif isinstance(key, bytes):
key = _safe_decode(key)
elif key is None:
key = ""
else:
key = str(key)
return key
def _get_safe_key(method_name, args, kwargs):
# type: (str, Optional[tuple[Any, ...]], Optional[dict[str, Any]]) -> Optional[tuple[str, ...]]
"""
Gets the key (or keys) from the given method_name.
The method_name could be a redis command or a django caching command
"""
key = None
if args is not None and method_name.lower() in _MULTI_KEY_COMMANDS:
# for example redis "mget"
key = tuple(args)
elif args is not None and len(args) >= 1:
# for example django "set_many/get_many" or redis "get"
if isinstance(args[0], (dict, list, tuple)):
key = tuple(args[0])
else:
key = (args[0],)
elif kwargs is not None and "key" in kwargs:
# this is a legacy case for older versions of Django
if isinstance(kwargs["key"], (list, tuple)):
if len(kwargs["key"]) > 0:
key = tuple(kwargs["key"])
else:
if kwargs["key"] is not None:
key = (kwargs["key"],)
return key
def _parse_rediscluster_command(command):
# type: (Any) -> Sequence[Any]
return command.args
def _set_pipeline_data(
span, is_cluster, get_command_args_fn, is_transaction, command_stack
):
# type: (Span, bool, Any, bool, Sequence[Any]) -> None
span.set_tag("redis.is_cluster", is_cluster)
span.set_tag("redis.transaction", is_transaction)
commands = []
for i, arg in enumerate(command_stack):
if i >= _MAX_NUM_COMMANDS:
break
command = get_command_args_fn(arg)
commands.append(_get_safe_command(command[0], command[1:]))
span.set_data(
"redis.commands",
{
"count": len(command_stack),
"first_ten": commands,
},
)
def _set_client_data(span, is_cluster, name, *args):
# type: (Span, bool, str, *Any) -> None
span.set_tag("redis.is_cluster", is_cluster)
if name:
span.set_tag("redis.command", name)
span.set_tag(SPANDATA.DB_OPERATION, name)
if name and args:
name_low = name.lower()
if (name_low in _SINGLE_KEY_COMMANDS) or (
name_low in _MULTI_KEY_COMMANDS and len(args) == 1
):
span.set_tag("redis.key", args[0])