Skip to content

Commit 319992b

Browse files
authored
Provide sockname when logging a protocol error (#935)
1 parent 4d30c25 commit 319992b

3 files changed

Lines changed: 52 additions & 10 deletions

File tree

tests/test_logger.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,24 @@ def test_log_exception_warning():
6161

6262
assert not mock_log_warning.mock_calls
6363
assert mock_log_debug.mock_calls
64+
65+
66+
def test_log_exception_once():
67+
"""Test we only log with warning level once."""
68+
quiet_logger = QuietLogger()
69+
exc = Exception()
70+
with patch("zeroconf._logger.log.warning") as mock_log_warning, patch(
71+
"zeroconf._logger.log.debug"
72+
) as mock_log_debug:
73+
quiet_logger.log_exception_once(exc, "the exceptional exception warning")
74+
75+
assert mock_log_warning.mock_calls
76+
assert not mock_log_debug.mock_calls
77+
78+
with patch("zeroconf._logger.log.warning") as mock_log_warning, patch(
79+
"zeroconf._logger.log.debug"
80+
) as mock_log_debug:
81+
quiet_logger.log_exception_once(exc, "the exceptional exception warning")
82+
83+
assert not mock_log_warning.mock_calls
84+
assert mock_log_debug.mock_calls

zeroconf/_core.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,10 @@ def datagram_received(
226226
if self.suppress_duplicate_packet(data, now):
227227
# Guard against duplicate packets
228228
log.debug(
229-
'Ignoring duplicate message received from %r:%r (socket %d) (%d bytes) as [%r]',
229+
'Ignoring duplicate message received from %r:%r [socket %s] (%d bytes) as [%r]',
230230
addr,
231231
port,
232-
self.transport.get_extra_info('socket').fileno(),
232+
self._socket_description,
233233
len(data),
234234
data,
235235
)
@@ -249,20 +249,20 @@ def datagram_received(
249249
msg = DNSIncoming(data, scope, now)
250250
if msg.valid:
251251
log.debug(
252-
'Received from %r:%r (socket %d): %r (%d bytes) as [%r]',
252+
'Received from %r:%r [socket %s]: %r (%d bytes) as [%r]',
253253
addr,
254254
port,
255-
self.transport.get_extra_info('socket').fileno(),
255+
self._socket_description,
256256
msg,
257257
len(data),
258258
data,
259259
)
260260
else:
261261
log.debug(
262-
'Received from %r:%r (socket %d): (%d bytes) [%r]',
262+
'Received from %r:%r [socket %s]: (%d bytes) [%r]',
263263
addr,
264264
port,
265-
self.transport.get_extra_info('socket').fileno(),
265+
self._socket_description,
266266
len(data),
267267
data,
268268
)
@@ -316,12 +316,22 @@ def _respond_query(
316316

317317
self.zc.handle_assembled_query(packets, addr, port, v6_flow_scope)
318318

319+
@property
320+
def _socket_description(self) -> str:
321+
"""A human readable description of the socket."""
322+
assert self.transport is not None
323+
fileno = self.transport.get_extra_info('socket').fileno()
324+
sockname = self.transport.get_extra_info('sockname')
325+
return f"{fileno} ({sockname})"
326+
319327
def error_received(self, exc: Exception) -> None:
320328
"""Likely socket closed or IPv6."""
321-
assert self.transport is not None
322-
self.log_warning_once(
323-
'Error with socket %d: %s', self.transport.get_extra_info('socket').fileno(), exc
324-
)
329+
# We preformat the message string with the socket as we want
330+
# log_exception_once to log a warrning message once PER EACH
331+
# different socket in case there are problems with multiple
332+
# sockets
333+
msg_str = f"Error with socket {self._socket_description}): %s"
334+
self.log_exception_once(exc, msg_str, exc)
325335

326336
def connection_made(self, transport: asyncio.BaseTransport) -> None:
327337
self.transport = cast(asyncio.DatagramTransport, transport)

zeroconf/_logger.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,14 @@ def log_warning_once(cls, *args: Any) -> None:
6161
logger = log.debug
6262
cls._seen_logs[msg_str] = cast(int, cls._seen_logs[msg_str]) + 1
6363
logger(*args)
64+
65+
@classmethod
66+
def log_exception_once(cls, exc: Exception, *args: Any) -> None:
67+
msg_str = args[0]
68+
if msg_str not in cls._seen_logs:
69+
cls._seen_logs[msg_str] = 0
70+
logger = log.warning
71+
else:
72+
logger = log.debug
73+
cls._seen_logs[msg_str] = cast(int, cls._seen_logs[msg_str]) + 1
74+
logger(*args, exc_info=exc)

0 commit comments

Comments
 (0)