class HttpTransport(Transport): """The default HTTP transport.""" def __init__(self, options): Transport.__init__(self, options) self._worker = BackgroundWorker() self._auth = self.parsed_dsn.to_auth("sentry-python/%s" % VERSION) self._pool = _make_pool( self.parsed_dsn, http_proxy=options["http_proxy"], https_proxy=options["https_proxy"], ) self._disabled_until = None self._retry = urllib3.util.Retry() self.options = options def _send_event(self, event): if self._disabled_until is not None: if datetime.utcnow() < self._disabled_until: return self._disabled_until = None with capture_internal_exceptions(): body = io.BytesIO() with gzip.GzipFile(fileobj=body, mode="w") as f: f.write(json.dumps(event).encode("utf-8")) logger.debug("Sending %s event [%s] to %s project:%s" % ( event.get("level") or "error", event["event_id"], self.parsed_dsn.host, self.parsed_dsn.project_id, )) response = self._pool.request( "POST", str(self._auth.store_api_url), body=body.getvalue(), headers={ "X-Sentry-Auth": str(self._auth.to_header()), "Content-Type": "application/json", "Content-Encoding": "gzip", }, ) try: if response.status == 429: self._disabled_until = datetime.utcnow() + timedelta( seconds=self._retry.get_retry_after(response)) return elif response.status >= 300 or response.status < 200: raise ValueError("Unexpected status code: %s" % response.status) finally: response.close() self._disabled_until = None def capture_event(self, event): self._worker.submit(lambda: self._send_event(event)) def shutdown(self, timeout, callback=None): logger.debug("Shutting down HTTP transport orderly") if timeout <= 0: self._worker.kill() else: self._worker.shutdown(timeout, callback) def kill(self): logger.debug("Killing HTTP transport") self._worker.kill() def copy(self): transport = type(self)(self.options) transport._pool = self._pool return transport
class HttpTransport(Transport): """The default HTTP transport.""" def __init__(self, options): Transport.__init__(self, options) self._worker = BackgroundWorker() self._auth = self.parsed_dsn.to_auth("sentry.python/%s" % VERSION) self._disabled_until = None self._retry = urllib3.util.Retry() self.options = options self._pool = self._make_pool( self.parsed_dsn, http_proxy=options["http_proxy"], https_proxy=options["https_proxy"], ca_certs=options["ca_certs"], ) from sentry_sdk import Hub self.hub_cls = Hub def _send_event(self, event): if self._disabled_until is not None: if datetime.utcnow() < self._disabled_until: return self._disabled_until = None body = io.BytesIO() with gzip.GzipFile(fileobj=body, mode="w") as f: f.write(json.dumps(event, allow_nan=False).encode("utf-8")) logger.debug("Sending %s event [%s] to %s project:%s" % ( event.get("level") or "error", event["event_id"], self.parsed_dsn.host, self.parsed_dsn.project_id, )) response = self._pool.request( "POST", str(self._auth.store_api_url), body=body.getvalue(), headers={ "X-Sentry-Auth": str(self._auth.to_header()), "Content-Type": "application/json", "Content-Encoding": "gzip", }, ) try: if response.status == 429: self._disabled_until = datetime.utcnow() + timedelta( seconds=self._retry.get_retry_after(response) or 60) return elif response.status >= 300 or response.status < 200: raise ValueError("Unexpected status code: %s" % response.status) finally: response.close() self._disabled_until = None def _get_pool_options(self, ca_certs): return { "num_pools": 2, "cert_reqs": "CERT_REQUIRED", "ca_certs": ca_certs or certifi.where(), } def _make_pool(self, parsed_dsn, http_proxy, https_proxy, ca_certs): # Use http_proxy if scheme is https and https_proxy is not set proxy = parsed_dsn.scheme == "https" and https_proxy or http_proxy if not proxy: proxy = getproxies().get(parsed_dsn.scheme) opts = self._get_pool_options(ca_certs) if proxy: return urllib3.ProxyManager(proxy, **opts) else: return urllib3.PoolManager(**opts) def capture_event(self, event): hub = self.hub_cls.current def send_event_wrapper(): with hub: with capture_internal_exceptions(): self._send_event(event) self._worker.submit(send_event_wrapper) def shutdown(self, timeout, callback=None): logger.debug("Shutting down HTTP transport orderly") if timeout <= 0: self._worker.kill() else: self._worker.shutdown(timeout, callback) def kill(self): logger.debug("Killing HTTP transport") self._worker.kill() def copy(self): transport = type(self)(self.options) transport._pool = self._pool return transport