session.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import uuid
  2. from datetime import datetime, timezone
  3. from sentry_sdk.utils import format_timestamp
  4. from typing import TYPE_CHECKING
  5. if TYPE_CHECKING:
  6. from typing import Optional
  7. from typing import Union
  8. from typing import Any
  9. from typing import Dict
  10. from sentry_sdk._types import SessionStatus
  11. def _minute_trunc(ts: "datetime") -> "datetime":
  12. return ts.replace(second=0, microsecond=0)
  13. def _make_uuid(
  14. val: "Union[str, uuid.UUID]",
  15. ) -> "uuid.UUID":
  16. if isinstance(val, uuid.UUID):
  17. return val
  18. return uuid.UUID(val)
  19. class Session:
  20. def __init__(
  21. self,
  22. sid: "Optional[Union[str, uuid.UUID]]" = None,
  23. did: "Optional[str]" = None,
  24. timestamp: "Optional[datetime]" = None,
  25. started: "Optional[datetime]" = None,
  26. duration: "Optional[float]" = None,
  27. status: "Optional[SessionStatus]" = None,
  28. release: "Optional[str]" = None,
  29. environment: "Optional[str]" = None,
  30. user_agent: "Optional[str]" = None,
  31. ip_address: "Optional[str]" = None,
  32. errors: "Optional[int]" = None,
  33. user: "Optional[Any]" = None,
  34. session_mode: str = "application",
  35. ) -> None:
  36. if sid is None:
  37. sid = uuid.uuid4()
  38. if started is None:
  39. started = datetime.now(timezone.utc)
  40. if status is None:
  41. status = "ok"
  42. self.status = status
  43. self.did: "Optional[str]" = None
  44. self.started = started
  45. self.release: "Optional[str]" = None
  46. self.environment: "Optional[str]" = None
  47. self.duration: "Optional[float]" = None
  48. self.user_agent: "Optional[str]" = None
  49. self.ip_address: "Optional[str]" = None
  50. self.session_mode: str = session_mode
  51. self.errors = 0
  52. self.update(
  53. sid=sid,
  54. did=did,
  55. timestamp=timestamp,
  56. duration=duration,
  57. release=release,
  58. environment=environment,
  59. user_agent=user_agent,
  60. ip_address=ip_address,
  61. errors=errors,
  62. user=user,
  63. )
  64. @property
  65. def truncated_started(self) -> "datetime":
  66. return _minute_trunc(self.started)
  67. def update(
  68. self,
  69. sid: "Optional[Union[str, uuid.UUID]]" = None,
  70. did: "Optional[str]" = None,
  71. timestamp: "Optional[datetime]" = None,
  72. started: "Optional[datetime]" = None,
  73. duration: "Optional[float]" = None,
  74. status: "Optional[SessionStatus]" = None,
  75. release: "Optional[str]" = None,
  76. environment: "Optional[str]" = None,
  77. user_agent: "Optional[str]" = None,
  78. ip_address: "Optional[str]" = None,
  79. errors: "Optional[int]" = None,
  80. user: "Optional[Any]" = None,
  81. ) -> None:
  82. # If a user is supplied we pull some data form it
  83. if user:
  84. if ip_address is None:
  85. ip_address = user.get("ip_address")
  86. if did is None:
  87. did = user.get("id") or user.get("email") or user.get("username")
  88. if sid is not None:
  89. self.sid = _make_uuid(sid)
  90. if did is not None:
  91. self.did = str(did)
  92. if timestamp is None:
  93. timestamp = datetime.now(timezone.utc)
  94. self.timestamp = timestamp
  95. if started is not None:
  96. self.started = started
  97. if duration is not None:
  98. self.duration = duration
  99. if release is not None:
  100. self.release = release
  101. if environment is not None:
  102. self.environment = environment
  103. if ip_address is not None:
  104. self.ip_address = ip_address
  105. if user_agent is not None:
  106. self.user_agent = user_agent
  107. if errors is not None:
  108. self.errors = errors
  109. if status is not None:
  110. self.status = status
  111. def close(
  112. self,
  113. status: "Optional[SessionStatus]" = None,
  114. ) -> "Any":
  115. if status is None and self.status == "ok":
  116. status = "exited"
  117. if status is not None:
  118. self.update(status=status)
  119. def get_json_attrs(
  120. self,
  121. with_user_info: "Optional[bool]" = True,
  122. ) -> "Any":
  123. attrs = {}
  124. if self.release is not None:
  125. attrs["release"] = self.release
  126. if self.environment is not None:
  127. attrs["environment"] = self.environment
  128. if with_user_info:
  129. if self.ip_address is not None:
  130. attrs["ip_address"] = self.ip_address
  131. if self.user_agent is not None:
  132. attrs["user_agent"] = self.user_agent
  133. return attrs
  134. def to_json(self) -> "Any":
  135. rv: "Dict[str, Any]" = {
  136. "sid": str(self.sid),
  137. "init": True,
  138. "started": format_timestamp(self.started),
  139. "timestamp": format_timestamp(self.timestamp),
  140. "status": self.status,
  141. }
  142. if self.errors:
  143. rv["errors"] = self.errors
  144. if self.did is not None:
  145. rv["did"] = self.did
  146. if self.duration is not None:
  147. rv["duration"] = self.duration
  148. attrs = self.get_json_attrs()
  149. if attrs:
  150. rv["attrs"] = attrs
  151. return rv