diff --git a/.buildinfo b/.buildinfo index 04afd0f718..c7cca1b551 100644 --- a/.buildinfo +++ b/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 2ed008e28db0c89418795e4f88735099 +config: b35fde85f9e4bd191fe6e3c6be1b209a tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.doctrees/apidocs.doctree b/.doctrees/apidocs.doctree index 6f74f5e0d3..aa96eea6f2 100644 Binary files a/.doctrees/apidocs.doctree and b/.doctrees/apidocs.doctree differ diff --git a/.doctrees/environment.pickle b/.doctrees/environment.pickle index 54fe779d30..21d83dff13 100644 Binary files a/.doctrees/environment.pickle and b/.doctrees/environment.pickle differ diff --git a/_modules/index.html b/_modules/index.html index 0283eb3109..1ac54c1063 100644 --- a/_modules/index.html +++ b/_modules/index.html @@ -2,7 +2,7 @@
-
from collections.abc import Mapping
from datetime import datetime, timezone
from importlib import import_module
-
-from sentry_sdk._compat import PY37, check_uwsgi_thread_support
-from sentry_sdk.utils import (
- capture_internal_exceptions,
- current_stacktrace,
- disable_capture_event,
+from typing import cast
+
+from sentry_sdk._compat import PY37, check_uwsgi_thread_support
+from sentry_sdk.utils import (
+ capture_internal_exceptions,
+ current_stacktrace,
format_timestamp,
get_sdk_name,
get_type_name,
@@ -160,7 +160,7 @@ Source code for sentry_sdk.client
from typing import Type
from typing import Union
- from sentry_sdk._types import Event, Hint
+ from sentry_sdk._types import Event, Hint, SDKInfo
from sentry_sdk.integrations import Integration
from sentry_sdk.metrics import MetricsAggregator
from sentry_sdk.scope import Scope
@@ -175,7 +175,7 @@ Source code for sentry_sdk.client
"name": "sentry.python", # SDK name will be overridden after integrations have been loaded with sentry_sdk.integrations.setup_integrations()
"version": VERSION,
"packages": [{"name": "pypi:sentry-sdk", "version": VERSION}],
-}
+} # type: SDKInfo
def _get_options(*args, **kwargs):
@@ -508,532 +508,534 @@ Source code for sentry_sdk.client
try:
setup_continuous_profiler(
self.options,
- capture_func=_capture_envelope,
- )
- except Exception as e:
- logger.debug("Can not set up continuous profiler. (%s)", e)
-
- finally:
- _client_init_debug.set(old_debug)
-
- self._setup_instrumentation(self.options.get("functions_to_trace", []))
-
- if (
- self.monitor
- or self.metrics_aggregator
- or has_profiling_enabled(self.options)
- or isinstance(self.transport, HttpTransport)
- ):
- # If we have anything on that could spawn a background thread, we
- # need to check if it's safe to use them.
- check_uwsgi_thread_support()
-
+ sdk_info=SDK_INFO,
+ capture_func=_capture_envelope,
+ )
+ except Exception as e:
+ logger.debug("Can not set up continuous profiler. (%s)", e)
+
+ finally:
+ _client_init_debug.set(old_debug)
+
+ self._setup_instrumentation(self.options.get("functions_to_trace", []))
+
+ if (
+ self.monitor
+ or self.metrics_aggregator
+ or has_profiling_enabled(self.options)
+ or isinstance(self.transport, HttpTransport)
+ ):
+ # If we have anything on that could spawn a background thread, we
+ # need to check if it's safe to use them.
+ check_uwsgi_thread_support()
+
[docs]
- def is_active(self):
- # type: () -> bool
- """
- .. versionadded:: 2.0.0
-
- Returns whether the client is active (able to send data to Sentry)
- """
- return True
+ def is_active(self):
+ # type: () -> bool
+ """
+ .. versionadded:: 2.0.0
+
+ Returns whether the client is active (able to send data to Sentry)
+ """
+ return True
-
+
[docs]
- def should_send_default_pii(self):
- # type: () -> bool
- """
- .. versionadded:: 2.0.0
-
- Returns whether the client should send default PII (Personally Identifiable Information) data to Sentry.
- """
- return self.options.get("send_default_pii", False)
+ def should_send_default_pii(self):
+ # type: () -> bool
+ """
+ .. versionadded:: 2.0.0
+
+ Returns whether the client should send default PII (Personally Identifiable Information) data to Sentry.
+ """
+ return self.options.get("send_default_pii", False)
-
- @property
- def dsn(self):
- # type: () -> Optional[str]
- """Returns the configured DSN as string."""
- return self.options["dsn"]
-
- def _prepare_event(
- self,
- event, # type: Event
- hint, # type: Hint
- scope, # type: Optional[Scope]
- ):
- # type: (...) -> Optional[Event]
-
- if event.get("timestamp") is None:
- event["timestamp"] = datetime.now(timezone.utc)
-
- if scope is not None:
- is_transaction = event.get("type") == "transaction"
- spans_before = len(event.get("spans", []))
- event_ = scope.apply_to_event(event, hint, self.options)
-
- # one of the event/error processors returned None
- if event_ is None:
- if self.transport:
- self.transport.record_lost_event(
- "event_processor",
- data_category=("transaction" if is_transaction else "error"),
- )
- if is_transaction:
- self.transport.record_lost_event(
- "event_processor",
- data_category="span",
- quantity=spans_before + 1, # +1 for the transaction itself
- )
- return None
-
- event = event_
-
- spans_delta = spans_before - len(event.get("spans", []))
- if is_transaction and spans_delta > 0 and self.transport is not None:
- self.transport.record_lost_event(
- "event_processor", data_category="span", quantity=spans_delta
- )
-
- if (
- self.options["attach_stacktrace"]
- and "exception" not in event
- and "stacktrace" not in event
- and "threads" not in event
- ):
- with capture_internal_exceptions():
- event["threads"] = {
- "values": [
- {
- "stacktrace": current_stacktrace(
- include_local_variables=self.options.get(
- "include_local_variables", True
- ),
- max_value_length=self.options.get(
- "max_value_length", DEFAULT_MAX_VALUE_LENGTH
- ),
- ),
- "crashed": False,
- "current": True,
- }
- ]
- }
-
- for key in "release", "environment", "server_name", "dist":
- if event.get(key) is None and self.options[key] is not None:
- event[key] = str(self.options[key]).strip() # type: ignore[literal-required]
- if event.get("sdk") is None:
- sdk_info = dict(SDK_INFO)
- sdk_info["integrations"] = sorted(self.integrations.keys())
- event["sdk"] = sdk_info
-
- if event.get("platform") is None:
- event["platform"] = "python"
-
- event = handle_in_app(
- event,
- self.options["in_app_exclude"],
- self.options["in_app_include"],
- self.options["project_root"],
- )
-
- if event is not None:
- event_scrubber = self.options["event_scrubber"]
- if event_scrubber and not self.options["send_default_pii"]:
- event_scrubber.scrub_event(event)
-
- # Postprocess the event here so that annotated types do
- # generally not surface in before_send
- if event is not None:
- event = serialize(
- event,
- max_request_body_size=self.options.get("max_request_body_size"),
- max_value_length=self.options.get("max_value_length"),
- )
-
- before_send = self.options["before_send"]
- if (
- before_send is not None
- and event is not None
- and event.get("type") != "transaction"
- ):
- new_event = None
- with capture_internal_exceptions():
- new_event = before_send(event, hint or {})
- if new_event is None:
- logger.info("before send dropped event")
- if self.transport:
- self.transport.record_lost_event(
- "before_send", data_category="error"
- )
- event = new_event # type: ignore
-
- before_send_transaction = self.options["before_send_transaction"]
- if (
- before_send_transaction is not None
- and event is not None
- and event.get("type") == "transaction"
- ):
- new_event = None
- spans_before = len(event.get("spans", []))
- with capture_internal_exceptions():
- new_event = before_send_transaction(event, hint or {})
- if new_event is None:
- logger.info("before send transaction dropped event")
- if self.transport:
- self.transport.record_lost_event(
- reason="before_send", data_category="transaction"
- )
- self.transport.record_lost_event(
- reason="before_send",
- data_category="span",
- quantity=spans_before + 1, # +1 for the transaction itself
+
+ @property
+ def dsn(self):
+ # type: () -> Optional[str]
+ """Returns the configured DSN as string."""
+ return self.options["dsn"]
+
+ def _prepare_event(
+ self,
+ event, # type: Event
+ hint, # type: Hint
+ scope, # type: Optional[Scope]
+ ):
+ # type: (...) -> Optional[Event]
+
+ if event.get("timestamp") is None:
+ event["timestamp"] = datetime.now(timezone.utc)
+
+ if scope is not None:
+ is_transaction = event.get("type") == "transaction"
+ spans_before = len(event.get("spans", []))
+ event_ = scope.apply_to_event(event, hint, self.options)
+
+ # one of the event/error processors returned None
+ if event_ is None:
+ if self.transport:
+ self.transport.record_lost_event(
+ "event_processor",
+ data_category=("transaction" if is_transaction else "error"),
+ )
+ if is_transaction:
+ self.transport.record_lost_event(
+ "event_processor",
+ data_category="span",
+ quantity=spans_before + 1, # +1 for the transaction itself
+ )
+ return None
+
+ event = event_
+
+ spans_delta = spans_before - len(event.get("spans", []))
+ if is_transaction and spans_delta > 0 and self.transport is not None:
+ self.transport.record_lost_event(
+ "event_processor", data_category="span", quantity=spans_delta
+ )
+
+ if (
+ self.options["attach_stacktrace"]
+ and "exception" not in event
+ and "stacktrace" not in event
+ and "threads" not in event
+ ):
+ with capture_internal_exceptions():
+ event["threads"] = {
+ "values": [
+ {
+ "stacktrace": current_stacktrace(
+ include_local_variables=self.options.get(
+ "include_local_variables", True
+ ),
+ max_value_length=self.options.get(
+ "max_value_length", DEFAULT_MAX_VALUE_LENGTH
+ ),
+ ),
+ "crashed": False,
+ "current": True,
+ }
+ ]
+ }
+
+ for key in "release", "environment", "server_name", "dist":
+ if event.get(key) is None and self.options[key] is not None:
+ event[key] = str(self.options[key]).strip() # type: ignore[literal-required]
+ if event.get("sdk") is None:
+ sdk_info = dict(SDK_INFO)
+ sdk_info["integrations"] = sorted(self.integrations.keys())
+ event["sdk"] = sdk_info
+
+ if event.get("platform") is None:
+ event["platform"] = "python"
+
+ event = handle_in_app(
+ event,
+ self.options["in_app_exclude"],
+ self.options["in_app_include"],
+ self.options["project_root"],
+ )
+
+ if event is not None:
+ event_scrubber = self.options["event_scrubber"]
+ if event_scrubber and not self.options["send_default_pii"]:
+ event_scrubber.scrub_event(event)
+
+ # Postprocess the event here so that annotated types do
+ # generally not surface in before_send
+ if event is not None:
+ event = cast(
+ "Event",
+ serialize(
+ cast("Dict[str, Any]", event),
+ max_request_body_size=self.options.get("max_request_body_size"),
+ max_value_length=self.options.get("max_value_length"),
+ custom_repr=self.options.get("custom_repr"),
+ ),
+ )
+
+ before_send = self.options["before_send"]
+ if (
+ before_send is not None
+ and event is not None
+ and event.get("type") != "transaction"
+ ):
+ new_event = None
+ with capture_internal_exceptions():
+ new_event = before_send(event, hint or {})
+ if new_event is None:
+ logger.info("before send dropped event")
+ if self.transport:
+ self.transport.record_lost_event(
+ "before_send", data_category="error"
+ )
+ event = new_event # type: ignore
+
+ before_send_transaction = self.options["before_send_transaction"]
+ if (
+ before_send_transaction is not None
+ and event is not None
+ and event.get("type") == "transaction"
+ ):
+ new_event = None
+ spans_before = len(event.get("spans", []))
+ with capture_internal_exceptions():
+ new_event = before_send_transaction(event, hint or {})
+ if new_event is None:
+ logger.info("before send transaction dropped event")
+ if self.transport:
+ self.transport.record_lost_event(
+ reason="before_send", data_category="transaction"
)
- else:
- spans_delta = spans_before - len(new_event.get("spans", []))
- if spans_delta > 0 and self.transport is not None:
- self.transport.record_lost_event(
- reason="before_send", data_category="span", quantity=spans_delta
- )
-
- event = new_event # type: ignore
-
- return event
-
- def _is_ignored_error(self, event, hint):
- # type: (Event, Hint) -> bool
- exc_info = hint.get("exc_info")
- if exc_info is None:
- return False
-
- error = exc_info[0]
- error_type_name = get_type_name(exc_info[0])
- error_full_name = "%s.%s" % (exc_info[0].__module__, error_type_name)
-
- for ignored_error in self.options["ignore_errors"]:
- # String types are matched against the type name in the
- # exception only
- if isinstance(ignored_error, str):
- if ignored_error == error_full_name or ignored_error == error_type_name:
- return True
- else:
- if issubclass(error, ignored_error):
- return True
-
- return False
-
- def _should_capture(
- self,
- event, # type: Event
- hint, # type: Hint
- scope=None, # type: Optional[Scope]
- ):
- # type: (...) -> bool
- # Transactions are sampled independent of error events.
- is_transaction = event.get("type") == "transaction"
- if is_transaction:
- return True
-
- ignoring_prevents_recursion = scope is not None and not scope._should_capture
- if ignoring_prevents_recursion:
- return False
-
- ignored_by_config_option = self._is_ignored_error(event, hint)
- if ignored_by_config_option:
- return False
-
- return True
-
- def _should_sample_error(
- self,
- event, # type: Event
- hint, # type: Hint
- ):
- # type: (...) -> bool
- error_sampler = self.options.get("error_sampler", None)
-
- if callable(error_sampler):
- with capture_internal_exceptions():
- sample_rate = error_sampler(event, hint)
- else:
- sample_rate = self.options["sample_rate"]
-
- try:
- not_in_sample_rate = sample_rate < 1.0 and random.random() >= sample_rate
- except NameError:
- logger.warning(
- "The provided error_sampler raised an error. Defaulting to sampling the event."
- )
-
- # If the error_sampler raised an error, we should sample the event, since the default behavior
- # (when no sample_rate or error_sampler is provided) is to sample all events.
- not_in_sample_rate = False
- except TypeError:
- parameter, verb = (
- ("error_sampler", "returned")
- if callable(error_sampler)
- else ("sample_rate", "contains")
- )
- logger.warning(
- "The provided %s %s an invalid value of %s. The value should be a float or a bool. Defaulting to sampling the event."
- % (parameter, verb, repr(sample_rate))
- )
-
- # If the sample_rate has an invalid value, we should sample the event, since the default behavior
- # (when no sample_rate or error_sampler is provided) is to sample all events.
- not_in_sample_rate = False
-
- if not_in_sample_rate:
- # because we will not sample this event, record a "lost event".
- if self.transport:
- self.transport.record_lost_event("sample_rate", data_category="error")
+ self.transport.record_lost_event(
+ reason="before_send",
+ data_category="span",
+ quantity=spans_before + 1, # +1 for the transaction itself
+ )
+ else:
+ spans_delta = spans_before - len(new_event.get("spans", []))
+ if spans_delta > 0 and self.transport is not None:
+ self.transport.record_lost_event(
+ reason="before_send", data_category="span", quantity=spans_delta
+ )
+
+ event = new_event # type: ignore
+
+ return event
+
+ def _is_ignored_error(self, event, hint):
+ # type: (Event, Hint) -> bool
+ exc_info = hint.get("exc_info")
+ if exc_info is None:
+ return False
+
+ error = exc_info[0]
+ error_type_name = get_type_name(exc_info[0])
+ error_full_name = "%s.%s" % (exc_info[0].__module__, error_type_name)
+
+ for ignored_error in self.options["ignore_errors"]:
+ # String types are matched against the type name in the
+ # exception only
+ if isinstance(ignored_error, str):
+ if ignored_error == error_full_name or ignored_error == error_type_name:
+ return True
+ else:
+ if issubclass(error, ignored_error):
+ return True
+
+ return False
+
+ def _should_capture(
+ self,
+ event, # type: Event
+ hint, # type: Hint
+ scope=None, # type: Optional[Scope]
+ ):
+ # type: (...) -> bool
+ # Transactions are sampled independent of error events.
+ is_transaction = event.get("type") == "transaction"
+ if is_transaction:
+ return True
+
+ ignoring_prevents_recursion = scope is not None and not scope._should_capture
+ if ignoring_prevents_recursion:
+ return False
+
+ ignored_by_config_option = self._is_ignored_error(event, hint)
+ if ignored_by_config_option:
+ return False
+
+ return True
+
+ def _should_sample_error(
+ self,
+ event, # type: Event
+ hint, # type: Hint
+ ):
+ # type: (...) -> bool
+ error_sampler = self.options.get("error_sampler", None)
+
+ if callable(error_sampler):
+ with capture_internal_exceptions():
+ sample_rate = error_sampler(event, hint)
+ else:
+ sample_rate = self.options["sample_rate"]
+
+ try:
+ not_in_sample_rate = sample_rate < 1.0 and random.random() >= sample_rate
+ except NameError:
+ logger.warning(
+ "The provided error_sampler raised an error. Defaulting to sampling the event."
+ )
+
+ # If the error_sampler raised an error, we should sample the event, since the default behavior
+ # (when no sample_rate or error_sampler is provided) is to sample all events.
+ not_in_sample_rate = False
+ except TypeError:
+ parameter, verb = (
+ ("error_sampler", "returned")
+ if callable(error_sampler)
+ else ("sample_rate", "contains")
+ )
+ logger.warning(
+ "The provided %s %s an invalid value of %s. The value should be a float or a bool. Defaulting to sampling the event."
+ % (parameter, verb, repr(sample_rate))
+ )
+
+ # If the sample_rate has an invalid value, we should sample the event, since the default behavior
+ # (when no sample_rate or error_sampler is provided) is to sample all events.
+ not_in_sample_rate = False
- return False
-
- return True
-
- def _update_session_from_event(
- self,
- session, # type: Session
- event, # type: Event
- ):
- # type: (...) -> None
-
- crashed = False
- errored = False
- user_agent = None
-
- exceptions = (event.get("exception") or {}).get("values")
- if exceptions:
- errored = True
- for error in exceptions:
- mechanism = error.get("mechanism")
- if isinstance(mechanism, Mapping) 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")
- headers_dict = headers if isinstance(headers, dict) else {}
- for k, v in headers_dict.items():
- 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),
- )
-
+ if not_in_sample_rate:
+ # because we will not sample this event, record a "lost event".
+ if self.transport:
+ self.transport.record_lost_event("sample_rate", data_category="error")
+
+ return False
+
+ return True
+
+ def _update_session_from_event(
+ self,
+ session, # type: Session
+ event, # type: Event
+ ):
+ # type: (...) -> None
+
+ crashed = False
+ errored = False
+ user_agent = None
+
+ exceptions = (event.get("exception") or {}).get("values")
+ if exceptions:
+ errored = True
+ for error in exceptions:
+ mechanism = error.get("mechanism")
+ if isinstance(mechanism, Mapping) 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")
+ headers_dict = headers if isinstance(headers, dict) else {}
+ for k, v in headers_dict.items():
+ 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),
+ )
+
[docs]
- def capture_event(
- self,
- event, # type: Event
- hint=None, # type: Optional[Hint]
- scope=None, # type: Optional[Scope]
- ):
- # type: (...) -> Optional[str]
- """Captures an event.
-
- :param event: A ready-made event that can be directly sent to Sentry.
-
- :param hint: Contains metadata about the event that can be read from `before_send`, such as the original exception object or a HTTP request object.
-
- :param scope: An optional :py:class:`sentry_sdk.Scope` to apply to events.
-
- :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.
- """
- if disable_capture_event.get(False):
- return None
+ def capture_event(
+ self,
+ event, # type: Event
+ hint=None, # type: Optional[Hint]
+ scope=None, # type: Optional[Scope]
+ ):
+ # type: (...) -> Optional[str]
+ """Captures an event.
+
+ :param event: A ready-made event that can be directly sent to Sentry.
+
+ :param hint: Contains metadata about the event that can be read from `before_send`, such as the original exception object or a HTTP request object.
+
+ :param scope: An optional :py:class:`sentry_sdk.Scope` to apply to events.
- if hint is None:
- hint = {}
- event_id = event.get("event_id")
- hint = dict(hint or ()) # type: Hint
-
- if event_id is None:
- event["event_id"] = event_id = uuid.uuid4().hex
- if not self._should_capture(event, hint, scope):
- return None
-
- profile = event.pop("profile", None)
+ :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.
+ """
+ if hint is None:
+ hint = {}
+ event_id = event.get("event_id")
+ hint = dict(hint or ()) # type: Hint
+
+ 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
-
- # 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)
-
- is_transaction = event_opt.get("type") == "transaction"
- is_checkin = event_opt.get("type") == "check_in"
-
- if (
- not is_transaction
- and not is_checkin
- and not self._should_sample_error(event, hint)
- ):
- return None
-
- attachments = hint.get("attachments")
+ profile = event.pop("profile", None)
+
+ 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)
+
+ is_transaction = event_opt.get("type") == "transaction"
+ is_checkin = event_opt.get("type") == "check_in"
+
+ if (
+ not is_transaction
+ and not is_checkin
+ and not self._should_sample_error(event, hint)
+ ):
+ return None
- trace_context = event_opt.get("contexts", {}).get("trace") or {}
- dynamic_sampling_context = trace_context.pop("dynamic_sampling_context", {})
-
- headers = {
- "event_id": event_opt["event_id"],
- "sent_at": format_timestamp(datetime.now(timezone.utc)),
- } # type: dict[str, object]
-
- if dynamic_sampling_context:
- headers["trace"] = dynamic_sampling_context
-
- envelope = Envelope(headers=headers)
+ attachments = hint.get("attachments")
+
+ trace_context = event_opt.get("contexts", {}).get("trace") or {}
+ dynamic_sampling_context = trace_context.pop("dynamic_sampling_context", {})
+
+ headers = {
+ "event_id": event_opt["event_id"],
+ "sent_at": format_timestamp(datetime.now(timezone.utc)),
+ } # type: dict[str, object]
+
+ if dynamic_sampling_context:
+ headers["trace"] = dynamic_sampling_context
- if is_transaction:
- if isinstance(profile, Profile):
- envelope.add_profile(profile.to_json(event_opt, self.options))
- envelope.add_transaction(event_opt)
- elif is_checkin:
- envelope.add_checkin(event_opt)
- else:
- envelope.add_event(event_opt)
-
- for attachment in attachments or ():
- envelope.add_item(attachment.to_envelope_item())
-
- if self.spotlight:
- self.spotlight.capture_envelope(envelope)
-
- if self.transport is None:
- return None
-
- self.transport.capture_envelope(envelope)
+ envelope = Envelope(headers=headers)
+
+ if is_transaction:
+ if isinstance(profile, Profile):
+ envelope.add_profile(profile.to_json(event_opt, self.options))
+ envelope.add_transaction(event_opt)
+ elif is_checkin:
+ envelope.add_checkin(event_opt)
+ else:
+ envelope.add_event(event_opt)
+
+ for attachment in attachments or ():
+ envelope.add_item(attachment.to_envelope_item())
+
+ if self.spotlight:
+ self.spotlight.capture_envelope(envelope)
+
+ if self.transport is None:
+ return None
- return event_id
-
+ self.transport.capture_envelope(envelope)
- 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)
-
+ 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)
+
[docs]
- def get_integration(
- self, name_or_class # type: Union[str, Type[Integration]]
- ):
- # type: (...) -> Any
- """Returns the integration for this client by name or class.
- If the client does not have that integration then `None` is returned.
- """
- if isinstance(name_or_class, str):
- integration_name = name_or_class
- elif name_or_class.identifier is not None:
- integration_name = name_or_class.identifier
- else:
- raise ValueError("Integration has no name")
-
- return self.integrations.get(integration_name)
-
+ def get_integration(
+ self, name_or_class # type: Union[str, Type[Integration]]
+ ):
+ # type: (...) -> Any
+ """Returns the integration for this client by name or class.
+ If the client does not have that integration then `None` is returned.
+ """
+ if isinstance(name_or_class, str):
+ integration_name = name_or_class
+ elif name_or_class.identifier is not None:
+ integration_name = name_or_class.identifier
+ else:
+ raise ValueError("Integration has no name")
+ return self.integrations.get(integration_name)