def _capture_exception(exception): with capture_internal_exceptions(): hub = Hub.current event, hint = event_from_exception( exception, with_locals=hub.client.options["with_locals"], mechanism={ "type": "sanic", "handled": False }, ) hub.capture_event(event, hint=hint)
def event_processor(event, hint): request = weak_request() if request is None: return event try: if integration.transaction_style == "route_name": event["transaction"] = request.matched_route.name elif integration.transaction_style == "route_pattern": event["transaction"] = request.matched_route.pattern except Exception: pass with capture_internal_exceptions(): PyramidRequestExtractor(request).extract_into_event(event) if _should_send_default_pii(): with capture_internal_exceptions(): user_info = event.setdefault("user", {}) user_info["id"] = authenticated_userid(request) return event
def event_processor(event, hint): with capture_internal_exceptions(): event["transaction"] = task.name with capture_internal_exceptions(): extra = event.setdefault("extra", {}) extra["celery-job"] = { "task_name": task.name, "args": args, "kwargs": kwargs, } if "exc_info" in hint: with capture_internal_exceptions(): if issubclass(hint["exc_info"][0], SoftTimeLimitExceeded): event["fingerprint"] = [ "celery", "SoftTimeLimitExceeded", getattr(task, "name", task), ] return event
def _process_ws(event, hint): if not hasattr(current, "websocket"): return event wrapper = current.websocket with capture_internal_exceptions(): data = event.setdefault("request", {}) _process_common(data, wrapper) event["transaction"] = wrapper.name return event
def _sentry_start_response(old_start_response, span, status, response_headers, exc_info=None): # type: (Callable[[str, U, Optional[E]], T], Span, str, U, Optional[E]) -> T with capture_internal_exceptions(): status_int = int(status.split(" ", 1)[0]) span.set_tag("http.status_code", status_int) if 500 <= status_int < 600: span.set_failure() return old_start_response(status, response_headers, exc_info)
def sentry_report_done(*args, **kwargs): with capture_internal_exceptions(): hub = Hub.current integration = hub.get_integration(AwsLambdaIntegration) if integration is not None: # Flush out the event queue before AWS kills the # process. This is not threadsafe. # make new transport with empty queue new_transport = hub.client.transport.copy() hub.client.close() hub.client.transport = new_transport return old_report_done(*args, **kwargs)
def event_processor(event, hint): # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. request = weak_request() if request is None: return event if "transaction" not in event: try: event["transaction"] = resolve(request.path).func.__name__ except Exception: pass with capture_internal_exceptions(): DjangoRequestExtractor(request).extract_into_event(event) if _should_send_default_pii(): with capture_internal_exceptions(): _set_user_info(request, event) return event
def event_processor(event, hint): job = weak_job() if job is not None: with capture_internal_exceptions(): event["transaction"] = job.func_name with capture_internal_exceptions(): extra = event.setdefault("extra", {}) extra["rq-job"] = { "job_id": job.id, "func": job.func_name, "args": job.args, "kwargs": job.kwargs, "description": job.description, } if "exc_info" in hint: with capture_internal_exceptions(): if issubclass(hint["exc_info"][0], JobTimeoutException): event["fingerprint"] = ["rq", "JobTimeoutException", job.func_name] return event
def inner(event, hint): request = weak_request() # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. if request is None: return event with capture_internal_exceptions(): ClasticRequestExtractor(request).extract_into_event(event) return event
def _emit(self, record): if not self.can_record(record): return hub = Hub.current integration = hub.get_integration(LoggingIntegration) if integration is None: return if self._should_create_event(record): with capture_internal_exceptions(): hint = None # exc_info might be None or (None, None, None) if record.exc_info is not None and record.exc_info[ 0] is not None: event, hint = event_from_exception( record.exc_info, client_options=hub.client.options, mechanism={ "type": "logging", "handled": True }, ) else: event = {} event["level"] = self._logging_to_event_level(record.levelname) event["logger"] = record.name event["logentry"] = { "message": to_string(record.msg), "params": record.args, } hub.capture_event(event, hint=hint) with capture_internal_exceptions(): hub.add_breadcrumb(self._breadcrumb_from_record(record), hint={"log_record": record})
def sentry_sdk_excepthook(exctype, value, traceback): with capture_internal_exceptions(): hub = Hub.current event, hint = event_from_exception( (exctype, value, traceback), with_locals=hub.client.options["with_locals"], mechanism={ "type": "excepthook", "handled": False }, ) hub.capture_event(event, hint=hint) return old_excepthook(exctype, value, traceback)
def sentry_sdk_excepthook(exctype, value, traceback): hub = Hub.current integration = hub.get_integration(ExcepthookIntegration) if integration is not None and _should_send(integration.always_run): with capture_internal_exceptions(): event, hint = event_from_exception( (exctype, value, traceback), client_options=hub.client.options, mechanism={"type": "excepthook", "handled": False}, ) hub.capture_event(event, hint=hint) return old_excepthook(exctype, value, traceback)
def inner(event, hint): request = weak_request() # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. if request is None: return event if "transaction" not in event: try: event["transaction"] = request.url_rule.endpoint except Exception: pass with capture_internal_exceptions(): FlaskRequestExtractor(request).extract_into_event(event) if _should_send_default_pii(): with capture_internal_exceptions(): _add_user_to_event(event) return event
def sentry_handler(event, context, *args, **kwargs): # type: (Any, Any, *Any, **Any) -> Any hub = Hub.current integration = hub.get_integration(AwsLambdaIntegration) if integration is None: return handler(event, context, *args, **kwargs) # If an integration is there, a client has to be there. client = hub.client # type: Any configured_time = context.get_remaining_time_in_millis() with hub.push_scope() as scope: with capture_internal_exceptions(): scope.clear_breadcrumbs() scope.add_event_processor( _make_request_event_processor(event, context, configured_time)) scope.set_tag("aws_region", context.invoked_function_arn.split(":")[3]) # Starting the Timeout thread only if the configured time is greater than Timeout warning # buffer and timeout_warning parameter is set True. if (integration.timeout_warning and configured_time > TIMEOUT_WARNING_BUFFER): waiting_time = (configured_time - TIMEOUT_WARNING_BUFFER) / MILLIS_TO_SECONDS timeout_thread = TimeoutThread( waiting_time, configured_time / MILLIS_TO_SECONDS) # Starting the thread to raise timeout warning exception timeout_thread.start() headers = event.get("headers", {}) transaction = Transaction.continue_from_headers( headers, op="serverless.function", name=context.function_name) with hub.start_transaction(transaction): try: return handler(event, context, *args, **kwargs) except Exception: exc_info = sys.exc_info() event, hint = event_from_exception( exc_info, client_options=client.options, mechanism={ "type": "aws_lambda", "handled": False }, ) hub.capture_event(event, hint=hint) reraise(*exc_info)
def _emit(self, record): # type: (LogRecord) -> None if not _can_record(record): return hub = Hub.current if hub.client is None: return client_options = hub.client.options # exc_info might be None or (None, None, None) if record.exc_info is not None and record.exc_info[0] is not None: event, hint = event_from_exception( record.exc_info, client_options=client_options, mechanism={ "type": "logging", "handled": True }, ) elif record.exc_info and record.exc_info[0] is None: event = {} hint = {} with capture_internal_exceptions(): event["threads"] = { "values": [{ "stacktrace": current_stacktrace(client_options["with_locals"]), "crashed": False, "current": True, }] } else: event = {} hint = {} hint["log_record"] = 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) hub.capture_event(event, hint=hint)
def add_context(event: 'Event', hint: 'Hint') -> Optional['Event']: if "exc_info" in hint: _, exc_value, _ = hint["exc_info"] # Ignore GeneratorExit, KeyboardInterrupt, and SystemExit exceptions if not isinstance(exc_value, Exception): return None from zerver.models import get_user_profile_by_id with capture_internal_exceptions(): user_info = event.get("user", {}) if user_info.get("id"): user_profile = get_user_profile_by_id(user_info["id"]) user_info["realm"] = user_profile.realm.string_id or 'root' user_info["role"] = user_profile.get_role_name() return event
def _patch_drf(): """ Patch Django Rest Framework for more/better request data. DRF's request type is a wrapper around Django's request type. The attribute we're interested in is `request.data`, which is a cached property containing a parsed request body. Reading a request body from that property is more reliable than reading from any of Django's own properties, as those don't hold payloads in memory and therefore can only be accessed once. We patch the Django request object to include a weak backreference to the DRF request object, such that we can later use either in `DjangoRequestExtractor`. This function is not called directly on SDK setup, because importing almost any part of Django Rest Framework will try to access Django settings (where `sentry_sdk.init()` might be called from in the first place). Instead we run this function on every request and do the patching on the first request. """ global _DRF_PATCHED if _DRF_PATCHED: # Double-checked locking return with _DRF_PATCH_LOCK: if _DRF_PATCHED: return # We set this regardless of whether the code below succeeds or fails. # There is no point in trying to patch again on the next request. _DRF_PATCHED = True with capture_internal_exceptions(): try: from rest_framework.views import APIView # type: ignore except ImportError: pass else: old_drf_initial = APIView.initial def sentry_patched_drf_initial(self, request, *args, **kwargs): with capture_internal_exceptions(): request._request._sentry_drf_request_backref = weakref.ref( request) pass return old_drf_initial(self, request, *args, **kwargs) APIView.initial = sentry_patched_drf_initial
def event_processor(event, hint): # type: (Event, Hint) -> Optional[Event] with capture_internal_exceptions(): tags = event.setdefault("tags", {}) tags["celery_task_id"] = uuid extra = event.setdefault("extra", {}) extra["celery-job"] = { "task_name": task.name, "args": args, "kwargs": kwargs, } if "exc_info" in hint: with capture_internal_exceptions(): if issubclass(hint["exc_info"][0], SoftTimeLimitExceeded): event["fingerprint"] = [ "celery", "SoftTimeLimitExceeded", getattr(task, "name", task), ] return event
def _process_http(event, hint): if not hasattr(current, "request"): return event wrapper = current.request with capture_internal_exceptions(): data = event.setdefault("request", {}) _process_common(data, wrapper) data["method"] = wrapper.method data["content_length"] = wrapper.content_length event["transaction"] = wrapper.name return event
def run_wsgi_app(app, environ, start_response): hub = Hub.current hub.push_scope() with capture_internal_exceptions(): with hub.configure_scope() as scope: scope.add_event_processor(_make_wsgi_event_processor(environ)) try: rv = app(environ, start_response) except Exception: einfo = _capture_exception(hub) hub.pop_scope_unsafe() reraise(*einfo) return _ScopePoppingResponse(hub, rv)
def _serialize_node(self, obj, max_depth=None, max_breadth=None): # type: (Any, Optional[int], Optional[int]) -> Any with capture_internal_exceptions(): with self.memo.memoize(obj) as result: if result: return CYCLE_MARKER return self._serialize_node_impl(obj, max_depth=max_depth, max_breadth=max_breadth) if self.meta_node.is_databag(): return u"<failed to serialize, use init(debug=True) to see error logs>" return None
def event_processor(event, hint): # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any] # if the request is gone we are fine not logging the data from # it. This might happen if the processor is pushed away to # another thread. request = weak_request() if request is None: return event try: drf_request = request._sentry_drf_request_backref() if drf_request is not None: request = drf_request except AttributeError: pass with capture_internal_exceptions(): DjangoRequestExtractor(request).extract_into_event(event) if _should_send_default_pii(): with capture_internal_exceptions(): _set_user_info(request, event) return event
def apply_to_event(self, event, hint=None): # type: (Dict[str, Any], Dict[str, Any]) -> Optional[Dict[str, Any]] """Applies the information contained on the scope to the given event.""" def _drop(event, cause, ty): # type: (Dict[str, Any], Callable, str) -> Optional[Any] logger.info("%s (%s) dropped event (%s)", ty, cause, event) return None if self._level is not None: event["level"] = self._level event.setdefault("breadcrumbs", []).extend(self._breadcrumbs) if event.get("user") is None and self._user is not None: event["user"] = self._user if event.get("transaction") is None and self._transaction is not None: event["transaction"] = self._transaction if event.get("fingerprint") is None and self._fingerprint is not None: event["fingerprint"] = self._fingerprint if self._extras: event.setdefault("extra", {}).update(object_to_json(self._extras)) if self._tags: event.setdefault("tags", {}).update(self._tags) if self._contexts: event.setdefault("contexts", {}).update(self._contexts) exc_info = hint.get("exc_info") if hint is not None else None if exc_info is not None: for processor in self._error_processors: new_event = processor(event, exc_info) if new_event is None: return _drop(event, processor, "error processor") event = new_event for processor in chain(global_event_processors, self._event_processors): new_event = event with capture_internal_exceptions(): new_event = processor(event, hint) if new_event is None: return _drop(event, processor, "event processor") event = new_event return event
def __call__(self, environ, start_response): hub = Hub(Hub.current) with hub: with capture_internal_exceptions(): with hub.configure_scope() as scope: scope._name = "wsgi" scope.add_event_processor( _make_wsgi_event_processor(environ)) try: rv = self.app(environ, start_response) except Exception: reraise(*_capture_exception(hub)) return _ScopedResponse(hub, rv)
def event_processor(event, hint): with capture_internal_exceptions(): # if the code below fails halfway through we at least have some data request_info = event.setdefault("request", {}) if _should_send_default_pii(): user_info = event.setdefault("user", {}) user_info["ip_address"] = client_ip request_info["url"] = request_url request_info["query_string"] = query_string request_info["method"] = method request_info["env"] = env request_info["headers"] = headers return event
def _capture_exception(exception): if isinstance(exception, SanicException): return hub = Hub.current integration = hub.get_integration(SanicIntegration) if integration is None: return with capture_internal_exceptions(): event, hint = event_from_exception( exception, client_options=hub.client.options, mechanism={"type": "sanic", "handled": False}, ) hub.capture_event(event, hint=hint)
def sentry_patched_popen_init(self, *a, **kw): # type: (subprocess.Popen[Any], *Any, **Any) -> None hub = Hub.current if hub.get_integration(StdlibIntegration) is None: return old_popen_init(self, *a, **kw) # type: ignore # Convert from tuple to list to be able to set values. a = list(a) args = _init_argument(a, kw, "args", 0) or [] cwd = _init_argument(a, kw, "cwd", 9) # if args is not a list or tuple (and e.g. some iterator instead), # let's not use it at all. There are too many things that can go wrong # when trying to collect an iterator into a list and setting that list # into `a` again. # # Also invocations where `args` is not a sequence are not actually # legal. They just happen to work under CPython. description = None if isinstance(args, (list, tuple)) and len(args) < 100: with capture_internal_exceptions(): description = " ".join(map(str, args)) if description is None: description = safe_repr(args) env = None with hub.start_span(op="subprocess", description=description) as span: for k, v in hub.iter_trace_propagation_headers(span): if env is None: env = _init_argument( a, kw, "env", 10, lambda x: dict(x or os.environ) ) env["SUBPROCESS_" + k.upper().replace("-", "_")] = v if cwd: span.set_data("subprocess.cwd", cwd) rv = old_popen_init(self, *a, **kw) # type: ignore span.set_tag("subprocess.pid", self.pid) return rv
def _capture_event(self, event): with capture_internal_exceptions(): key = self.project_key if key is None: return if not is_current_event_safe(): metrics.incr("internal.uncaptured.events", skip_internal=False) sdk_logger.warn("internal-error.unsafe-stacktrace") return auth = Auth( scheme="https", host="localhost", project_id=key.project_id, public_key=key.public_key, secret_key=key.secret_key, client="sentry-python/%s" % SDK_VERSION, ) headers = { "HTTP_X_SENTRY_AUTH": auth.to_header(), "HTTP_CONTENT_ENCODING": "deflate" } request = self.request_factory.post( "/api/{}/store/".format(key.project_id), data=zlib.compress(json.dumps(event).encode("utf8")), content_type="application/octet-stream", **headers) from sentry.web.api import StoreView resp = StoreView.as_view()(request, project_id=six.text_type( key.project_id)) if resp.status_code != 200: sdk_logger.warn( "internal-error.invalid-response", extra={ "project_id": settings.SENTRY_PROJECT, "project_key": settings.SENTRY_PROJECT_KEY, "status_code": resp.status_code, }, )
def inner(event, hint): # type: (Dict[str, Any], Dict[str, Any]) -> Dict[str, Any] try: if integration.transaction_style == "endpoint": event[ "transaction"] = request.route.name or transaction_from_function( request.route.callback) elif integration.transaction_style == "url": event["transaction"] = request.route.rule except Exception: pass with capture_internal_exceptions(): BottleRequestExtractor(request).extract_into_event(event) return event
def _capture_exception(exception): # type: (Union[Tuple[Optional[type], Optional[BaseException], Any], BaseException]) -> None hub = Hub.current integration = hub.get_integration(SanicIntegration) if integration is None: return # If an integration is there, a client has to be there. client = hub.client # type: Any with capture_internal_exceptions(): event, hint = event_from_exception( exception, client_options=client.options, mechanism={"type": "sanic", "handled": False}, ) hub.capture_event(event, hint=hint)
def event_processor(event, hint): request = weak_request() if request is None: return event with capture_internal_exceptions(): _set_user_info(request, event) request_info = event.setdefault("request", {}) request_info["cookies"] = dict(request.COOKIES) scrub_data(event.get("request", {})) if 'exception' in event: exc = event.get("exception", {}) for val in exc.get('values', []): stack = val.get('stacktrace', {}) for frame in stack.get('frames', []): scrub_data(frame['vars']) return event
def _capture_event(self, event): with capture_internal_exceptions(): key = self.project_key if key is None: return if not is_current_event_safe(): metrics.incr('internal.uncaptured.events', skip_internal=False) sdk_logger.warn('internal-error.unsafe-stacktrace') return auth = Auth( scheme="https", host="localhost", project_id=key.project_id, public_key=key.public_key, secret_key=key.secret_key, client="sentry-python/%s" % SDK_VERSION ) headers = { 'HTTP_X_SENTRY_AUTH': auth.to_header(), 'HTTP_CONTENT_ENCODING': 'deflate' } request = self.request_factory.post( '/api/{}/store/'.format(key.project_id), data=zlib.compress(json.dumps(event).encode('utf8')), content_type='application/octet-stream', **headers ) from sentry.web.api import StoreView resp = StoreView.as_view()( request, project_id=six.text_type(key.project_id), ) if resp.status_code != 200: sdk_logger.warn('internal-error.invalid-response', extra={ 'project_id': settings.SENTRY_PROJECT, 'project_key': settings.SENTRY_PROJECT_KEY, 'status_code': resp.status_code, })
def ignore_retry(event, hint): with capture_internal_exceptions(): if isinstance(hint["exc_info"][1], Retry): return None return event
def transport(event): with capture_internal_exceptions(): metrics.incr('internal.uncaptured.events', skip_internal=False) sdk_logger.warn('internal-error.noop-hub')