Merge lp:~facundo/magicicada-gui/log-exceptions into lp:magicicada-gui

Proposed by Facundo Batista
Status: Merged
Approved by: Natalia Bidart
Approved revision: 69
Merged at revision: 69
Proposed branch: lp:~facundo/magicicada-gui/log-exceptions
Merge into: lp:magicicada-gui
Diff against target: 160 lines (+108/-8)
3 files modified
magicicada/logger.py (+17/-0)
magicicada/tests/helpers.py (+8/-8)
magicicada/tests/test_logger.py (+83/-0)
To merge this branch: bzr merge lp:~facundo/magicicada-gui/log-exceptions
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+32806@code.launchpad.net

Description of the change

Log unhandled exceptions.

To post a comment you must log in.
68. By Facundo Batista

Tested the logging

69. By Facundo Batista

Make pylint and pep8 happy

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Lovely.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'magicicada/logger.py'
2--- magicicada/logger.py 2010-06-20 19:50:46 +0000
3+++ magicicada/logger.py 2010-08-18 21:20:58 +0000
4@@ -21,6 +21,8 @@
5
6 import logging
7 import os
8+import sys
9+import traceback
10
11 from logging.handlers import RotatingFileHandler
12
13@@ -35,6 +37,18 @@
14 self.doRollover()
15
16
17+def exception_handler(exc_type, exc_value, tb):
18+ """Handle an unhandled exception."""
19+ # stderr
20+ exception = traceback.format_exception(exc_type, exc_value, tb)
21+ exception = "".join(exception)
22+ print >> sys.stderr, exception
23+
24+ # log
25+ logger = logging.getLogger('magicicada')
26+ logger.error("Unhandled exception!\n%s", exception)
27+
28+
29 def set_up():
30 """Set up the logging."""
31
32@@ -53,3 +67,6 @@
33 '%Y-%m-%d %H:%M:%S')
34 handler.setFormatter(formatter)
35 logger.setLevel(logging.DEBUG)
36+
37+ # hook the exception handler
38+ sys.excepthook = exception_handler
39
40=== modified file 'magicicada/tests/helpers.py'
41--- magicicada/tests/helpers.py 2010-06-19 18:55:01 +0000
42+++ magicicada/tests/helpers.py 2010-08-18 21:20:58 +0000
43@@ -33,21 +33,21 @@
44 """Just add the record to self.records."""
45 self.records.append(record)
46
47- def check(self, level, msg):
48+ def check(self, level, *msgs):
49 """Check that something is logged."""
50 for rec in self.records:
51- if rec.levelname == level and str(msg) in rec.message:
52+ if rec.levelname == level and all(m in rec.message for m in msgs):
53 return True
54 return False
55
56- def check_error(self, msg):
57+ def check_error(self, *msgs):
58 """Shortcut for ERROR check."""
59- return self.check('ERROR', msg)
60+ return self.check('ERROR', *msgs)
61
62- def check_info(self, msg):
63+ def check_info(self, *msgs):
64 """Shortcut for INFO check."""
65- return self.check('INFO', msg)
66+ return self.check('INFO', *msgs)
67
68- def check_debug(self, msg):
69+ def check_debug(self, *msgs):
70 """Shortcut for DEBUG check."""
71- return self.check('DEBUG', msg)
72+ return self.check('DEBUG', *msgs)
73
74=== added file 'magicicada/tests/test_logger.py'
75--- magicicada/tests/test_logger.py 1970-01-01 00:00:00 +0000
76+++ magicicada/tests/test_logger.py 2010-08-18 21:20:58 +0000
77@@ -0,0 +1,83 @@
78+# Tests some logging functions
79+#
80+# Author: Facundo Batista <facundo@taniquetil.com.ar>
81+#
82+# Copyright 2010 Chicharreros
83+#
84+# This program is free software: you can redistribute it and/or modify it
85+# under the terms of the GNU General Public License version 3, as published
86+# by the Free Software Foundation.
87+#
88+# This program is distributed in the hope that it will be useful, but
89+# WITHOUT ANY WARRANTY; without even the implied warranties of
90+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
91+# PURPOSE. See the GNU General Public License for more details.
92+#
93+# You should have received a copy of the GNU General Public License along
94+# with this program. If not, see <http://www.gnu.org/licenses/>.
95+
96+"""Tests some logging functions."""
97+
98+import cStringIO
99+import logging
100+import sys
101+import unittest
102+
103+from magicicada.logger import exception_handler
104+from magicicada.tests.helpers import MementoHandler
105+
106+
107+# It's ok to access private data in the test suite
108+# pylint: disable=W0212
109+
110+
111+class ExceptionTests(unittest.TestCase):
112+ """Test that we log on unhandled exceptions."""
113+
114+ def _get_exception_data(self):
115+ """Return data from a real exception."""
116+ try:
117+ 1 / 0
118+ except ZeroDivisionError:
119+ return sys.exc_info()
120+
121+ def test_hook(self):
122+ """Check that we're hooked in sys."""
123+ self.assertTrue(sys.excepthook is exception_handler)
124+
125+ def test_logs(self):
126+ """Unhandled exceptions logs in error."""
127+ # set up logger
128+ handler = MementoHandler()
129+ handler.setLevel(logging.DEBUG)
130+ l = logging.getLogger('magicicada')
131+
132+ # call
133+ l.addHandler(handler)
134+ exc = self._get_exception_data()
135+ try:
136+ exception_handler(*exc)
137+ finally:
138+ l.removeHandler(handler)
139+
140+ # check
141+ self.assertTrue(handler.check_error("Unhandled exception",
142+ "ZeroDivisionError"))
143+
144+ def test_stderr(self):
145+ """Unhandled exceptions are also sent to stderr."""
146+ fh = cStringIO.StringIO()
147+
148+ # call
149+ orig_stderr = sys.stderr
150+ sys.stderr = fh
151+ exc = self._get_exception_data()
152+ try:
153+ exception_handler(*exc)
154+ finally:
155+ sys.stderr = orig_stderr
156+
157+ # check
158+ shown = fh.getvalue()
159+ self.assertTrue("Traceback" in shown)
160+ self.assertTrue("ZeroDivisionError" in shown)

Subscribers

People subscribed via source and target branches