Skip to content

Commit c5785fb

Browse files
authored
feat(transport): Expose socket_options (#2786)
1 parent 0901953 commit c5785fb

File tree

4 files changed

+37
-13
lines changed

4 files changed

+37
-13
lines changed

sentry_sdk/client.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ def _get_options(*args, **kwargs):
148148
if rv["event_scrubber"] is None:
149149
rv["event_scrubber"] = EventScrubber()
150150

151+
if rv["socket_options"] and not isinstance(rv["socket_options"], list):
152+
logger.warning(
153+
"Ignoring socket_options because of unexpected format. See urllib3.HTTPConnection.socket_options for the expected format."
154+
)
155+
rv["socket_options"] = None
156+
151157
return rv
152158

153159

sentry_sdk/consts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from typing import Dict
1515
from typing import Any
1616
from typing import Sequence
17+
from typing import Tuple
1718
from typing_extensions import TypedDict
1819

1920
from sentry_sdk.integrations import Integration
@@ -260,6 +261,7 @@ def __init__(
260261
https_proxy=None, # type: Optional[str]
261262
ignore_errors=[], # type: Sequence[Union[type, str]] # noqa: B006
262263
max_request_body_size="medium", # type: str
264+
socket_options=None, # type: Optional[List[Tuple[int, int, int | bytes]]]
263265
before_send=None, # type: Optional[EventProcessor]
264266
before_breadcrumb=None, # type: Optional[BreadcrumbProcessor]
265267
debug=None, # type: Optional[bool]

sentry_sdk/transport.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
from __future__ import print_function
22

33
import io
4-
import urllib3
5-
import certifi
64
import gzip
75
import time
8-
96
from datetime import timedelta
107
from collections import defaultdict
118

9+
import urllib3
10+
import certifi
11+
1212
from sentry_sdk.utils import Dsn, logger, capture_internal_exceptions, json_dumps
1313
from sentry_sdk.worker import BackgroundWorker
1414
from sentry_sdk.envelope import Envelope, Item, PayloadRef
15-
1615
from sentry_sdk._compat import datetime_utcnow
1716
from sentry_sdk._types import TYPE_CHECKING
1817

@@ -441,12 +440,17 @@ def _send_envelope(
441440

442441
def _get_pool_options(self, ca_certs):
443442
# type: (Optional[Any]) -> Dict[str, Any]
444-
return {
443+
options = {
445444
"num_pools": self._num_pools,
446445
"cert_reqs": "CERT_REQUIRED",
447446
"ca_certs": ca_certs or certifi.where(),
448447
}
449448

449+
if self.options["socket_options"]:
450+
options["socket_options"] = self.options["socket_options"]
451+
452+
return options
453+
450454
def _in_no_proxy(self, parsed_dsn):
451455
# type: (Dsn) -> bool
452456
no_proxy = getproxies().get("no")

tests/test_transport.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
import pickle
44
import gzip
55
import io
6-
6+
import socket
7+
from collections import namedtuple
78
from datetime import datetime, timedelta
89

910
import pytest
10-
from collections import namedtuple
11-
from werkzeug.wrappers import Request, Response
12-
1311
from pytest_localserver.http import WSGIServer
12+
from werkzeug.wrappers import Request, Response
1413

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

157156

157+
def test_socket_options(make_client):
158+
socket_options = [
159+
(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
160+
(socket.SOL_TCP, socket.TCP_KEEPINTVL, 10),
161+
(socket.SOL_TCP, socket.TCP_KEEPCNT, 6),
162+
]
163+
164+
client = make_client(socket_options=socket_options)
165+
166+
options = client.transport._get_pool_options([])
167+
assert options["socket_options"] == socket_options
168+
169+
158170
def test_transport_infinite_loop(capturing_server, request, make_client):
159171
client = make_client(
160172
debug=True,
@@ -219,7 +231,7 @@ def test_parse_rate_limits(input, expected):
219231
assert dict(_parse_rate_limits(input, now=NOW)) == expected
220232

221233

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

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

242254
@pytest.mark.parametrize("response_code", [200, 429])
243255
def test_data_category_limits(
244-
capturing_server, capsys, caplog, response_code, make_client, monkeypatch
256+
capturing_server, response_code, make_client, monkeypatch
245257
):
246258
client = make_client(send_client_reports=False)
247259

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

289301
@pytest.mark.parametrize("response_code", [200, 429])
290302
def test_data_category_limits_reporting(
291-
capturing_server, capsys, caplog, response_code, make_client, monkeypatch
303+
capturing_server, response_code, make_client, monkeypatch
292304
):
293305
client = make_client(send_client_reports=True)
294306

@@ -371,7 +383,7 @@ def intercepting_fetch(*args, **kwargs):
371383

372384
@pytest.mark.parametrize("response_code", [200, 429])
373385
def test_complex_limits_without_data_category(
374-
capturing_server, capsys, caplog, response_code, make_client
386+
capturing_server, response_code, make_client
375387
):
376388
client = make_client()
377389
capturing_server.respond_with(

0 commit comments

Comments
 (0)