caches.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. """
  2. Code used for the Caches module in Sentry
  3. """
  4. from sentry_sdk.consts import OP, SPANDATA
  5. from sentry_sdk.integrations.redis.utils import _get_safe_key, _key_as_string
  6. from sentry_sdk.utils import capture_internal_exceptions
  7. GET_COMMANDS = ("get", "mget")
  8. SET_COMMANDS = ("set", "setex")
  9. from typing import TYPE_CHECKING
  10. if TYPE_CHECKING:
  11. from sentry_sdk.integrations.redis import RedisIntegration
  12. from sentry_sdk.tracing import Span
  13. from typing import Any, Optional
  14. def _get_op(name: str) -> "Optional[str]":
  15. op = None
  16. if name.lower() in GET_COMMANDS:
  17. op = OP.CACHE_GET
  18. elif name.lower() in SET_COMMANDS:
  19. op = OP.CACHE_PUT
  20. return op
  21. def _compile_cache_span_properties(
  22. redis_command: str,
  23. args: "tuple[Any, ...]",
  24. kwargs: "dict[str, Any]",
  25. integration: "RedisIntegration",
  26. ) -> "dict[str, Any]":
  27. key = _get_safe_key(redis_command, args, kwargs)
  28. key_as_string = _key_as_string(key)
  29. keys_as_string = key_as_string.split(", ")
  30. is_cache_key = False
  31. for prefix in integration.cache_prefixes:
  32. for kee in keys_as_string:
  33. if kee.startswith(prefix):
  34. is_cache_key = True
  35. break
  36. if is_cache_key:
  37. break
  38. value = None
  39. if redis_command.lower() in SET_COMMANDS:
  40. value = args[-1]
  41. properties = {
  42. "op": _get_op(redis_command),
  43. "description": _get_cache_span_description(
  44. redis_command, args, kwargs, integration
  45. ),
  46. "key": key,
  47. "key_as_string": key_as_string,
  48. "redis_command": redis_command.lower(),
  49. "is_cache_key": is_cache_key,
  50. "value": value,
  51. }
  52. return properties
  53. def _get_cache_span_description(
  54. redis_command: str,
  55. args: "tuple[Any, ...]",
  56. kwargs: "dict[str, Any]",
  57. integration: "RedisIntegration",
  58. ) -> str:
  59. description = _key_as_string(_get_safe_key(redis_command, args, kwargs))
  60. if integration.max_data_size and len(description) > integration.max_data_size:
  61. description = description[: integration.max_data_size - len("...")] + "..."
  62. return description
  63. def _set_cache_data(
  64. span: "Span",
  65. redis_client: "Any",
  66. properties: "dict[str, Any]",
  67. return_value: "Optional[Any]",
  68. ) -> None:
  69. with capture_internal_exceptions():
  70. span.set_data(SPANDATA.CACHE_KEY, properties["key"])
  71. if properties["redis_command"] in GET_COMMANDS:
  72. if return_value is not None:
  73. span.set_data(SPANDATA.CACHE_HIT, True)
  74. size = (
  75. len(str(return_value).encode("utf-8"))
  76. if not isinstance(return_value, bytes)
  77. else len(return_value)
  78. )
  79. span.set_data(SPANDATA.CACHE_ITEM_SIZE, size)
  80. else:
  81. span.set_data(SPANDATA.CACHE_HIT, False)
  82. elif properties["redis_command"] in SET_COMMANDS:
  83. if properties["value"] is not None:
  84. size = (
  85. len(properties["value"].encode("utf-8"))
  86. if not isinstance(properties["value"], bytes)
  87. else len(properties["value"])
  88. )
  89. span.set_data(SPANDATA.CACHE_ITEM_SIZE, size)
  90. try:
  91. connection_params = redis_client.connection_pool.connection_kwargs
  92. except AttributeError:
  93. # If it is a cluster, there is no connection_pool attribute so we
  94. # need to get the default node from the cluster instance
  95. default_node = redis_client.get_default_node()
  96. connection_params = {
  97. "host": default_node.host,
  98. "port": default_node.port,
  99. }
  100. host = connection_params.get("host")
  101. if host is not None:
  102. span.set_data(SPANDATA.NETWORK_PEER_ADDRESS, host)
  103. port = connection_params.get("port")
  104. if port is not None:
  105. span.set_data(SPANDATA.NETWORK_PEER_PORT, port)