mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-37035: Don't log OSError (GH-13548)
https://bugs.python.org/issue37035
This commit is contained in:
parent
ff6b2e66b1
commit
1f39c28e48
8 changed files with 35 additions and 18 deletions
|
@ -59,13 +59,6 @@ _MIN_SCHEDULED_TIMER_HANDLES = 100
|
||||||
# before cleanup of cancelled handles is performed.
|
# before cleanup of cancelled handles is performed.
|
||||||
_MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5
|
_MIN_CANCELLED_TIMER_HANDLES_FRACTION = 0.5
|
||||||
|
|
||||||
# Exceptions which must not call the exception handler in fatal error
|
|
||||||
# methods (_fatal_error())
|
|
||||||
_FATAL_ERROR_IGNORE = (BrokenPipeError,
|
|
||||||
ConnectionResetError, ConnectionAbortedError)
|
|
||||||
|
|
||||||
if ssl is not None:
|
|
||||||
_FATAL_ERROR_IGNORE = _FATAL_ERROR_IGNORE + (ssl.SSLCertVerificationError,)
|
|
||||||
|
|
||||||
_HAS_IPv6 = hasattr(socket, 'AF_INET6')
|
_HAS_IPv6 = hasattr(socket, 'AF_INET6')
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ class _ProactorBasePipeTransport(transports._FlowControlMixin,
|
||||||
|
|
||||||
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
||||||
try:
|
try:
|
||||||
if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
|
if isinstance(exc, OSError):
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
logger.debug("%r: %s", self, message, exc_info=True)
|
logger.debug("%r: %s", self, message, exc_info=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -685,7 +685,7 @@ class _SelectorTransport(transports._FlowControlMixin,
|
||||||
|
|
||||||
def _fatal_error(self, exc, message='Fatal error on transport'):
|
def _fatal_error(self, exc, message='Fatal error on transport'):
|
||||||
# Should be called from exception handler only.
|
# Should be called from exception handler only.
|
||||||
if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
|
if isinstance(exc, OSError):
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
logger.debug("%r: %s", self, message, exc_info=True)
|
logger.debug("%r: %s", self, message, exc_info=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -707,7 +707,7 @@ class SSLProtocol(protocols.Protocol):
|
||||||
self._fatal_error(exc, 'Fatal error on SSL transport')
|
self._fatal_error(exc, 'Fatal error on SSL transport')
|
||||||
|
|
||||||
def _fatal_error(self, exc, message='Fatal error on transport'):
|
def _fatal_error(self, exc, message='Fatal error on transport'):
|
||||||
if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
|
if isinstance(exc, OSError):
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
logger.debug("%r: %s", self, message, exc_info=True)
|
logger.debug("%r: %s", self, message, exc_info=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -724,7 +724,7 @@ class _UnixWritePipeTransport(transports._FlowControlMixin,
|
||||||
|
|
||||||
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
def _fatal_error(self, exc, message='Fatal error on pipe transport'):
|
||||||
# should be called by exception handler only
|
# should be called by exception handler only
|
||||||
if isinstance(exc, base_events._FATAL_ERROR_IGNORE):
|
if isinstance(exc, OSError):
|
||||||
if self._loop.get_debug():
|
if self._loop.get_debug():
|
||||||
logger.debug("%r: %s", self, message, exc_info=True)
|
logger.debug("%r: %s", self, message, exc_info=True)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -448,10 +448,23 @@ class SelectorTransportTests(test_utils.TestCase):
|
||||||
tr._force_close = mock.Mock()
|
tr._force_close = mock.Mock()
|
||||||
tr._fatal_error(exc)
|
tr._fatal_error(exc)
|
||||||
|
|
||||||
|
m_exc.assert_not_called()
|
||||||
|
|
||||||
|
tr._force_close.assert_called_with(exc)
|
||||||
|
|
||||||
|
@mock.patch('asyncio.log.logger.error')
|
||||||
|
def test_fatal_error_custom_exception(self, m_exc):
|
||||||
|
class MyError(Exception):
|
||||||
|
pass
|
||||||
|
exc = MyError()
|
||||||
|
tr = self.create_transport()
|
||||||
|
tr._force_close = mock.Mock()
|
||||||
|
tr._fatal_error(exc)
|
||||||
|
|
||||||
m_exc.assert_called_with(
|
m_exc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
exc_info=(MyError, MOCK_ANY, MOCK_ANY))
|
||||||
|
|
||||||
tr._force_close.assert_called_with(exc)
|
tr._force_close.assert_called_with(exc)
|
||||||
|
|
||||||
|
@ -1338,10 +1351,20 @@ class SelectorDatagramTransportTests(test_utils.TestCase):
|
||||||
err = ConnectionRefusedError()
|
err = ConnectionRefusedError()
|
||||||
transport._fatal_error(err)
|
transport._fatal_error(err)
|
||||||
self.assertFalse(self.protocol.error_received.called)
|
self.assertFalse(self.protocol.error_received.called)
|
||||||
|
m_exc.assert_not_called()
|
||||||
|
|
||||||
|
@mock.patch('asyncio.base_events.logger.error')
|
||||||
|
def test_fatal_error_connected_custom_error(self, m_exc):
|
||||||
|
class MyException(Exception):
|
||||||
|
pass
|
||||||
|
transport = self.datagram_transport(address=('0.0.0.0', 1))
|
||||||
|
err = MyException()
|
||||||
|
transport._fatal_error(err)
|
||||||
|
self.assertFalse(self.protocol.error_received.called)
|
||||||
m_exc.assert_called_with(
|
m_exc.assert_called_with(
|
||||||
test_utils.MockPattern(
|
test_utils.MockPattern(
|
||||||
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
'Fatal error on transport\nprotocol:.*\ntransport:.*'),
|
||||||
exc_info=(ConnectionRefusedError, MOCK_ANY, MOCK_ANY))
|
exc_info=(MyException, MOCK_ANY, MOCK_ANY))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -977,11 +977,7 @@ class UnixWritePipeTransportTests(test_utils.TestCase):
|
||||||
self.assertFalse(self.loop.readers)
|
self.assertFalse(self.loop.readers)
|
||||||
self.assertEqual(bytearray(), tr._buffer)
|
self.assertEqual(bytearray(), tr._buffer)
|
||||||
self.assertTrue(tr.is_closing())
|
self.assertTrue(tr.is_closing())
|
||||||
m_logexc.assert_called_with(
|
m_logexc.assert_not_called()
|
||||||
test_utils.MockPattern(
|
|
||||||
'Fatal write error on pipe transport'
|
|
||||||
'\nprotocol:.*\ntransport:.*'),
|
|
||||||
exc_info=(OSError, MOCK_ANY, MOCK_ANY))
|
|
||||||
self.assertEqual(1, tr._conn_lost)
|
self.assertEqual(1, tr._conn_lost)
|
||||||
test_utils.run_briefly(self.loop)
|
test_utils.run_briefly(self.loop)
|
||||||
self.protocol.connection_lost.assert_called_with(err)
|
self.protocol.connection_lost.assert_called_with(err)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
Don't log OSError based exceptions if a fatal error has occurred in asyncio
|
||||||
|
transport. Peer can generate almost any OSError, user cannot avoid these exceptions
|
||||||
|
by fixing own code.
|
||||||
|
Errors are still propagated to user code, it's just logging them
|
||||||
|
is pointless and pollute asyncio logs.
|
Loading…
Add table
Add a link
Reference in a new issue