def _error_logging_loop(cls, error_fifo, error_logger): try: while True: error_msg = error_fifo.get() error_logger.error('%s', error_msg) except: dump_condensed_debug_msg('ERROR LOGGING CO-THREAD STOPS WITH EXCEPTION!') raise # traceback should be printed to sys.stderr automatically
def _handle_error(self, exc): if self._error_callback is None: traceback.print_exc() else: try: self._error_callback(exc) except Exception: dump_condensed_debug_msg( 'Exception caught when calling ' '{0!a}._error_callback({1!a}):'.format(self, exc)) traceback.print_exc()
def test_dump_condensed_debug_msg_no_exc(self, mock_stdout, mock_stderr, _dump_condensed_debug_msg_lock): """ Tests for dumping error msg to stdout and stderr. Args/kwargs: `mock_stdout` Mocked stdout from a decorator. `mock_stderr` Mocked stderr from a decorator. `_dump_condensed_debug_msg_lock` Mocked threading.RLock from a decorator. """ # Make sure there is no exc_info from previous # exception handling sys.exc_clear() # Dump debug msg to stdout stdout_msg = '<dump_condensed_debug_msg header stdout>' dump_condensed_debug_msg(stdout_msg, sys.stdout) stdout_call = list(mock_stdout.mock_calls)[0] self.assertTrue(stdout_msg in str(stdout_call)) # Dump debug msg to stderr stderr_msg = '<dump_condensed_debug_msg header stderr>' dump_condensed_debug_msg(stderr_msg, sys.stderr) stderr_call = list(mock_stderr.mock_calls)[0] self.assertTrue(stderr_msg in str(stderr_call)) mock_stderr.reset_mock() mock_stdout.reset_mock() # Test while handling exception try: raise ValueError('ValueError msg') except ValueError: # Dump exception debug msg to stdout exc_stdout_msg = re.compile( r"\\nstdout\\n\\nCONDENSED DEBUG INFO:.+\[.+@.+\] " r"ValueError:.+ValueError msg.+raise ValueError" r"\('ValueError msg'\).+test_common_helpers.+`") dump_condensed_debug_msg(header='stdout', stream=sys.stdout) stdout_call = str(list(mock_stdout.mock_calls)[0]) self.assertRegexpMatches(text=stdout_call, expected_regexp=exc_stdout_msg) # Dump exception debug msg to stderr exc_stderr_msg = re.compile( r"\\nstderr\\n\\nCONDENSED DEBUG INFO:.+\[.+@.+\] " r"ValueError:.+ValueError msg.+raise ValueError" r"\('ValueError msg'\).+test_common_helpers.+`") dump_condensed_debug_msg(header='stderr', stream=sys.stderr) stderr_call = str(list(mock_stderr.mock_calls)[0]) self.assertRegexpMatches(text=stderr_call, expected_regexp=exc_stderr_msg)
def close(self): # typically, this method is called at interpreter exit # (by logging.shutdown() which is always registered with # atexit.register() machinery) try: try: super(AMQPHandler, self).close() self._closing = True self._pusher.shutdown() except: dump_condensed_debug_msg( 'EXCEPTION DURING EXECUTION OF close() OF THE AMQP LOGGING HANDLER!') raise except (KeyboardInterrupt, SystemExit): raise except: exc = sys.exc_info()[1] self._error_fifo.put(exc)
def _publishing_loop(proxy): # proxy is a weakref.proxy(self) (to avoid reference cycles) try: output_fifo = proxy._output_fifo while proxy._publishing or not output_fifo.empty(): proxy._publishing_thread_heartbeat_flag = True item = output_fifo.get() if item is not None: # None is a "wake up!" sentinel data, routing_key, custom_prop_kwargs = item try: proxy._handle_data(data, routing_key, custom_prop_kwargs) except Exception as exc: proxy._handle_error(exc) except: dump_condensed_debug_msg('PUBLISHING CO-THREAD STOPS WITH EXCEPTION!') raise # traceback should be printed to sys.stderr automatically finally: proxy._publishing = False
def _report_critical_exception_after_commit(): debug_msg = None try: exc_info = sys.exc_info() debug_msg = make_condensed_debug_msg(exc_info) LOGGER.critical( 'Most probably, some Auth DB changes *have been* committed ' '*but* the corresponding Audit Log entries have *not* been ' 'emitted (!!!) because of an exception. Debug message: %s.', debug_msg, exc_info=exc_info) except: dump_condensed_debug_msg( 'EXCEPTION WHEN TRYING TO LOG AUDIT LOG CRITICAL EXCEPTION!') raise finally: # noinspection PyUnusedLocal exc_info = None # (<- breaking traceback-related reference cycle, if any) dump_condensed_debug_msg('AUDIT LOG CRITICAL EXCEPTION!', debug_msg=(debug_msg or '[UNKNOWN EXCEPTION]'))
def close(self): # typically, this method is called at interpreter exit # (by logging.shutdown() which is always registered with # atexit.register() machinery) try: try: try: super(AMQPHandler, self).close() finally: self._closing = True self._pusher.shutdown() except: dump_condensed_debug_msg( 'EXCEPTION DURING EXECUTION OF close() OF THE AMQP LOGGING HANDLER!' ) raise except Exception as exc: self._error_fifo.put(exc) finally: # (to break any traceback-related reference cycle) self = None # noqa
def logging_configured(suffix=None): configure_logging(suffix) try: yield except SystemExit as exc: if exc.code: _LOGGER.critical( "SystemExit(%r) occurred (debug info: %s). Exiting...", exc.code, make_condensed_debug_msg(), exc_info=True) dump_condensed_debug_msg() else: _LOGGER.info("SystemExit(%r) occurred. Exiting...", exc.code) raise except KeyboardInterrupt: _LOGGER.warning("KeyboardInterrupt occurred. Exiting...") sys.exit(1) except: _LOGGER.critical('Irrecoverable problem (debug info: %s). Exiting...', make_condensed_debug_msg(), exc_info=True) dump_condensed_debug_msg() raise
def test_dump_condensed_debug_msg(self, mock_stdout, mock_stderr): """ Tests for dumping error msg to stdout and stderr. Args/kwargs: `mock_stdout` Mocked stdout from a decorator. `mock_stderr` Mocked stderr from a decorator. """ assert sys.exc_info() == (None, None, None) # Dump debug msg to stdout stdout_msg = '<dump_condensed_debug_msg header stdout>' dump_condensed_debug_msg(stdout_msg, sys.stdout) stdout_call = list(mock_stdout.mock_calls)[0] self.assertTrue(stdout_msg in str(stdout_call)) self.assertEqual(mock_stdout.mock_calls[-1], call.flush()) # Dump debug msg to stderr stderr_msg = '<dump_condensed_debug_msg header stderr>' dump_condensed_debug_msg(stderr_msg, sys.stderr) stderr_call = list(mock_stderr.mock_calls)[0] self.assertTrue(stderr_msg in str(stderr_call)) self.assertEqual(mock_stderr.mock_calls[-1], call.flush()) mock_stderr.reset_mock() mock_stdout.reset_mock() # Test while handling exception try: raise ValueError('ValueError msg') except ValueError: # Dump exception debug msg to stdout exc_stdout_msg = re.compile( r"\\nstdout\\n\\nCONDENSED DEBUG INFO: \[.+\] \[.+@.+\] " r"ValueError:.+ValueError msg.+raise ValueError" r"\(\\?'ValueError msg\\?'\).+test_common_helpers.+`") dump_condensed_debug_msg(header='stdout', stream=sys.stdout) stdout_call = str(list(mock_stdout.mock_calls)[0]) self.assertRegex(text=stdout_call, expected_regex=exc_stdout_msg) self.assertEqual(mock_stdout.mock_calls[-1], call.flush()) # Dump exception debug msg to stderr exc_stderr_msg = re.compile( r"\\nstderr\\n\\nCONDENSED DEBUG INFO: \[.+\] \[.+@.+\] " r"ValueError:.+ValueError msg.+raise ValueError" r"\(\\?'ValueError msg\\?'\).+test_common_helpers.+`") dump_condensed_debug_msg(header='stderr', stream=sys.stderr) stderr_call = str(list(mock_stderr.mock_calls)[0]) self.assertRegex(text=stderr_call, expected_regex=exc_stderr_msg) self.assertEqual(mock_stderr.mock_calls[-1], call.flush()) # Same but specifying argument `debug_msg` mock_stderr.reset_mock() exc_stderr_msg = re.compile( r"\\nstderr\\n\\nCONDENSED DEBUG INFO: \[[^@]+\] " r"my_debug_msg\\n\W*\Z") dump_condensed_debug_msg(header='stderr', stream=sys.stderr, debug_msg='my_debug_msg') stderr_call = str(list(mock_stderr.mock_calls)[0]) self.assertRegex(text=stderr_call, expected_regex=exc_stderr_msg) self.assertEqual(mock_stderr.mock_calls[-1], call.flush())