Browse Source

[3095] Traceback handling function

A function that catches exceptions, prints them to correct places and
exists.
Michal 'vorner' Vaner 11 years ago
parent
commit
4b1b5fd99b

+ 2 - 0
src/lib/python/isc/log_messages/Makefile.am

@@ -21,6 +21,7 @@ EXTRA_DIST += server_common_messages.py
 EXTRA_DIST += dbutil_messages.py
 EXTRA_DIST += msgq_messages.py
 EXTRA_DIST += pycc_messages.py
+EXTRA_DIST += util_messages.py
 
 CLEANFILES = __init__.pyc
 CLEANFILES += init_messages.pyc
@@ -43,6 +44,7 @@ CLEANFILES += server_common_messages.pyc
 CLEANFILES += dbutil_messages.pyc
 CLEANFILES += msgq_messages.pyc
 CLEANFILES += pycc_messages.pyc
+CLEANFILES += util_messages.pyc
 
 CLEANDIRS = __pycache__
 

+ 1 - 0
src/lib/python/isc/log_messages/util_messages.py

@@ -0,0 +1 @@
+from work.util_messages import *

+ 13 - 1
src/lib/python/isc/util/Makefile.am

@@ -1,8 +1,20 @@
 SUBDIRS = . cio tests
 
-python_PYTHON =  __init__.py process.py socketserver_mixin.py file.py
+python_PYTHON =  __init__.py process.py socketserver_mixin.py file.py \
+	traceback_handler.py
+BUILT_SOURCES = $(PYTHON_LOGMSGPKG_DIR)/work/util_messages.py
 python_PYTHON += address_formatter.py
 
+EXTRA_DIST = util_messages.mes
+
+CLEANFILES = $(PYTHON_LOGMSGPKG_DIR)/work/util_messages.py
+CLEANFILES += $(PYTHON_LOGMSGPKG_DIR)/work/util_messages.pyc
+
+# Define rule to build logging source files from message file
+$(PYTHON_LOGMSGPKG_DIR)/work/util_messages.py: util_messages.mes
+	$(top_builddir)/src/lib/log/compiler/message \
+		-d $(PYTHON_LOGMSGPKG_DIR)/work -p $(srcdir)/util_messages.mes
+
 pythondir = $(pyexecdir)/isc/util
 
 CLEANDIRS = __pycache__

+ 1 - 1
src/lib/python/isc/util/tests/Makefile.am

@@ -1,6 +1,6 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
 PYTESTS = process_test.py socketserver_mixin_test.py file_test.py
-PYTESTS += address_formatter_test.py
+PYTESTS += address_formatter_test.py traceback_handler_test.py
 EXTRA_DIST = $(PYTESTS)
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries

+ 0 - 2
src/lib/python/isc/util/tests/address_formatter_test.py

@@ -62,7 +62,5 @@ class AddressFormatterTest(unittest.TestCase):
         self.assertRaises(ValueError, str, AddressFormatter(("::1", 123), 1))
         self.assertRaises(ValueError, str, AddressFormatter(("::1", 123), 1))
 
-
-
 if __name__ == "__main__":
     unittest.main()

+ 85 - 0
src/lib/python/isc/util/tests/traceback_handler_test.py

@@ -0,0 +1,85 @@
+# Copyright (C) 2013  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+import unittest
+import os
+import isc.log
+import isc.util.traceback_handler
+
+class HandlerTest(unittest.TestCase):
+    def setUp(self):
+        """
+        Save some things to be restored later, if we overwrite them
+        for tests.
+        """
+        self.exit = isc.util.traceback_handler.sys.exit
+        self.logger = isc.util.traceback_handler.logger
+        # Sanity check - the functions exist.
+        self.assertTrue(self.exit)
+        self.assertTrue(self.logger)
+
+    def tearDown(self):
+        """
+        Restore mocked things.
+        """
+        isc.util.traceback_handler.sys.exit = self.exit
+        isc.util.traceback_handler.logger = self.logger
+
+    def test_success(self):
+        """
+        Test the handler doesn't influence the result of successful
+        function.
+        """
+        def succ():
+            return 42
+
+        self.assertEqual(42,
+                         isc.util.traceback_handler.traceback_handler(succ))
+
+    def test_exception(self):
+        """
+        Test the exception is caught and logged, but not propagated.
+        """
+        # Mock up bunch of things
+        self.exited = False
+        def exit(status):
+            self.assertEqual(1, status)
+            self.exited = True
+        isc.util.traceback_handler.sys.exit = exit
+        self.logged = False
+        obj = self
+        class Logger:
+            def fatal(self, message, ename, exception, filename):
+                obj.assertTrue(isinstance(exception, Exception))
+                obj.assertEqual('Exception', ename)
+                with open(filename) as f:
+                    text = f.read()
+                obj.assertTrue(text.startswith('Traceback'))
+                os.remove(filename)
+                obj.logged = True
+        isc.util.traceback_handler.logger = Logger()
+        # The failing function
+        def fail():
+            raise Exception('Anybody there?')
+        # Does not raise, but returns nothing
+        self.assertIsNone(isc.util.traceback_handler.traceback_handler(fail))
+        # It logged and exited (sane values for those are checked in the mocks)
+        self.assertTrue(self.exited)
+        self.assertTrue(self.logged)
+
+if __name__ == "__main__":
+    isc.log.init("bind10")
+    isc.log.resetUnitTestRootLogger()
+    unittest.main()

+ 32 - 0
src/lib/python/isc/util/traceback_handler.py

@@ -0,0 +1,32 @@
+# Copyright (C) 2013  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+from isc.log_messages.util_messages import *
+import sys
+import tempfile
+import os
+import traceback
+
+logger = isc.log.Logger('util')
+
+def traceback_handler(main):
+    try:
+        return main()
+    except Exception as e:
+        fd, name = tempfile.mkstemp(text=True)
+        with os.fdopen(fd, 'w') as handle:
+            traceback.print_exc(None, handle)
+        logger.fatal(UNHANDLED_EXCEPTION, type(e).__name__, e, name)
+        sys.exit(1)

+ 25 - 0
src/lib/python/isc/util/util_messages.mes

@@ -0,0 +1,25 @@
+# Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+
+# No namespace declaration - these constants go in the global namespace
+# of the libddns_messages python module.
+
+% UNHANDLED_EXCEPTION program terminated with exception %1: %2. More info in %3
+A program encountered unexpected situation and it didn't know how to handle it.
+It terminated. The exact problem is signified in the message. This might be
+caused by a bug in the program, broken installation, or just very rare
+condition which wasn't handled in the code. A full stack trace is left in the
+given file. If you report a bug for this exception, include that file. The file
+will not be deleted automatically and you may want to remove it when you no
+longer need the information there.