Skip to content

feat(transport): Client Report Support #1181

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 29 commits into from
Sep 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
edb55fa
feat(transport): Experimental sdk outcomes support
mitsuhiko Sep 2, 2021
9e45ec0
fix: Formatting
Sep 2, 2021
34a2044
feat: use internal as data category for sdk outcomes
mitsuhiko Sep 3, 2021
71af713
Update sentry_sdk/client.py
mitsuhiko Sep 5, 2021
4ebac46
fix: better align recording of lost events with expectations
mitsuhiko Sep 5, 2021
8022c6f
fix: typing
mitsuhiko Sep 5, 2021
834e78a
fix: condition
mitsuhiko Sep 5, 2021
3c587e1
fix: Formatting
Sep 5, 2021
51b3b8c
fix: reformat
mitsuhiko Sep 5, 2021
a6cc971
fix: tests and added send_client_reports option
mitsuhiko Sep 5, 2021
049bc5e
fix: make lint happy
mitsuhiko Sep 5, 2021
ca94e19
ref: change protocol to latest revision
mitsuhiko Sep 6, 2021
1ccaf30
ref: attach pending client reports to the most recent envelope
mitsuhiko Sep 6, 2021
add2c4c
ref: correctly count bytes for attachments
mitsuhiko Sep 6, 2021
38ea2e1
fix: test with changed lost event recording
mitsuhiko Sep 6, 2021
5c62e81
fix: add test for client reports and fix periodic flushing
mitsuhiko Sep 6, 2021
da373e4
fix: try to attach to an envelope every 30, flush separate every 60
mitsuhiko Sep 6, 2021
e57691a
ref: switch to a custom wsgi server to better capture envelopes
mitsuhiko Sep 7, 2021
aad8efd
fix: lint
mitsuhiko Sep 7, 2021
f4a8552
fix: some python 3 stuff
mitsuhiko Sep 7, 2021
ccec734
fix: make envelope parsing work on all python 3 versions
mitsuhiko Sep 7, 2021
dbbad2b
fix: lint
mitsuhiko Sep 7, 2021
768a27e
fix: python 3 stuff
mitsuhiko Sep 7, 2021
8f462f6
fix: more old python stuff
mitsuhiko Sep 7, 2021
c06be04
fix: moar lint
mitsuhiko Sep 7, 2021
7f0c74f
fix: race
mitsuhiko Sep 8, 2021
3ecc725
fix: race more
mitsuhiko Sep 8, 2021
89b5777
fix: count empty attachments as 1
mitsuhiko Sep 10, 2021
f63464d
fix: order outcomes before assert
mitsuhiko Sep 13, 2021
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
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"python.pythonPath": ".venv/bin/python"
"python.pythonPath": ".venv/bin/python",
"python.formatting.provider": "black"
}
11 changes: 9 additions & 2 deletions scripts/init_serverless_sdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,23 @@ def extract_and_load_lambda_function_module(self, module_path):
# Supported python versions are 2.7, 3.6, 3.7, 3.8
if py_version >= (3, 5):
import importlib.util
spec = importlib.util.spec_from_file_location(module_name, module_file_path)

spec = importlib.util.spec_from_file_location(
module_name, module_file_path
)
self.lambda_function_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(self.lambda_function_module)
elif py_version[0] < 3:
import imp
self.lambda_function_module = imp.load_source(module_name, module_file_path)

self.lambda_function_module = imp.load_source(
module_name, module_file_path
)
else:
raise ValueError("Python version %s is not supported." % py_version)
else:
import importlib

self.lambda_function_module = importlib.import_module(module_path)

def get_lambda_handler(self):
Expand Down
9 changes: 8 additions & 1 deletion sentry_sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@
NotImplementedType = Any

EventDataCategory = Literal[
"default", "error", "crash", "transaction", "security", "attachment", "session"
"default",
"error",
"crash",
"transaction",
"security",
"attachment",
"session",
"internal",
]
SessionStatus = Literal["ok", "exited", "crashed", "abnormal"]
EndpointType = Literal["store", "envelope"]
3 changes: 3 additions & 0 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,9 @@ def _should_capture(
self.options["sample_rate"] < 1.0
and random.random() >= self.options["sample_rate"]
):
# record a lost event if we did not sample this.
if self.transport:
self.transport.record_lost_event("sample_rate", data_category="error")
return False

if self._is_ignored_error(event, hint):
Expand Down
1 change: 1 addition & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def __init__(
traces_sampler=None, # type: Optional[TracesSampler]
auto_enabling_integrations=True, # type: bool
auto_session_tracking=True, # type: bool
send_client_reports=True, # type: bool
_experiments={}, # type: Experiments # noqa: B006
):
# type: (...) -> None
Expand Down
18 changes: 14 additions & 4 deletions sentry_sdk/envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json
import mimetypes

from sentry_sdk._compat import text_type
from sentry_sdk._compat import text_type, PY2
from sentry_sdk._types import MYPY
from sentry_sdk.session import Session
from sentry_sdk.utils import json_dumps, capture_internal_exceptions
Expand All @@ -18,6 +18,14 @@
from sentry_sdk._types import Event, EventDataCategory


def parse_json(data):
# type: (Union[bytes, text_type]) -> Any
# on some python 3 versions this needs to be bytes
if not PY2 and isinstance(data, bytes):
data = data.decode("utf-8", "replace")
return json.loads(data)


class Envelope(object):
def __init__(
self,
Expand Down Expand Up @@ -114,7 +122,7 @@ def deserialize_from(
cls, f # type: Any
):
# type: (...) -> Envelope
headers = json.loads(f.readline())
headers = parse_json(f.readline())
items = []
while 1:
item = Item.deserialize_from(f)
Expand Down Expand Up @@ -236,6 +244,8 @@ def data_category(self):
return "transaction"
elif ty == "event":
return "error"
elif ty == "client_report":
return "internal"
else:
return "default"

Expand Down Expand Up @@ -284,11 +294,11 @@ def deserialize_from(
line = f.readline().rstrip()
if not line:
return None
headers = json.loads(line)
headers = parse_json(line)
length = headers["length"]
payload = f.read(length)
if headers.get("type") in ("event", "transaction"):
rv = cls(headers=headers, payload=PayloadRef(json=json.loads(payload)))
rv = cls(headers=headers, payload=PayloadRef(json=parse_json(payload)))
else:
rv = cls(headers=headers, payload=payload)
f.readline()
Expand Down
15 changes: 12 additions & 3 deletions sentry_sdk/tracing.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,13 +507,22 @@ def finish(self, hub=None):
# This transaction is already finished, ignore.
return None

hub = hub or self.hub or sentry_sdk.Hub.current
client = hub.client

# This is a de facto proxy for checking if sampled = False
if self._span_recorder is None:
logger.debug("Discarding transaction because sampled = False")
return None

hub = hub or self.hub or sentry_sdk.Hub.current
client = hub.client
# This is not entirely accurate because discards here are not
# exclusively based on sample rate but also traces sampler, but
# we handle this the same here.
if client and client.transport:
client.transport.record_lost_event(
"sample_rate", data_category="transaction"
)

return None

if client is None:
# We have no client and therefore nowhere to send this transaction.
Expand Down
Loading