Skip to content

Commit

Permalink
ref: Add opt-in JS-style serializer behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
untitaker committed Oct 1, 2019
1 parent 773cd94 commit 2132758
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 85 deletions.
51 changes: 26 additions & 25 deletions sentry_sdk/client.py
Expand Up @@ -10,9 +10,10 @@
get_type_name,
capture_internal_exceptions,
current_stacktrace,
disable_capture_event,
logger,
)
from sentry_sdk.serializer import serialize
from sentry_sdk.serializer import serialize, serialize_databag
from sentry_sdk.transport import make_transport
from sentry_sdk.consts import DEFAULT_OPTIONS, SDK_INFO, ClientConstructor
from sentry_sdk.integrations import setup_integrations
Expand All @@ -31,7 +32,6 @@


_client_init_debug = ContextVar("client_init_debug")
_client_in_capture_event = ContextVar("client_in_capture_event")


def _get_options(*args, **kwargs):
Expand Down Expand Up @@ -123,8 +123,13 @@ def _prepare_event(
scope, # type: Optional[Scope]
):
# type: (...) -> Optional[Event]

client = self # type: Client # type: ignore

if event.get("timestamp") is None:
event["timestamp"] = datetime.utcnow()
event["timestamp"] = serialize_databag(
client, datetime.utcnow(), is_databag=False, should_repr_strings=False
)

hint = dict(hint or ()) # type: Hint

Expand Down Expand Up @@ -170,7 +175,9 @@ def _prepare_event(

# Postprocess the event here so that annotated types do
# generally not surface in before_send
if event is not None:
if event is not None and not self.options["_experiments"].get(
"fast_serialize", False
):
event = serialize(event)

before_send = self.options["before_send"]
Expand Down Expand Up @@ -241,29 +248,23 @@ def capture_event(
:returns: An event ID. May be `None` if there is no DSN set or of if the SDK decided to discard the event for other reasons. In such situations setting `debug=True` on `init()` may help.
"""
is_recursive = _client_in_capture_event.get(False)
if is_recursive:
if disable_capture_event.get(False):
return None

_client_in_capture_event.set(True)

try:
if self.transport is None:
return None
if hint is None:
hint = {}
event_id = event.get("event_id")
if event_id is None:
event["event_id"] = event_id = uuid.uuid4().hex
if not self._should_capture(event, hint, scope):
return None
event_opt = self._prepare_event(event, hint, scope)
if event_opt is None:
return None
self.transport.capture_event(event_opt)
return event_id
finally:
_client_in_capture_event.set(False)
if self.transport is None:
return None
if hint is None:
hint = {}
event_id = event.get("event_id")
if event_id is None:
event["event_id"] = event_id = uuid.uuid4().hex
if not self._should_capture(event, hint, scope):
return None
event_opt = self._prepare_event(event, hint, scope)
if event_opt is None:
return None
self.transport.capture_event(event_opt)
return event_id

def close(
self,
Expand Down
2 changes: 1 addition & 1 deletion sentry_sdk/consts.py
Expand Up @@ -49,7 +49,7 @@ def __init__(
# DO NOT ENABLE THIS RIGHT NOW UNLESS YOU WANT TO EXCEED YOUR EVENT QUOTA IMMEDIATELY
traces_sample_rate=0.0, # type: float
traceparent_v2=False, # type: bool
_experiments={}, # type: Dict[str, Any]
_experiments={"fast_serialize": False}, # type: Dict[str, Any]
):
# type: (...) -> None
pass
Expand Down
12 changes: 11 additions & 1 deletion sentry_sdk/hub.py
Expand Up @@ -11,6 +11,7 @@
from sentry_sdk.scope import Scope
from sentry_sdk.client import Client
from sentry_sdk.tracing import Span
from sentry_sdk.serializer import serialize_databag
from sentry_sdk.utils import (
exc_info_from_error,
event_from_exception,
Expand Down Expand Up @@ -332,7 +333,14 @@ def capture_message(
return None
if level is None:
level = "info"
return self.capture_event({"message": message, "level": level})
return self.capture_event(
{
"message": serialize_databag(
self.client, message, should_repr_strings=False
),
"level": level,
}
)

def capture_exception(
self, error=None # type: Optional[Union[BaseException, ExcInfo]]
Expand Down Expand Up @@ -404,6 +412,8 @@ def add_breadcrumb(
if crumb.get("type") is None:
crumb["type"] = "default"

crumb = serialize_databag(client, crumb, should_repr_strings=False)

if client.options["before_breadcrumb"] is not None:
new_crumb = client.options["before_breadcrumb"](crumb, hint)
else:
Expand Down
5 changes: 4 additions & 1 deletion sentry_sdk/integrations/_wsgi_common.py
@@ -1,5 +1,6 @@
import json

from sentry_sdk.serializer import serialize_databag
from sentry_sdk.hub import Hub, _should_send_default_pii
from sentry_sdk.utils import AnnotatedValue
from sentry_sdk._compat import text_type, iteritems
Expand Down Expand Up @@ -42,7 +43,7 @@ def extract_into_event(self, event):
data = None # type: Optional[Union[AnnotatedValue, Dict[str, Any]]]

content_length = self.content_length()
request_info = event.setdefault("request", {})
request_info = event.get("request", {})

if _should_send_default_pii():
request_info["cookies"] = dict(self.cookies())
Expand Down Expand Up @@ -71,6 +72,8 @@ def extract_into_event(self, event):

request_info["data"] = data

event["request"] = serialize_databag(client, request_info)

def content_length(self):
# type: () -> int
try:
Expand Down
10 changes: 5 additions & 5 deletions sentry_sdk/integrations/celery.py
Expand Up @@ -11,6 +11,7 @@
)

from sentry_sdk.hub import Hub
from sentry_sdk.serializer import serialize_databag
from sentry_sdk.utils import capture_internal_exceptions, event_from_exception
from sentry_sdk.tracing import Span
from sentry_sdk._compat import reraise
Expand Down Expand Up @@ -162,11 +163,10 @@ def event_processor(event, hint):
# type: (Event, Hint) -> Optional[Event]
with capture_internal_exceptions():
extra = event.setdefault("extra", {})
extra["celery-job"] = {
"task_name": task.name,
"args": args,
"kwargs": kwargs,
}
extra["celery-job"] = serialize_databag(
Hub.current.client,
{"task_name": task.name, "args": args, "kwargs": kwargs},
)

if "exc_info" in hint:
with capture_internal_exceptions():
Expand Down
5 changes: 4 additions & 1 deletion sentry_sdk/integrations/logging.py
Expand Up @@ -4,6 +4,7 @@
import datetime

from sentry_sdk.hub import Hub
from sentry_sdk.serializer import serialize_databag
from sentry_sdk.utils import (
to_string,
event_from_exception,
Expand Down Expand Up @@ -204,7 +205,9 @@ def _emit(self, record):
event["level"] = _logging_to_event_level(record.levelname)
event["logger"] = record.name
event["logentry"] = {"message": to_string(record.msg), "params": record.args}
event["extra"] = _extra_from_record(record)
event["extra"] = serialize_databag(
Hub.current.client, _extra_from_record(record), should_repr_strings=False
)

hub.capture_event(event, hint=hint)

Expand Down
16 changes: 13 additions & 3 deletions sentry_sdk/scope.py
Expand Up @@ -3,7 +3,11 @@
from functools import wraps
from itertools import chain

import sentry_sdk

from sentry_sdk.utils import logger, capture_internal_exceptions
from sentry_sdk.serializer import serialize_databag


from sentry_sdk._types import MYPY

Expand Down Expand Up @@ -162,7 +166,9 @@ def set_tag(
):
# type: (...) -> None
"""Sets a tag for a key to a specific value."""
self._tags[key] = value
self._tags[key] = serialize_databag(
sentry_sdk.Hub.current.client, value, should_repr_strings=False
)

def remove_tag(
self, key # type: str
Expand All @@ -178,7 +184,9 @@ def set_context(
):
# type: (...) -> None
"""Binds a context at a certain key to a specific value."""
self._contexts[key] = value
self._contexts[key] = serialize_databag(
sentry_sdk.Hub.current.client, value, should_repr_strings=False
)

def remove_context(
self, key # type: str
Expand All @@ -194,7 +202,9 @@ def set_extra(
):
# type: (...) -> None
"""Sets an extra key to a specific value."""
self._extras[key] = value
self._extras[key] = serialize_databag(
sentry_sdk.Hub.current.client, value, should_repr_strings=False
)

def remove_extra(
self, key # type: str
Expand Down
33 changes: 27 additions & 6 deletions sentry_sdk/serializer.py
Expand Up @@ -6,6 +6,7 @@
from sentry_sdk.utils import (
AnnotatedValue,
capture_internal_exception,
disable_capture_event,
safe_repr,
strip_string,
)
Expand All @@ -27,6 +28,7 @@
from typing import ContextManager
from typing import Type

from sentry_sdk import Client
from sentry_sdk._types import NotImplementedType, Event

ReprProcessor = Callable[[Any, Dict[str, Any]], Union[NotImplementedType, str]]
Expand Down Expand Up @@ -87,8 +89,8 @@ def __exit__(
self._inner.pop(id(self._objs.pop()), None)


def serialize(event):
# type: (Event) -> Event
def serialize(event, **kwargs):
# type: (Event, **Any) -> Event
memo = Memo()
path = [] # type: List[Segment]
meta_stack = [] # type: List[Dict[str, Any]]
Expand Down Expand Up @@ -277,7 +279,26 @@ def _serialize_node_impl(

return _flatten_annotated(strip_string(obj))

rv = _serialize_node(event)
if meta_stack:
rv["_meta"] = meta_stack[0]
return rv
disable_capture_event.set(True)
try:
rv = _serialize_node(event, **kwargs)
if meta_stack:
rv["_meta"] = meta_stack[0]
return rv
finally:
disable_capture_event.set(False)


def serialize_databag(client, data, should_repr_strings=True, is_databag=True):
# type: (Optional[Client], Any, bool, bool) -> Any
is_recursive = disable_capture_event.get(None)
if is_recursive:
return CYCLE_MARKER

if client is not None and client.options["_experiments"].get(
"fast_serialize", False
):
return serialize(
data, should_repr_strings=should_repr_strings, is_databag=is_databag
)
return data
44 changes: 34 additions & 10 deletions sentry_sdk/tracing.py
Expand Up @@ -5,6 +5,8 @@
from datetime import datetime

import sentry_sdk

from sentry_sdk.serializer import serialize_databag
from sentry_sdk.utils import capture_internal_exceptions, logger
from sentry_sdk._compat import PY2
from sentry_sdk._types import MYPY
Expand All @@ -24,6 +26,8 @@
from typing import List
from typing import Tuple

from sentry_sdk import Client

_traceparent_header_format_re = re.compile(
"^[ \t]*" # whitespace
"([0-9a-f]{32})?" # trace_id
Expand Down Expand Up @@ -252,11 +256,15 @@ def to_legacy_traceparent(self):

def set_tag(self, key, value):
# type: (str, Any) -> None
self._tags[key] = value
self._tags[key] = serialize_databag(
sentry_sdk.Hub.current.client, value, should_repr_strings=False
)

def set_data(self, key, value):
# type: (str, Any) -> None
self._data[key] = value
self._data[key] = serialize_databag(
sentry_sdk.Hub.current.client, value, should_repr_strings=False
)

def set_failure(self):
# type: () -> None
Expand Down Expand Up @@ -292,7 +300,9 @@ def finish(self, hub=None):
# transaction for this span that would be flushed out eventually.
return None

if hub.client is None:
client = hub.client

if client is None:
# We have no client and therefore nowhere to send this transaction
# event.
return None
Expand All @@ -312,18 +322,25 @@ def finish(self, hub=None):
"type": "transaction",
"transaction": self.transaction,
"contexts": {"trace": self.get_trace_context()},
"timestamp": self.timestamp,
"start_timestamp": self.start_timestamp,
"timestamp": serialize_databag(
client, self.timestamp, is_databag=False, should_repr_strings=False
),
"start_timestamp": serialize_databag(
client,
self.start_timestamp,
is_databag=False,
should_repr_strings=False,
),
"spans": [
s.to_json()
s.to_json(client)
for s in self._span_recorder.finished_spans
if s is not self
],
}
)

def to_json(self):
# type: () -> Any
def to_json(self, client):
# type: (Optional[Client]) -> Any
rv = {
"trace_id": self.trace_id,
"span_id": self.span_id,
Expand All @@ -332,8 +349,15 @@ def to_json(self):
"transaction": self.transaction,
"op": self.op,
"description": self.description,
"start_timestamp": self.start_timestamp,
"timestamp": self.timestamp,
"start_timestamp": serialize_databag(
client,
self.start_timestamp,
is_databag=False,
should_repr_strings=False,
),
"timestamp": serialize_databag(
client, self.timestamp, is_databag=False, should_repr_strings=False
),
"tags": self._tags,
"data": self._data,
}
Expand Down

0 comments on commit 2132758

Please sign in to comment.