8000 feat: Add envelope abstraction and session tracking (#627) · etherscan-io/sentry-python@427ddb0 · GitHub
[go: up one dir, main page]

Skip to content
.hEHvLI{min-width:0;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .bmcJak{min-width:0;}/*!sc*/ .fyKNMY[data-size="medium"]{color:var(--fgColor-default,var(--color-fg-default,#1F2328));}/*!sc*/ .gUkoLg{-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}/*!sc*/ .dpBUfI{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ @media screen and (min-width:544px){.dpBUfI{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}}/*!sc*/ @media screen and (min-width:768px){.dpBUfI{-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;}}/*!sc*/ @media screen and (min-width:1012px){.dpBUfI{-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;}}/*!sc*/ .hKWjvQ{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;}/*!sc*/ .cvdqJW{width:20px;height:20px;margin-right:8px;margin-top:-1px;margin-left:1px;}/*!sc*/ .dkaFxu{font-weight:600;white-space:nowrap;color:var(--fgColor-default,var(--color-fg-default,#1F2328));}/*!sc*/ .dkaFxu:hover{color:var(--fgColor-default,var(--color-fg-default,#1F2328));-webkit-text-decoration:underline;text-decoration:underline;}/*!sc*/ .irPhWZ{width:60px;}/*!sc*/ .dNbsEP{width:62px;}/*!sc*/ .kHfwUD{width:60px;height:22px;}/*!sc*/ .bHLmSv{position:absolute;inset:0 -2px;cursor:col-resize;background-color:transparent;-webkit-transition-delay:0.1s;transition-delay:0.1s;}/*!sc*/ .bHLmSv:hover{background-color:var(--bgColor-neutral-muted,var(--color-neutral-muted,rgba(175,184,193,0.2)));}/*!sc*/ .hqtbbn{bottom:0 !important;-webkit-clip:rect(1px,1px,1px,1px);clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);height:84px;position:absolute;width:320px;}/*!sc*/ data-styled.g1[id="Box-sc-g0xbh4-0"]{content:"hEHvLI,bmcJak,fyKNMY,gUkoLg,dpBUfI,hKWjvQ,cvdqJW,dkaFxu,irPhWZ,dNbsEP,kHfwUD,bHLmSv,hqtbbn,"}/*!sc*/ .brGdpi{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;-webkit-clip:rect(0,0,0,0);clip:rect(0,0,0,0);white-space:nowrap;border-width:0;}/*!sc*/ data-styled.g4[id="_VisuallyHidden__VisuallyHidden-sc-11jhm7a-0"]{content:"brGdpi,"}/*!sc*/ .jjwhNb{position:relative;display:inline-block;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;}/*!sc*/ .jjwhNb::after{position:absolute;z-index:1000000;display:none;padding:0.5em 0.75em;font:normal normal 11px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";-webkit-font-smoothing:subpixel-antialiased;color:var(--tooltip-fgColor,var(--fgColor-onEmphasis,var(--color-fg-on-emphasis,#ffffff)));text-align:center;-webkit-text-decoration:none;text-decoration:none;text-shadow:none;text-transform:none;-webkit-letter-spacing:normal;-moz-letter-spacing:normal;-ms-letter-spacing:normal;letter-spacing:normal;word-wrap:break-word;white-space:pre;pointer-events:none;content:attr(aria-label);background:var(--tooltip-bgColor,var(--bgColor-emphasis,var(--color-neutral-emphasis-plus,#24292f)));border-radius:6px;opacity:0;}/*!sc*/ @-webkit-keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ @keyframes tooltip-appear{from{opacity:0;}to{opacity:1;}}/*!sc*/ .jjwhNb:hover::after,.jjwhNb:active::after,.jjwhNb:focus::after,.jjwhNb:focus-within::after{display:inline-block;-webkit-text-decoration:none;text-decoration:none;-webkit-animation-name:tooltip-appear;animation-name:tooltip-appear;-webkit-animation-duration:0.1s;animation-duration:0.1s;-webkit-animation-fill-mode:forwards;animation-fill-mode:forwards;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in;-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .jjwhNb.tooltipped-no-delay:hover::after,.jjwhNb.tooltipped-no-delay:active::after,.jjwhNb.tooltipped-no-delay:focus::after,.jjwhNb.tooltipped-no-delay:focus-within::after{-webkit-animation-delay:0s;animation-delay:0s;}/*!sc*/ .jjwhNb.tooltipped-multiline:hover::after,.jjwhNb.tooltipped-multiline:active::after,.jjwhNb.tooltipped-multiline:focus::after,.jjwhNb.tooltipped-multiline:focus-within::after{display:table-cell;}/*!sc*/ .jjwhNb.tooltipped-s::after,.jjwhNb.tooltipped-se::after,.jjwhNb.tooltipped-sw::after{top:100%;right:50%;margin-top:6px;}/*!sc*/ .jjwhNb.tooltipped-se::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .jjwhNb.tooltipped-sw::after{margin-right:-16px;}/*!sc*/ .jjwhNb.tooltipped-n::after,.jjwhNb.tooltipped-ne::after,.jjwhNb.tooltipped-nw::after{right:50%;bottom:100%;margin-bottom:6px;}/*!sc*/ .jjwhNb.tooltipped-ne::after{right:auto;left:50%;margin-left:-16px;}/*!sc*/ .jjwhNb.tooltipped-nw::after{margin-right:-16px;}/*!sc*/ .jjwhNb.tooltipped-s::after,.jjwhNb.tooltipped-n::after{-webkit-transform:translateX(50%);-ms-transform:translateX(50%);transform:translateX(50%);}/*!sc*/ .jjwhNb.tooltipped-w::after{right:100%;bottom:50%;margin-right:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .jjwhNb.tooltipped-e::after{bottom:50%;left:100%;margin-left:6px;-webkit-transform:translateY(50%);-ms-transform:translateY(50%);transform:translateY(50%);}/*!sc*/ .jjwhNb.tooltipped-multiline::after{width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:250px;word-wrap:break-word;white-space:pre-line;border-collapse:separate;}/*!sc*/ .jjwhNb.tooltipped-multiline.tooltipped-s::after,.jjwhNb.tooltipped-multiline.tooltipped-n::after{right:auto;left:50%;-webkit-transform:translateX(-50%);-ms-transform:translateX(-50%);transform:translateX(-50%);}/*!sc*/ .jjwhNb.tooltipped-multiline.tooltipped-w::after,.jjwhNb.tooltipped-multiline.tooltipped-e::after{right:100%;}/*!sc*/ .jjwhNb.tooltipped-align-right-2::after{right:0;margin-right:0;}/*!sc*/ .jjwhNb.tooltipped-align-left-2::after{left:0;margin-left:0;}/*!sc*/ data-styled.g5[id="Tooltip__TooltipBase-sc-17tf59c-0"]{content:"jjwhNb,"}/*!sc*/ .irithh{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:60px;}/*!sc*/ .irithh::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ .ihfxfT{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:62px;}/*!sc*/ .ihfxfT::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ .kRBfod{position:relative;overflow:hidden;-webkit-mask-image:radial-gradient(white,black);mask-image:radial-gradient(white,black);background-color:var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5)));border-radius:3px;display:block;height:1.2em;width:60px;height:22px;}/*!sc*/ .kRBfod::after{-webkit-animation:crVFvv 1.5s infinite linear;animation:crVFvv 1.5s infinite linear;background:linear-gradient(90deg,transparent,var(--bgColor-neutral-muted,var(--color-neutral-subtle,rgba(234,238,242,0.5))),transparent);content:'';position:absolute;-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);bottom:0;left:0;right:0;top:0;}/*!sc*/ data-styled.g27[id="LoadingSkeleton-sc-695d630a-0"]{content:"irithh,ihfxfT,kRBfod,"}/*!sc*/ @-webkit-keyframes crVFvv{0%{-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);}50%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}100%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}}/*!sc*/ @keyframes crVFvv{0%{-webkit-transform:translateX(-100%);-ms-transform:translateX(-100%);transform:translateX(-100%);}50%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}100%{-webkit-transform:translateX(100%);-ms-transform:translateX(100%);transform:translateX(100%);}}/*!sc*/ data-styled.g53[id="sc-keyframes-crVFvv"]{content:"crVFvv,"}/*!sc*/

Commit 427ddb0

Browse files
authored
feat: Add envelope abstraction and session tracking (getsentry#627)
1 parent e680a75 commit 427ddb0

File tree

15 files changed

+930
-57
lines changed

15 files changed

+930
-57
lines changed

sentry_sdk/_types.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from typing import Optional
1313
from typing import Tuple
1414
from typing import Type
15+
from typing_extensions import Literal
1516

1617
ExcInfo = Tuple[
1718
Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]
@@ -29,3 +30,8 @@
2930

3031
# https://github.com/python/mypy/issues/5710
3132
NotImplementedType = Any
33+
34+
EventDataCategory = Literal[
35+
"default", "error", "crash", "transaction", "security", "attachment", "session"
36+
]
37+
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]

sentry_sdk/client.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,21 @@
1818
from sentry_sdk.consts import DEFAULT_OPTIONS, SDK_INFO, ClientConstructor
1919
from sentry_sdk.integrations import setup_integrations
2020
from sentry_sdk.utils import ContextVar
21+
from sentry_sdk.sessions import SessionFlusher
22+
from sentry_sdk.envelope import Envelope
2123

2224
from sentry_sdk._types import MYPY
2325

2426
if MYPY:
2527
from typing import Any
2628
from typing import Callable
2729
from typing import Dict
30+
from typing import List
2831
from typing import Optional
2932

3033
from sentry_sdk.scope import Scope
3134
from sentry_sdk._types import Event, Hint
35+
from sentry_sdk.sessions import Session
3236

3337

3438
_client_init_debug = ContextVar("client_init_debug")
@@ -91,9 +95,20 @@ def __setstate__(self, state):
9195
def _init_impl(self):
9296
# type: () -> None
9397
old_debug = _client_init_debug.get(False)
98+
99+
def _send_sessions(sessions):
100+
# type: (List[Any]) -> None
101+
transport = self.transport
102+
if sessions and transport:
103+
envelope = Envelope()
104+
for session in sessions:
105+
envelope.add_session(session)
106+
transport.capture_envelope(envelope)
107+
94108
try:
95109
_client_init_debug.set(self.options["debug"])
96110
self.transport = make_transport(self.options)
111+
self.session_flusher = SessionFlusher(flush_func=_send_sessions)
97112

98113
request_bodies = ("always", "never", "small", "medium")
99114
if self.options["request_bodies"] not in request_bodies:
@@ -230,6 +245,48 @@ def _should_capture(
230245

231246
return True
232247

248+
def _update_session_from_event(
249+
self,
250+
session, # type: Session
251+
event, # type: Event
252+
):
253+
# type: (...) -> None
254+
255+
crashed = False
256+
errored = False
257+
user_agent = None
258+
259+
# Figure out if this counts as an error and if we should mark the
260+
# session as crashed.
261+
level = event.get("level")
262+
if level == "fatal":
263+
crashed = True
264+
if not crashed:
265+
exceptions = (event.get("exception") or {}).get("values")
266+
if exceptions:
267+
errored = True
268+
for error in exceptions:
269+
mechanism = error.get("mechanism")
270+
if mechanism and mechanism.get("handled") is False:
271+
crashed = True
272+
break
273+
274+
user = event.get("user")
275+
276+
if session.user_agent is None:
277+
headers = (event.get("request") or {}).get("headers")
278+
for (k, v) in iteritems(headers or {}):
279+
if k.lower() == "user-agent":
280+
user_agent = v
281+
break
282+
283+
session.update(
284+
status="crashed" if crashed else None,
285+< F438 /span>
user=user,
286+
user_agent=user_agent,
287+
errors=session.errors + (errored or crashed),
288+
)
289+
233290
def capture_event(
234291
self,
235292
event, # type: Event
@@ -260,9 +317,25 @@ def capture_event(
260317
event_opt = self._prepare_event(event, hint, scope)
261318
if event_opt is None:
262319
return None
320+
321+
# whenever we capture an event we also check if the session needs
322+
# to be updated based on that information.
323+
session = scope.session if scope else None
324+
if session:
325+
self._update_session_from_event(session, event)
326+
263327
self.transport.capture_event(event_opt)
264328
return event_id
265329

330+
def capture_session(
331+
self, session # type: Session
332+
):
333+
# type: (...) -> None
334+
if not session.release:
335+
logger.info("Discarded session update because of missing release")
336+
else:
337+
self.session_flusher.add_session(session)
338+
266339
def close(
267340
self,
268341
timeout=None, # type: Optional[float]
@@ -275,6 +348,7 @@ def close(
275348
"""
276349
if self.transport is not None:
277350
self.flush(timeout=timeout, callback=callback)
351+
self.session_flusher.kill()
278352
self.transport.kill()
279353
self.transport = None
280354

@@ -294,6 +368,7 @@ def flush(
294368
if self.transport is not None:
295369
if timeout is None:
296370
timeout = self.options["shutdown_timeout"]
371+
self.session_flusher.flush()
297372
self.transport.flush(timeout=timeout, callback=callback)
298373

299374
def __enter__(self):

sentry_sdk/consts.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"max_spans": Optional[int],
2727
"record_sql_params": Optional[bool],
2828
"auto_enabling_integrations": Optional[bool],
29+
"auto_session_tracking": Optional[bool],
2930
},
3031
total=False,
3132
)

0 commit comments

Comments
 (0)
0