Skip to content

feat(transport): Expose socket_options #2786

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 3 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sentry_sdk/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ def _get_options(*args, **kwargs):
if rv["event_scrubber"] is None:
rv["event_scrubber"] = EventScrubber()

if rv["socket_options"] and not isinstance(rv["socket_options"], list):
logger.warning(
"Ignoring socket_options because of unexpected format. See urllib3.HTTPConnection.socket_options for the expected format."
)
rv["socket_options"] = None

return rv


Expand Down
2 changes: 2 additions & 0 deletions sentry_sdk/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from typing import Dict
from typing import Any
from typing import Sequence
from typing import Tuple
from typing_extensions import TypedDict

from sentry_sdk.integrations import Integration
Expand Down Expand Up @@ -260,6 +261,7 @@ def __init__(
https_proxy=None, # type: Optional[str]
ignore_errors=[], # type: Sequence[Union[type, str]] # noqa: B006
max_request_body_size="medium", # type: str
socket_options=None, # type: Optional[List[Tuple[int, int, int | bytes]]]
before_send=None, # type: Optional[EventProcessor]
before_breadcrumb=None, # type: Optional[BreadcrumbProcessor]
debug=None, # type: Optional[bool]
Expand Down
14 changes: 9 additions & 5 deletions sentry_sdk/transport.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
from __future__ import print_function

import io
import urllib3
import certifi
import gzip
import time

from datetime import timedelta
from collections import defaultdict

import urllib3
import certifi

from sentry_sdk.utils import Dsn, logger, capture_internal_exceptions, json_dumps
from sentry_sdk.worker import BackgroundWorker
from sentry_sdk.envelope import Envelope, Item, PayloadRef

from sentry_sdk._compat import datetime_utcnow
from sentry_sdk._types import TYPE_CHECKING

Expand Down Expand Up @@ -441,12 +440,17 @@ def _send_envelope(

def _get_pool_options(self, ca_certs):
# type: (Optional[Any]) -> Dict[str, Any]
return {
options = {
"num_pools": self._num_pools,
"cert_reqs": "CERT_REQUIRED",
"ca_certs": ca_certs or certifi.where(),
}

if self.options["socket_options"]:
options["socket_options"] = self.options["socket_options"]

return options

def _in_no_proxy(self, parsed_dsn):
# type: (Dsn) -> bool
no_proxy = getproxies().get("no")
Expand Down
28 changes: 20 additions & 8 deletions tests/test_transport.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
import pickle
import gzip
import io

import socket
from collections import namedtuple
from datetime import datetime, timedelta

import pytest
from collections import namedtuple
from werkzeug.wrappers import Request, Response

from pytest_localserver.http import WSGIServer
from werkzeug.wrappers import Request, Response

from sentry_sdk import Hub, Client, add_breadcrumb, capture_message, Scope
from sentry_sdk._compat import datetime_utcnow
Expand Down Expand Up @@ -155,6 +154,19 @@ def test_transport_num_pools(make_client, num_pools, expected_num_pools):
assert options["num_pools"] == expected_num_pools


def test_socket_options(make_client):
socket_options = [
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10),
(socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
]

client = make_client(socket_options=socket_options)

options = client.transport._get_pool_options([])
assert options["socket_options"] == socket_options


def test_transport_infinite_loop(capturing_server, request, make_client):
client = make_client(
debug=True,
Expand Down Expand Up @@ -219,7 +231,7 @@ def test_parse_rate_limits(input, expected):
assert dict(_parse_rate_limits(input, now=NOW)) == expected


def test_simple_rate_limits(capturing_server, capsys, caplog, make_client):
def test_simple_rate_limits(capturing_server, make_client):
client = make_client()
capturing_server.respond_with(code=429, headers={"Retry-After": "4"})

Expand All @@ -241,7 +253,7 @@ def test_simple_rate_limits(capturing_server, capsys, caplog, make_client):

@pytest.mark.parametrize("response_code", [200, 429])
def test_data_category_limits(
capturing_server, capsys, caplog, response_code, make_client, monkeypatch
capturing_server, response_code, make_client, monkeypatch
):
client = make_client(send_client_reports=False)

Expand Down Expand Up @@ -288,7 +300,7 @@ def record_lost_event(reason, data_category=None, item=None):

@pytest.mark.parametrize("response_code", [200, 429])
def test_data_category_limits_reporting(
capturing_server, capsys, caplog, response_code, make_client, monkeypatch
capturing_server, response_code, make_client, monkeypatch
):
client = make_client(send_client_reports=True)

Expand Down Expand Up @@ -371,7 +383,7 @@ def intercepting_fetch(*args, **kwargs):

@pytest.mark.parametrize("response_code", [200, 429])
def test_complex_limits_without_data_category(
capturing_server, capsys, caplog, response_code, make_client
capturing_server, response_code, make_client
):
client = make_client()
capturing_server.respond_with(
Expand Down