Skip to content

feat: Add envelope abstraction and session tracking #627

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c8bd6a4
feat: Add envelope abstraction
mitsuhiko Feb 18, 2020
bede588
ref: Try to refactor client for envelopes
mitsuhiko Feb 18, 2020
e1658dd
feat: Added basic internal session abstraction
mitsuhiko Feb 18, 2020
732e861
feat: Add session capturing to base transport
mitsuhiko Feb 19, 2020
7de5fb0
feat: Added super basic session handling
mitsuhiko Feb 19, 2020
7672659
ref: move session flusher to the client
mitsuhiko Feb 19, 2020
f1ae05d
fix: a bad import
mitsuhiko Feb 19, 2020
a807904
fix: Fix and update test code
mitsuhiko Feb 19, 2020
b82554b
ref: Added fork protection for session flusher
mitsuhiko Feb 19, 2020
b28cda2
feat: Added basic session tracking to WSGI
mitsuhiko Feb 19, 2020
0b57a97
ref: Do not emit sessions without release information
mitsuhiko Feb 20, 2020
de391bf
fix: Correctly pass release and environment to new sessions
mitsuhiko Feb 20, 2020
e875701
fix: correct flush interval
mitsuhiko Feb 20, 2020
57fd15f
Merge branch 'master' into feature/envelopes
mitsuhiko Feb 21, 2020
fa5efbd
ref: format
mitsuhiko Feb 21, 2020
b4e37a2
ref: update sessions from the scope application
mitsuhiko Feb 21, 2020
5d8779f
fix: flask test on older flask versions
mitsuhiko Feb 21, 2020
64b2724
ref: Update session system latest updates
mitsuhiko Feb 23, 2020
a4ba81d
ref: Send init flag
mitsuhiko Feb 23, 2020
9311910
ref: Implement basic split rate limits
mitsuhiko Feb 24, 2020
9dc9097
fix: dicarding of items
mitsuhiko Feb 24, 2020
49eac3e
ref: set the user on the session on scope update
mitsuhiko Feb 24, 2020
276acae
docs: add typing extensions to doc requirements
mitsuhiko Feb 24, 2020
9294ddd
ref: remove hub reference from session
mitsuhiko Mar 3, 2020
c565404
feat: Add debug printing for envelope sending
mitsuhiko Mar 11, 2020
bb4cd0f
ref: Move auto session tracking to experiments
mitsuhiko Mar 11, 2020
7774fde
ref: remove degraded
mitsuhiko Mar 11, 2020
9cb3743
Merge branch 'master' into feature/envelopes
mitsuhiko Mar 11, 2020
52e087a
ref: Fmt
mitsuhiko Mar 11, 2020
0197859
fix: lint
mitsuhiko Mar 11, 2020
b3b035b
ref: meh
mitsuhiko Mar 11, 2020
726928b
ref: Move incorrect type doc
mitsuhiko Mar 11, 2020
4571794
ref: fix lint
mitsuhiko Mar 11, 2020
49f6063
ref: Simplify event type detection
mitsuhiko Mar 11, 2020
13962ad
ref: Reuse format_timestamp
mitsuhiko Mar 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from typing import Optional
from typing import Tuple
from typing import Type
from typing_extensions import Literal

ExcInfo = Tuple[
Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]
Expand All @@ -29,3 +30,8 @@

# https://github.com/python/mypy/issues/5710
NotImplementedType = Any

EventDataCategory = Literal[
"default", "error", "crash", "transaction", "security", "attachment", "session"
]
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]
75 changes: 75 additions & 0 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,21 @@
from sentry_sdk.consts import DEFAULT_OPTIONS, SDK_INFO, ClientConstructor
from sentry_sdk.integrations import setup_integrations
from sentry_sdk.utils import ContextVar
from sentry_sdk.sessions import SessionFlusher
from sentry_sdk.envelope import Envelope

from sentry_sdk._types import MYPY

if MYPY:
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional

from sentry_sdk.scope import Scope
from sentry_sdk._types import Event, Hint
from sentry_sdk.sessions import Session


_client_init_debug = ContextVar("client_init_debug")
Expand Down Expand Up @@ -91,9 +95,20 @@ def __setstate__(self, state):
def _init_impl(self):
# type: () -> None
old_debug = _client_init_debug.get(False)

def _send_sessions(sessions):
# type: (List[Any]) -> None
transport = self.transport
if sessions and transport:
envelope = Envelope()
for session in sessions:
envelope.add_session(session)
transport.capture_envelope(envelope)

try:
_client_init_debug.set(self.options["debug"])
self.transport = make_transport(self.options)
self.session_flusher = SessionFlusher(flush_func=_send_sessions)

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

return True

def _update_session_from_event(
self,
session, # type: Session
event, # type: Event
):
# type: (...) -> None

crashed = False
errored = False
user_agent = None

# Figure out if this counts as an error and if we should mark the
# session as crashed.
level = event.get("level")
if level == "fatal":
crashed = True
if not crashed:
exceptions = (event.get("exception") or {}).get("values")
if exceptions:
errored = True
for error in exceptions:
mechanism = error.get("mechanism")
if mechanism and mechanism.get("handled") is False:
crashed = True
break

user = event.get("user")

if session.user_agent is None:
headers = (event.get("request") or {}).get("headers")
for (k, v) in iteritems(headers or {}):
if k.lower() == "user-agent":
user_agent = v
break

session.update(
status="crashed" if crashed else None,
user=user,
user_agent=user_agent,
errors=session.errors + (errored or crashed),
)

def capture_event(
self,
event, # type: Event
Expand Down Expand Up @@ -260,9 +317,25 @@ def capture_event(
event_opt = self._prepare_event(event, hint, scope)
if event_opt is None:
return None

# whenever we capture an event we also check if the session needs
# to be updated based on that information.
session = scope.session if scope else None
if session:
self._update_session_from_event(session, event)

self.transport.capture_event(event_opt)
return event_id

def capture_session(
self, session # type: Session
):
# type: (...) -> None
if not session.release:
logger.info("Discarded session update because of missing release")
else:
self.session_flusher.add_session(session)

def close(
self,
timeout=None, # type: Optional[float]
Expand All @@ -275,6 +348,7 @@ def close(
"""
if self.transport is not None:
self.flush(timeout=timeout, callback=callback)
self.session_flusher.kill()
self.transport.kill()
self.transport = None

Expand All @@ -294,6 +368,7 @@ def flush(
if self.transport is not None:
if timeout is None:
timeout = self.options["shutdown_timeout"]
self.session_flusher.flush()
self.transport.flush(timeout=timeout, callback=callback)

def __enter__(self):
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"max_spans": Optional[int],
"record_sql_params": Optional[bool],
"auto_enabling_integrations": Optional[bool],
"auto_session_tracking": Optional[bool],
},
total=False,
)
Expand Down
Loading