prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Do not add redis SET data in span description when `set_default_pii=False`
  ### Problem Statement
  
  Currently the redis integration records a span for all redis commands. This is good. 
  But when `send_default_pii=False` the value of the redis SET command (https://redis.io/commands/set/) should be redacted.
  
  ### Solution Brainstorm
  
  do it
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `sentry_sdk/integrations/redis.py`
  Content:
  ```
  1 from __future__ import absolute_import
  2 
  3 from sentry_sdk import Hub
  4 from sentry_sdk.consts import OP
  5 from sentry_sdk.utils import capture_internal_exceptions, logger
  6 from sentry_sdk.integrations import Integration, DidNotEnable
  7 
  8 from sentry_sdk._types import TYPE_CHECKING
  9 
  10 if TYPE_CHECKING:
  11     from typing import Any, Sequence
  12 
  13 _SINGLE_KEY_COMMANDS = frozenset(
  14     ["decr", "decrby", "get", "incr", "incrby", "pttl", "set", "setex", "setnx", "ttl"]
  15 )
  16 _MULTI_KEY_COMMANDS = frozenset(["del", "touch", "unlink"])
  17 
  18 #: Trim argument lists to this many values
  19 _MAX_NUM_ARGS = 10
  20 
  21 
  22 def patch_redis_pipeline(pipeline_cls, is_cluster, get_command_args_fn):
  23     # type: (Any, bool, Any) -> None
  24     old_execute = pipeline_cls.execute
  25 
  26     def sentry_patched_execute(self, *args, **kwargs):
  27         # type: (Any, *Any, **Any) -> Any
  28         hub = Hub.current
  29 
  30         if hub.get_integration(RedisIntegration) is None:
  31             return old_execute(self, *args, **kwargs)
  32 
  33         with hub.start_span(
  34             op=OP.DB_REDIS, description="redis.pipeline.execute"
  35         ) as span:
  36             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},
  55                 )
  56 
  57             return old_execute(self, *args, **kwargs)
  58 
  59     pipeline_cls.execute = sentry_patched_execute
  60 
  61 
  62 def _get_redis_command_args(command):
  63     # type: (Any) -> Sequence[Any]
  64     return command[0]
  65 
  66 
  67 def _parse_rediscluster_command(command):
  68     # type: (Any) -> Sequence[Any]
  69     return command.args
  70 
  71 
  72 def _patch_rediscluster():
  73     # type: () -> None
  74     try:
  75         import rediscluster  # type: ignore
  76     except ImportError:
  77         return
  78 
  79     patch_redis_client(rediscluster.RedisCluster, is_cluster=True)
  80 
  81     # up to v1.3.6, __version__ attribute is a tuple
  82     # from v2.0.0, __version__ is a string and VERSION a tuple
  83     version = getattr(rediscluster, "VERSION", rediscluster.__version__)
  84 
  85     # StrictRedisCluster was introduced in v0.2.0 and removed in v2.0.0
  86     # https://github.com/Grokzen/redis-py-cluster/blob/master/docs/release-notes.rst
  87     if (0, 2, 0) < version < (2, 0, 0):
  88         pipeline_cls = rediscluster.pipeline.StrictClusterPipeline
  89         patch_redis_client(rediscluster.StrictRedisCluster, is_cluster=True)
  90     else:
  91         pipeline_cls = rediscluster.pipeline.ClusterPipeline
  92 
  93     patch_redis_pipeline(pipeline_cls, True, _parse_rediscluster_command)
  94 
  95 
  96 class RedisIntegration(Integration):
  97     identifier = "redis"
  98 
  99     @staticmethod
  100     def setup_once():
  101         # type: () -> None
  102         try:
  103             import redis
  104         except ImportError:
  105             raise DidNotEnable("Redis client not installed")
  106 
  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)
  124 
  125         try:
  126             _patch_rediscluster()
  127         except Exception:
  128             logger.exception("Error occurred while patching `rediscluster` library")
  129 
  130 
  131 def patch_redis_client(cls, is_cluster):
  132     # type: (Any, bool) -> None
  133     """
  134     This function can be used to instrument custom redis client classes or
  135     subclasses.
  136     """
  137     old_execute_command = cls.execute_command
  138 
  139     def sentry_patched_execute_command(self, name, *args, **kwargs):
  140         # type: (Any, str, *Any, **Any) -> Any
  141         hub = Hub.current
  142 
  143         if hub.get_integration(RedisIntegration) is None:
  144             return old_execute_command(self, name, *args, **kwargs)
  145 
  146         description = name
  147 
  148         with capture_internal_exceptions():
  149             description_parts = [name]
  150             for i, arg in enumerate(args):
  151                 if i > _MAX_NUM_ARGS:
  152                     break
  153 
  154                 description_parts.append(repr(arg))
  155 
  156             description = " ".join(description_parts)
  157 
  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 
  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])
  169 
  170             return old_execute_command(self, name, *args, **kwargs)
  171 
  172     cls.execute_command = sentry_patched_execute_command
  173
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/sentry_sdk/integrations/redis.py b/sentry_sdk/integrations/redis.py
  --- a/sentry_sdk/integrations/redis.py
  +++ b/sentry_sdk/integrations/redis.py
  @@ -2,7 +2,12 @@
   
   from sentry_sdk import Hub
   from sentry_sdk.consts import OP
  -from sentry_sdk.utils import capture_internal_exceptions, logger
  +from sentry_sdk.hub import _should_send_default_pii
  +from sentry_sdk.utils import (
  +    SENSITIVE_DATA_SUBSTITUTE,
  +    capture_internal_exceptions,
  +    logger,
  +)
   from sentry_sdk.integrations import Integration, DidNotEnable
   
   from sentry_sdk._types import TYPE_CHECKING
  @@ -15,8 +20,13 @@
   )
   _MULTI_KEY_COMMANDS = frozenset(["del", "touch", "unlink"])
   
  -#: Trim argument lists to this many values
  -_MAX_NUM_ARGS = 10
  +_COMMANDS_INCLUDING_SENSITIVE_DATA = [
  +    "auth",
  +]
  +
  +_MAX_NUM_ARGS = 10  # Trim argument lists to this many values
  +
  +_DEFAULT_MAX_DATA_SIZE = 1024
   
   
   def patch_redis_pipeline(pipeline_cls, is_cluster, get_command_args_fn):
  @@ -96,6 +106,10 @@
   class RedisIntegration(Integration):
       identifier = "redis"
   
  +    def __init__(self, max_data_size=_DEFAULT_MAX_DATA_SIZE):
  +        # type: (int) -> None
  +        self.max_data_size = max_data_size
  +
       @staticmethod
       def setup_once():
           # type: () -> None
  @@ -139,8 +153,9 @@
       def sentry_patched_execute_command(self, name, *args, **kwargs):
           # type: (Any, str, *Any, **Any) -> Any
           hub = Hub.current
  +        integration = hub.get_integration(RedisIntegration)
   
  -        if hub.get_integration(RedisIntegration) is None:
  +        if integration is None:
               return old_execute_command(self, name, *args, **kwargs)
   
           description = name
  @@ -151,12 +166,33 @@
                   if i > _MAX_NUM_ARGS:
                       break
   
  -                description_parts.append(repr(arg))
  +                name_low = name.lower()
  +
  +                if name_low in _COMMANDS_INCLUDING_SENSITIVE_DATA:
  +                    description_parts.append(SENSITIVE_DATA_SUBSTITUTE)
  +                    continue
  +
  +                arg_is_the_key = i == 0
  +                if arg_is_the_key:
  +                    description_parts.append(repr(arg))
  +
  +                else:
  +                    if _should_send_default_pii():
  +                        description_parts.append(repr(arg))
  +                    else:
  +                        description_parts.append(SENSITIVE_DATA_SUBSTITUTE)
   
               description = " ".join(description_parts)
   
  +        data_should_be_truncated = (
  +            integration.max_data_size and len(description) > integration.max_data_size
  +        )
  +        if data_should_be_truncated:
  +            description = description[: integration.max_data_size - len("...")] + "..."
  +
           with hub.start_span(op=OP.DB_REDIS, description=description) as span:
               span.set_tag("redis.is_cluster", is_cluster)
  +
               if name:
                   span.set_tag("redis.command", name)
  
verification_info: {"golden_diff": "diff --git a/sentry_sdk/integrations/redis.py b/sentry_sdk/integrations/redis.py\n--- a/sentry_sdk/integrations/redis.py\n+++ b/sentry_sdk/integrations/redis.py\n@@ -2,7 +2,12 @@\n \n from sentry_sdk import Hub\n from sentry_sdk.consts import OP\n-from sentry_sdk.utils import capture_internal_exceptions, logger\n+from sentry_sdk.hub import _should_send_default_pii\n+from sentry_sdk.utils import (\n+    SENSITIVE_DATA_SUBSTITUTE,\n+    capture_internal_exceptions,\n+    logger,\n+)\n from sentry_sdk.integrations import Integration, DidNotEnable\n \n from sentry_sdk._types import TYPE_CHECKING\n@@ -15,8 +20,13 @@\n )\n _MULTI_KEY_COMMANDS = frozenset([\"del\", \"touch\", \"unlink\"])\n \n-#: Trim argument lists to this many values\n-_MAX_NUM_ARGS = 10\n+_COMMANDS_INCLUDING_SENSITIVE_DATA = [\n+    \"auth\",\n+]\n+\n+_MAX_NUM_ARGS = 10  # Trim argument lists to this many values\n+\n+_DEFAULT_MAX_DATA_SIZE = 1024\n \n \n def patch_redis_pipeline(pipeline_cls, is_cluster, get_command_args_fn):\n@@ -96,6 +106,10 @@\n class RedisIntegration(Integration):\n     identifier = \"redis\"\n \n+    def __init__(self, max_data_size=_DEFAULT_MAX_DATA_SIZE):\n+        # type: (int) -> None\n+        self.max_data_size = max_data_size\n+\n     @staticmethod\n     def setup_once():\n         # type: () -> None\n@@ -139,8 +153,9 @@\n     def sentry_patched_execute_command(self, name, *args, **kwargs):\n         # type: (Any, str, *Any, **Any) -> Any\n         hub = Hub.current\n+        integration = hub.get_integration(RedisIntegration)\n \n-        if hub.get_integration(RedisIntegration) is None:\n+        if integration is None:\n             return old_execute_command(self, name, *args, **kwargs)\n \n         description = name\n@@ -151,12 +166,33 @@\n                 if i > _MAX_NUM_ARGS:\n                     break\n \n-                description_parts.append(repr(arg))\n+                name_low = name.lower()\n+\n+                if name_low in _COMMANDS_INCLUDING_SENSITIVE_DATA:\n+                    description_parts.append(SENSITIVE_DATA_SUBSTITUTE)\n+                    continue\n+\n+                arg_is_the_key = i == 0\n+                if arg_is_the_key:\n+                    description_parts.append(repr(arg))\n+\n+                else:\n+                    if _should_send_default_pii():\n+                        description_parts.append(repr(arg))\n+                    else:\n+                        description_parts.append(SENSITIVE_DATA_SUBSTITUTE)\n \n             description = \" \".join(description_parts)\n \n+        data_should_be_truncated = (\n+            integration.max_data_size and len(description) > integration.max_data_size\n+        )\n+        if data_should_be_truncated:\n+            description = description[: integration.max_data_size - len(\"...\")] + \"...\"\n+\n         with hub.start_span(op=OP.DB_REDIS, description=description) as span:\n             span.set_tag(\"redis.is_cluster\", is_cluster)\n+\n             if name:\n                 span.set_tag(\"redis.command\", name)\n", "issue": "Do not add redis SET data in span description when `set_default_pii=False`\n### Problem Statement\n\nCurrently the redis integration records a span for all redis commands. This is good. \r\nBut when `send_default_pii=False` the value of the redis SET command (https://redis.io/commands/set/) should be redacted.\n\n### Solution Brainstorm\n\ndo it\n", "before_files": [{"content": "from __future__ import absolute_import\n\nfrom sentry_sdk import Hub\nfrom sentry_sdk.consts import OP\nfrom sentry_sdk.utils import capture_internal_exceptions, logger\nfrom sentry_sdk.integrations import Integration, DidNotEnable\n\nfrom sentry_sdk._types import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing import Any, Sequence\n\n_SINGLE_KEY_COMMANDS = frozenset(\n    [\"decr\", \"decrby\", \"get\", \"incr\", \"incrby\", \"pttl\", \"set\", \"setex\", \"setnx\", \"ttl\"]\n)\n_MULTI_KEY_COMMANDS = frozenset([\"del\", \"touch\", \"unlink\"])\n\n#: Trim argument lists to this many values\n_MAX_NUM_ARGS = 10\n\n\ndef patch_redis_pipeline(pipeline_cls, is_cluster, get_command_args_fn):\n    # type: (Any, bool, Any) -> None\n    old_execute = pipeline_cls.execute\n\n    def sentry_patched_execute(self, *args, **kwargs):\n        # type: (Any, *Any, **Any) -> Any\n        hub = Hub.current\n\n        if hub.get_integration(RedisIntegration) is None:\n            return old_execute(self, *args, **kwargs)\n\n        with hub.start_span(\n            op=OP.DB_REDIS, description=\"redis.pipeline.execute\"\n        ) as span:\n            with capture_internal_exceptions():\n                span.set_tag(\"redis.is_cluster\", is_cluster)\n                transaction = self.transaction if not is_cluster else False\n                span.set_tag(\"redis.transaction\", transaction)\n\n                commands = []\n                for i, arg in enumerate(self.command_stack):\n                    if i > _MAX_NUM_ARGS:\n                        break\n                    command_args = []\n                    for j, command_arg in enumerate(get_command_args_fn(arg)):\n                        if j > 0:\n                            command_arg = repr(command_arg)\n                        command_args.append(command_arg)\n                    commands.append(\" \".join(command_args))\n\n                span.set_data(\n                    \"redis.commands\",\n                    {\"count\": len(self.command_stack), \"first_ten\": commands},\n                )\n\n            return old_execute(self, *args, **kwargs)\n\n    pipeline_cls.execute = sentry_patched_execute\n\n\ndef _get_redis_command_args(command):\n    # type: (Any) -> Sequence[Any]\n    return command[0]\n\n\ndef _parse_rediscluster_command(command):\n    # type: (Any) -> Sequence[Any]\n    return command.args\n\n\ndef _patch_rediscluster():\n    # type: () -> None\n    try:\n        import rediscluster  # type: ignore\n    except ImportError:\n        return\n\n    patch_redis_client(rediscluster.RedisCluster, is_cluster=True)\n\n    # up to v1.3.6, __version__ attribute is a tuple\n    # from v2.0.0, __version__ is a string and VERSION a tuple\n    version = getattr(rediscluster, \"VERSION\", rediscluster.__version__)\n\n    # StrictRedisCluster was introduced in v0.2.0 and removed in v2.0.0\n    # https://github.com/Grokzen/redis-py-cluster/blob/master/docs/release-notes.rst\n    if (0, 2, 0) < version < (2, 0, 0):\n        pipeline_cls = rediscluster.pipeline.StrictClusterPipeline\n        patch_redis_client(rediscluster.StrictRedisCluster, is_cluster=True)\n    else:\n        pipeline_cls = rediscluster.pipeline.ClusterPipeline\n\n    patch_redis_pipeline(pipeline_cls, True, _parse_rediscluster_command)\n\n\nclass RedisIntegration(Integration):\n    identifier = \"redis\"\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        try:\n            import redis\n        except ImportError:\n            raise DidNotEnable(\"Redis client not installed\")\n\n        patch_redis_client(redis.StrictRedis, is_cluster=False)\n        patch_redis_pipeline(redis.client.Pipeline, False, _get_redis_command_args)\n        try:\n            strict_pipeline = redis.client.StrictPipeline  # type: ignore\n        except AttributeError:\n            pass\n        else:\n            patch_redis_pipeline(strict_pipeline, False, _get_redis_command_args)\n\n        try:\n            import rb.clients  # type: ignore\n        except ImportError:\n            pass\n        else:\n            patch_redis_client(rb.clients.FanoutClient, is_cluster=False)\n            patch_redis_client(rb.clients.MappingClient, is_cluster=False)\n            patch_redis_client(rb.clients.RoutingClient, is_cluster=False)\n\n        try:\n            _patch_rediscluster()\n        except Exception:\n            logger.exception(\"Error occurred while patching `rediscluster` library\")\n\n\ndef patch_redis_client(cls, is_cluster):\n    # type: (Any, bool) -> None\n    \"\"\"\n    This function can be used to instrument custom redis client classes or\n    subclasses.\n    \"\"\"\n    old_execute_command = cls.execute_command\n\n    def sentry_patched_execute_command(self, name, *args, **kwargs):\n        # type: (Any, str, *Any, **Any) -> Any\n        hub = Hub.current\n\n        if hub.get_integration(RedisIntegration) is None:\n            return old_execute_command(self, name, *args, **kwargs)\n\n        description = name\n\n        with capture_internal_exceptions():\n            description_parts = [name]\n            for i, arg in enumerate(args):\n                if i > _MAX_NUM_ARGS:\n                    break\n\n                description_parts.append(repr(arg))\n\n            description = \" \".join(description_parts)\n\n        with hub.start_span(op=OP.DB_REDIS, description=description) as span:\n            span.set_tag(\"redis.is_cluster\", is_cluster)\n            if name:\n                span.set_tag(\"redis.command\", name)\n\n            if name and args:\n                name_low = name.lower()\n                if (name_low in _SINGLE_KEY_COMMANDS) or (\n                    name_low in _MULTI_KEY_COMMANDS and len(args) == 1\n                ):\n                    span.set_tag(\"redis.key\", args[0])\n\n            return old_execute_command(self, name, *args, **kwargs)\n\n    cls.execute_command = sentry_patched_execute_command\n", "path": "sentry_sdk/integrations/redis.py"}], "after_files": [{"content": "from __future__ import absolute_import\n\nfrom sentry_sdk import Hub\nfrom sentry_sdk.consts import OP\nfrom sentry_sdk.hub import _should_send_default_pii\nfrom sentry_sdk.utils import (\n    SENSITIVE_DATA_SUBSTITUTE,\n    capture_internal_exceptions,\n    logger,\n)\nfrom sentry_sdk.integrations import Integration, DidNotEnable\n\nfrom sentry_sdk._types import TYPE_CHECKING\n\nif TYPE_CHECKING:\n    from typing import Any, Sequence\n\n_SINGLE_KEY_COMMANDS = frozenset(\n    [\"decr\", \"decrby\", \"get\", \"incr\", \"incrby\", \"pttl\", \"set\", \"setex\", \"setnx\", \"ttl\"]\n)\n_MULTI_KEY_COMMANDS = frozenset([\"del\", \"touch\", \"unlink\"])\n\n_COMMANDS_INCLUDING_SENSITIVE_DATA = [\n    \"auth\",\n]\n\n_MAX_NUM_ARGS = 10  # Trim argument lists to this many values\n\n_DEFAULT_MAX_DATA_SIZE = 1024\n\n\ndef patch_redis_pipeline(pipeline_cls, is_cluster, get_command_args_fn):\n    # type: (Any, bool, Any) -> None\n    old_execute = pipeline_cls.execute\n\n    def sentry_patched_execute(self, *args, **kwargs):\n        # type: (Any, *Any, **Any) -> Any\n        hub = Hub.current\n\n        if hub.get_integration(RedisIntegration) is None:\n            return old_execute(self, *args, **kwargs)\n\n        with hub.start_span(\n            op=OP.DB_REDIS, description=\"redis.pipeline.execute\"\n        ) as span:\n            with capture_internal_exceptions():\n                span.set_tag(\"redis.is_cluster\", is_cluster)\n                transaction = self.transaction if not is_cluster else False\n                span.set_tag(\"redis.transaction\", transaction)\n\n                commands = []\n                for i, arg in enumerate(self.command_stack):\n                    if i > _MAX_NUM_ARGS:\n                        break\n                    command_args = []\n                    for j, command_arg in enumerate(get_command_args_fn(arg)):\n                        if j > 0:\n                            command_arg = repr(command_arg)\n                        command_args.append(command_arg)\n                    commands.append(\" \".join(command_args))\n\n                span.set_data(\n                    \"redis.commands\",\n                    {\"count\": len(self.command_stack), \"first_ten\": commands},\n                )\n\n            return old_execute(self, *args, **kwargs)\n\n    pipeline_cls.execute = sentry_patched_execute\n\n\ndef _get_redis_command_args(command):\n    # type: (Any) -> Sequence[Any]\n    return command[0]\n\n\ndef _parse_rediscluster_command(command):\n    # type: (Any) -> Sequence[Any]\n    return command.args\n\n\ndef _patch_rediscluster():\n    # type: () -> None\n    try:\n        import rediscluster  # type: ignore\n    except ImportError:\n        return\n\n    patch_redis_client(rediscluster.RedisCluster, is_cluster=True)\n\n    # up to v1.3.6, __version__ attribute is a tuple\n    # from v2.0.0, __version__ is a string and VERSION a tuple\n    version = getattr(rediscluster, \"VERSION\", rediscluster.__version__)\n\n    # StrictRedisCluster was introduced in v0.2.0 and removed in v2.0.0\n    # https://github.com/Grokzen/redis-py-cluster/blob/master/docs/release-notes.rst\n    if (0, 2, 0) < version < (2, 0, 0):\n        pipeline_cls = rediscluster.pipeline.StrictClusterPipeline\n        patch_redis_client(rediscluster.StrictRedisCluster, is_cluster=True)\n    else:\n        pipeline_cls = rediscluster.pipeline.ClusterPipeline\n\n    patch_redis_pipeline(pipeline_cls, True, _parse_rediscluster_command)\n\n\nclass RedisIntegration(Integration):\n    identifier = \"redis\"\n\n    def __init__(self, max_data_size=_DEFAULT_MAX_DATA_SIZE):\n        # type: (int) -> None\n        self.max_data_size = max_data_size\n\n    @staticmethod\n    def setup_once():\n        # type: () -> None\n        try:\n            import redis\n        except ImportError:\n            raise DidNotEnable(\"Redis client not installed\")\n\n        patch_redis_client(redis.StrictRedis, is_cluster=False)\n        patch_redis_pipeline(redis.client.Pipeline, False, _get_redis_command_args)\n        try:\n            strict_pipeline = redis.client.StrictPipeline  # type: ignore\n        except AttributeError:\n            pass\n        else:\n            patch_redis_pipeline(strict_pipeline, False, _get_redis_command_args)\n\n        try:\n            import rb.clients  # type: ignore\n        except ImportError:\n            pass\n        else:\n            patch_redis_client(rb.clients.FanoutClient, is_cluster=False)\n            patch_redis_client(rb.clients.MappingClient, is_cluster=False)\n            patch_redis_client(rb.clients.RoutingClient, is_cluster=False)\n\n        try:\n            _patch_rediscluster()\n        except Exception:\n            logger.exception(\"Error occurred while patching `rediscluster` library\")\n\n\ndef patch_redis_client(cls, is_cluster):\n    # type: (Any, bool) -> None\n    \"\"\"\n    This function can be used to instrument custom redis client classes or\n    subclasses.\n    \"\"\"\n    old_execute_command = cls.execute_command\n\n    def sentry_patched_execute_command(self, name, *args, **kwargs):\n        # type: (Any, str, *Any, **Any) -> Any\n        hub = Hub.current\n        integration = hub.get_integration(RedisIntegration)\n\n        if integration is None:\n            return old_execute_command(self, name, *args, **kwargs)\n\n        description = name\n\n        with capture_internal_exceptions():\n            description_parts = [name]\n            for i, arg in enumerate(args):\n                if i > _MAX_NUM_ARGS:\n                    break\n\n                name_low = name.lower()\n\n                if name_low in _COMMANDS_INCLUDING_SENSITIVE_DATA:\n                    description_parts.append(SENSITIVE_DATA_SUBSTITUTE)\n                    continue\n\n                arg_is_the_key = i == 0\n                if arg_is_the_key:\n                    description_parts.append(repr(arg))\n\n                else:\n                    if _should_send_default_pii():\n                        description_parts.append(repr(arg))\n                    else:\n                        description_parts.append(SENSITIVE_DATA_SUBSTITUTE)\n\n            description = \" \".join(description_parts)\n\n        data_should_be_truncated = (\n            integration.max_data_size and len(description) > integration.max_data_size\n        )\n        if data_should_be_truncated:\n            description = description[: integration.max_data_size - len(\"...\")] + \"...\"\n\n        with hub.start_span(op=OP.DB_REDIS, description=description) as span:\n            span.set_tag(\"redis.is_cluster\", is_cluster)\n\n            if name:\n                span.set_tag(\"redis.command\", name)\n\n            if name and args:\n                name_low = name.lower()\n                if (name_low in _SINGLE_KEY_COMMANDS) or (\n                    name_low in _MULTI_KEY_COMMANDS and len(args) == 1\n                ):\n                    span.set_tag(\"redis.key\", args[0])\n\n            return old_execute_command(self, name, *args, **kwargs)\n\n    cls.execute_command = sentry_patched_execute_command\n", "path": "sentry_sdk/integrations/redis.py"}]}