socket.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import socket
  2. import sentry_sdk
  3. from sentry_sdk._types import MYPY
  4. from sentry_sdk.consts import OP
  5. from sentry_sdk.integrations import Integration
  6. if MYPY:
  7. from socket import AddressFamily, SocketKind
  8. from typing import Tuple, Optional, Union, List
  9. __all__ = ["SocketIntegration"]
  10. class SocketIntegration(Integration):
  11. identifier = "socket"
  12. origin = f"auto.socket.{identifier}"
  13. @staticmethod
  14. def setup_once():
  15. # type: () -> None
  16. """
  17. patches two of the most used functions of socket: create_connection and getaddrinfo(dns resolver)
  18. """
  19. _patch_create_connection()
  20. _patch_getaddrinfo()
  21. def _get_span_description(host, port):
  22. # type: (Union[bytes, str, None], Union[bytes, str, int, None]) -> str
  23. try:
  24. host = host.decode() # type: ignore
  25. except (UnicodeDecodeError, AttributeError):
  26. pass
  27. try:
  28. port = port.decode() # type: ignore
  29. except (UnicodeDecodeError, AttributeError):
  30. pass
  31. description = "%s:%s" % (host, port) # type: ignore
  32. return description
  33. def _patch_create_connection():
  34. # type: () -> None
  35. real_create_connection = socket.create_connection
  36. def create_connection(
  37. address,
  38. timeout=socket._GLOBAL_DEFAULT_TIMEOUT, # type: ignore
  39. source_address=None,
  40. ):
  41. # type: (Tuple[Optional[str], int], Optional[float], Optional[Tuple[Union[bytearray, bytes, str], int]])-> socket.socket
  42. integration = sentry_sdk.get_client().get_integration(SocketIntegration)
  43. if integration is None:
  44. return real_create_connection(address, timeout, source_address)
  45. with sentry_sdk.start_span(
  46. op=OP.SOCKET_CONNECTION,
  47. name=_get_span_description(address[0], address[1]),
  48. origin=SocketIntegration.origin,
  49. ) as span:
  50. span.set_data("address", address)
  51. span.set_data("timeout", timeout)
  52. span.set_data("source_address", source_address)
  53. return real_create_connection(
  54. address=address, timeout=timeout, source_address=source_address
  55. )
  56. socket.create_connection = create_connection # type: ignore
  57. def _patch_getaddrinfo():
  58. # type: () -> None
  59. real_getaddrinfo = socket.getaddrinfo
  60. def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
  61. # type: (Union[bytes, str, None], Union[bytes, str, int, None], int, int, int, int) -> List[Tuple[AddressFamily, SocketKind, int, str, Union[Tuple[str, int], Tuple[str, int, int, int], Tuple[int, bytes]]]]
  62. integration = sentry_sdk.get_client().get_integration(SocketIntegration)
  63. if integration is None:
  64. return real_getaddrinfo(host, port, family, type, proto, flags)
  65. with sentry_sdk.start_span(
  66. op=OP.SOCKET_DNS,
  67. name=_get_span_description(host, port),
  68. origin=SocketIntegration.origin,
  69. ) as span:
  70. span.set_data("host", host)
  71. span.set_data("port", port)
  72. return real_getaddrinfo(host, port, family, type, proto, flags)
  73. socket.getaddrinfo = getaddrinfo