-
Notifications
You must be signed in to change notification settings - Fork 612
feat(transport): Add EnvelopePrinterTransport for debug logging #6181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ba9db5d
e7b5161
f050b85
4924648
ab577dc
851b0ba
239a332
6466117
8d69e7b
1471ea2
5205418
f0c3b66
7f9e04e
aeb6830
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,16 @@ | ||
| from abc import ABC, abstractmethod | ||
| import asyncio | ||
| import gzip | ||
| import io | ||
| import json | ||
| import logging | ||
| import os | ||
| import gzip | ||
| import socket | ||
| import ssl | ||
| import time | ||
| import warnings | ||
| from datetime import datetime, timedelta, timezone | ||
| from abc import ABC, abstractmethod | ||
| from collections import defaultdict | ||
| from datetime import datetime, timedelta, timezone | ||
| from urllib.request import getproxies | ||
|
|
||
| try: | ||
|
|
@@ -35,36 +37,37 @@ | |
| except ImportError: | ||
| ASYNC_TRANSPORT_AVAILABLE = False | ||
|
|
||
| import urllib3 | ||
| from typing import TYPE_CHECKING, Dict, List, cast | ||
|
|
||
| import certifi | ||
| import urllib3 | ||
|
|
||
| import sentry_sdk | ||
| from sentry_sdk.consts import EndpointType | ||
| from sentry_sdk.envelope import Envelope, Item, PayloadRef | ||
| from sentry_sdk.utils import ( | ||
| Dsn, | ||
| logger, | ||
| capture_internal_exceptions, | ||
| logger, | ||
| mark_sentry_task_internal, | ||
| ) | ||
| from sentry_sdk.worker import BackgroundWorker, Worker, AsyncWorker | ||
| from sentry_sdk.envelope import Envelope, Item, PayloadRef | ||
|
|
||
| from typing import TYPE_CHECKING, cast, List, Dict | ||
| from sentry_sdk.worker import AsyncWorker, BackgroundWorker, Worker | ||
|
|
||
| if TYPE_CHECKING: | ||
| from typing import Any | ||
| from typing import Callable | ||
| from typing import DefaultDict | ||
| from typing import Iterable | ||
| from typing import Mapping | ||
| from typing import Optional | ||
| from typing import Self | ||
| from typing import Tuple | ||
| from typing import Type | ||
| from typing import Union | ||
|
|
||
| from urllib3.poolmanager import PoolManager | ||
| from urllib3.poolmanager import ProxyManager | ||
| from typing import ( | ||
| Any, | ||
| Callable, | ||
| DefaultDict, | ||
| Iterable, | ||
| Mapping, | ||
| Optional, | ||
| Self, | ||
| Tuple, | ||
| Type, | ||
| Union, | ||
| ) | ||
|
|
||
| from urllib3.poolmanager import PoolManager, ProxyManager | ||
|
|
||
| from sentry_sdk._types import Event, EventDataCategory | ||
|
|
||
|
|
@@ -1081,6 +1084,83 @@ def _make_pool( | |
| return httpcore.ConnectionPool(**opts) | ||
|
|
||
|
|
||
| class _EnvelopePrinterTransport(Transport): | ||
| """Wraps another transport, printing envelope contents to the SDK debug logger before sending.""" | ||
|
|
||
| def __init__(self, transport: "Transport") -> None: | ||
| Transport.__init__(self, options=transport.options) | ||
| self._inner = transport | ||
| self.parsed_dsn = transport.parsed_dsn | ||
|
|
||
| self.envelope_logger = logging.getLogger("sentry_sdk.envelopes") | ||
| self.envelope_logger.setLevel(logging.INFO) | ||
| self.envelope_logger.propagate = False | ||
| if not self.envelope_logger.handlers: | ||
| handler = logging.StreamHandler() | ||
| handler.setLevel(logging.INFO) | ||
| handler.setFormatter(logging.Formatter("%(message)s")) | ||
| self.envelope_logger.addHandler(handler) | ||
|
|
||
| @property # type: ignore[misc] | ||
| def __class__(self) -> type: | ||
| return self._inner.__class__ | ||
|
|
||
| def capture_envelope(self, envelope: "Envelope") -> None: | ||
| try: | ||
| self.envelope_logger.info("--- Sentry Envelope ---") | ||
| self.envelope_logger.info( | ||
| "Headers: %s", json.dumps(envelope.headers, indent=2, default=str) | ||
| ) | ||
| for item in envelope.items: | ||
| self.envelope_logger.info(" Item type: %s", item.type) | ||
| self.envelope_logger.info( | ||
| " Item headers: %s", | ||
| json.dumps(item.headers, indent=2, default=str), | ||
| ) | ||
| try: | ||
| payload = json.loads(item.get_bytes()) | ||
| self.envelope_logger.info( | ||
| " Payload:\n%s", | ||
| json.dumps(payload, indent=2, default=str), | ||
| ) | ||
| except (ValueError, TypeError): | ||
| self.envelope_logger.info( | ||
| " Payload: <binary %d bytes>", | ||
| len(item.get_bytes()), | ||
| ) | ||
|
sentry[bot] marked this conversation as resolved.
|
||
| self.envelope_logger.info("--- End Envelope ---") | ||
| except Exception: | ||
| pass | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Silent exception swallowing hides debug tool failuresLow Severity The bare Reviewed by Cursor Bugbot for commit 8d69e7b. Configure here. |
||
|
|
||
| self._inner.capture_envelope(envelope) | ||
|
|
||
| def flush( | ||
| self, | ||
| timeout: float, | ||
| callback: "Optional[Any]" = None, | ||
| ) -> "Any": | ||
| return self._inner.flush(timeout, callback) | ||
|
|
||
| def kill(self) -> "Any": | ||
| return self._inner.kill() | ||
|
|
||
| def record_lost_event( | ||
| self, | ||
| reason: str, | ||
| data_category: "Optional[EventDataCategory]" = None, | ||
| item: "Optional[Item]" = None, | ||
| *, | ||
| quantity: int = 1, | ||
| ) -> None: | ||
| self._inner.record_lost_event(reason, data_category, item, quantity=quantity) | ||
|
|
||
| def is_healthy(self) -> bool: | ||
| return self._inner.is_healthy() | ||
|
|
||
| def __getattr__(self, name: str) -> "Any": | ||
| return getattr(self._inner, name) | ||
|
|
||
|
|
||
| class _FunctionTransport(Transport): | ||
| """ | ||
| DEPRECATED: Users wishing to provide a custom transport should subclass | ||
|
|
@@ -1147,8 +1227,10 @@ def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": | |
| "You tried to use AsyncHttpTransport but don't have httpcore[asyncio] installed. Falling back to sync transport." | ||
| ) | ||
|
|
||
| transport: "Optional[Transport]" = None | ||
|
|
||
| if isinstance(ref_transport, Transport): | ||
| return ref_transport | ||
| transport = ref_transport | ||
| elif isinstance(ref_transport, type) and issubclass(ref_transport, Transport): | ||
| transport_cls = ref_transport | ||
| elif callable(ref_transport): | ||
|
|
@@ -1158,11 +1240,16 @@ def make_transport(options: "Dict[str, Any]") -> "Optional[Transport]": | |
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| return _FunctionTransport(ref_transport) | ||
| transport = _FunctionTransport(ref_transport) | ||
|
|
||
| # if a transport class is given only instantiate it if the dsn is not | ||
| # empty or None | ||
|
ericapisani marked this conversation as resolved.
|
||
| if options["dsn"]: | ||
| return transport_cls(options) | ||
| if transport is None and options["dsn"]: | ||
| transport = transport_cls(options) | ||
|
|
||
| if transport is not None and os.environ.get( | ||
| "SENTRY_PRINT_ENVELOPES", "" | ||
| ).lower() in ("1", "true", "yes"): | ||
| transport = _EnvelopePrinterTransport(transport) | ||
|
cursor[bot] marked this conversation as resolved.
|
||
|
|
||
| return None | ||
| return transport | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,15 @@ | ||
| import asyncio | ||
| import logging | ||
| import pickle | ||
| import os | ||
| import pickle | ||
| import socket | ||
| import sys | ||
| import asyncio | ||
| from collections import defaultdict | ||
| from datetime import datetime, timedelta, timezone | ||
| from unittest import mock | ||
|
|
||
| import pytest | ||
|
|
||
| from tests.conftest import CapturingServer | ||
|
|
||
| try: | ||
|
|
@@ -30,23 +31,22 @@ | |
| import sentry_sdk | ||
| from sentry_sdk import ( | ||
| Client, | ||
| Hub, | ||
| add_breadcrumb, | ||
| capture_message, | ||
| isolation_scope, | ||
| get_isolation_scope, | ||
| Hub, | ||
| isolation_scope, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably best to remove the changes in |
||
| ) | ||
| from sentry_sdk._compat import PY37, PY38 | ||
| from sentry_sdk.envelope import Envelope, Item, parse_json, PayloadRef | ||
| from sentry_sdk.envelope import Envelope, Item, PayloadRef, parse_json | ||
| from sentry_sdk.integrations.asyncio import AsyncioIntegration | ||
| from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger | ||
| from sentry_sdk.transport import ( | ||
| KEEP_ALIVE_SOCKET_OPTIONS, | ||
| _parse_rate_limits, | ||
| AsyncHttpTransport, | ||
| HttpTransport, | ||
| _parse_rate_limits, | ||
| ) | ||
| from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger | ||
| from sentry_sdk.integrations.asyncio import AsyncioIntegration | ||
|
|
||
|
|
||
| server = None | ||
|
|
||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.