예제 #1
0
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
예제 #2
0
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