redis_cluster.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """
  2. Instrumentation for RedisCluster
  3. This is part of the main redis-py client.
  4. https://github.com/redis/redis-py/blob/master/redis/cluster.py
  5. """
  6. from sentry_sdk.integrations.redis._sync_common import (
  7. patch_redis_client,
  8. patch_redis_pipeline,
  9. )
  10. from sentry_sdk.integrations.redis.modules.queries import _set_db_data_on_span
  11. from sentry_sdk.integrations.redis.utils import _parse_rediscluster_command
  12. from sentry_sdk.utils import capture_internal_exceptions
  13. from typing import TYPE_CHECKING
  14. if TYPE_CHECKING:
  15. from typing import Any
  16. from redis import RedisCluster
  17. from redis.asyncio.cluster import (
  18. RedisCluster as AsyncRedisCluster,
  19. ClusterPipeline as AsyncClusterPipeline,
  20. )
  21. from sentry_sdk.tracing import Span
  22. def _set_async_cluster_db_data(
  23. span: "Span", async_redis_cluster_instance: "AsyncRedisCluster[Any]"
  24. ) -> None:
  25. default_node = async_redis_cluster_instance.get_default_node()
  26. if default_node is not None and default_node.connection_kwargs is not None:
  27. _set_db_data_on_span(span, default_node.connection_kwargs)
  28. def _set_async_cluster_pipeline_db_data(
  29. span: "Span", async_redis_cluster_pipeline_instance: "AsyncClusterPipeline[Any]"
  30. ) -> None:
  31. with capture_internal_exceptions():
  32. client = getattr(async_redis_cluster_pipeline_instance, "cluster_client", None)
  33. if client is None:
  34. # In older redis-py versions, the AsyncClusterPipeline had a `_client`
  35. # attr but it is private so potentially problematic and mypy does not
  36. # recognize it - see
  37. # https://github.com/redis/redis-py/blame/v5.0.0/redis/asyncio/cluster.py#L1386
  38. client = (
  39. async_redis_cluster_pipeline_instance._client # type: ignore[attr-defined]
  40. )
  41. _set_async_cluster_db_data(
  42. span,
  43. client,
  44. )
  45. def _set_cluster_db_data(
  46. span: "Span", redis_cluster_instance: "RedisCluster[Any]"
  47. ) -> None:
  48. default_node = redis_cluster_instance.get_default_node()
  49. if default_node is not None:
  50. connection_params = {
  51. "host": default_node.host,
  52. "port": default_node.port,
  53. }
  54. _set_db_data_on_span(span, connection_params)
  55. def _patch_redis_cluster() -> None:
  56. """Patches the cluster module on redis SDK (as opposed to rediscluster library)"""
  57. try:
  58. from redis import RedisCluster, cluster
  59. except ImportError:
  60. pass
  61. else:
  62. patch_redis_client(
  63. RedisCluster,
  64. is_cluster=True,
  65. set_db_data_fn=_set_cluster_db_data,
  66. )
  67. patch_redis_pipeline(
  68. cluster.ClusterPipeline,
  69. is_cluster=True,
  70. get_command_args_fn=_parse_rediscluster_command,
  71. set_db_data_fn=_set_cluster_db_data,
  72. )
  73. try:
  74. from redis.asyncio import cluster as async_cluster
  75. except ImportError:
  76. pass
  77. else:
  78. from sentry_sdk.integrations.redis._async_common import (
  79. patch_redis_async_client,
  80. patch_redis_async_pipeline,
  81. )
  82. patch_redis_async_client(
  83. async_cluster.RedisCluster,
  84. is_cluster=True,
  85. set_db_data_fn=_set_async_cluster_db_data,
  86. )
  87. patch_redis_async_pipeline(
  88. async_cluster.ClusterPipeline,
  89. is_cluster=True,
  90. get_command_args_fn=_parse_rediscluster_command,
  91. set_db_data_fn=_set_async_cluster_pipeline_db_data,
  92. )