| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- 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
- from typing import TYPE_CHECKING
- if TYPE_CHECKING:
- from typing import Any, Optional, Sequence
- from sentry_sdk.tracing import Span
- def _get_safe_command(name: str, args: "Sequence[Any]") -> str:
- command_parts = [name]
- name_low = name.lower()
- send_default_pii = should_send_default_pii()
- for i, arg in enumerate(args):
- if i > _MAX_NUM_ARGS:
- break
- 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 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: "Any") -> str:
- if isinstance(key, bytes):
- try:
- return key.decode()
- except UnicodeDecodeError:
- return ""
- return str(key)
- def _key_as_string(key: "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: str,
- args: "Optional[tuple[Any, ...]]",
- kwargs: "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: "Any") -> "Sequence[Any]":
- return command.args
- def _set_pipeline_data(
- span: "Span",
- is_cluster: bool,
- get_command_args_fn: "Any",
- is_transaction: bool,
- commands_seq: "Sequence[Any]",
- ) -> None:
- span.set_tag("redis.is_cluster", is_cluster)
- span.set_tag("redis.transaction", is_transaction)
- commands = []
- for i, arg in enumerate(commands_seq):
- 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(commands_seq),
- "first_ten": commands,
- },
- )
- def _set_client_data(span: "Span", is_cluster: bool, name: str, *args: "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])
|