added initial logging framwork.

svn: r5673
This commit is contained in:
Richard Taylor 2006-01-05 16:02:27 +00:00
parent 8eece3d712
commit ce52de5804
8 changed files with 506 additions and 1 deletions

View File

@ -1,3 +1,10 @@
2006-01-05 Richard Taylor <rjt-gramps@thegrindstone.me.uk>
* src/Assistant.py: added callback support for pages
* src/GrampsLogger/_ErrorReportAssistant.py src/GrampsLogger/_ErrorView.py
src/GrampsLogger/_GtkHandler.py src/GrampsLogger/_RotateHandler.py
test/GrampsLogger/GtkHandler_Test.py test/GrampsLogger/RotateLogger_Test.py:
added initial logging and error reporting framework.
2006-01-04 Don Allingham <don@gramps-project.org>
* src/FamilyView.py: Incorporate Steve Hall's identing ideas, general classes
* src/DisplayView.py: Open/OpenRecent MenuToolButton goodness :-)

View File

@ -40,6 +40,7 @@ class Assistant:
self.current_page = 0
self.max_page = 1
self.page_callbacks = {}
self.window = gtk.Window()
titlebox = gtk.HBox()
@ -100,6 +101,8 @@ class Assistant:
self.next.set_use_stock(True)
self.cancel.show()
self.call_page_callback()
def next_clicked(self,obj):
if self.current_page == self.max_page:
self.complete()
@ -120,6 +123,15 @@ class Assistant:
self.back.set_sensitive(True)
self.cancel.show()
self.call_page_callback()
def call_page_callback(self):
# If the page has a callback then call it.
if self.page_callbacks.has_key(
self.notebook.get_nth_page(self.notebook.get_current_page())):
self.page_callbacks[
self.notebook.get_nth_page(self.notebook.get_current_page())]()
def set_intro(self,text):
hbox = gtk.HBox(spacing=12)
image = gtk.Image()
@ -133,10 +145,12 @@ class Assistant:
def set_conclusion(self,title,text):
self.conclude_text = text
def add_page(self, title, child):
def add_page(self, title, child, callback=None):
self.title_text.append(_format % title)
self.notebook.append_page(child)
self.max_page += 1
if callback is not None:
self.page_callbacks[child] = callback
def show(self):
self.title_text.append(_format % _('Finished'))
@ -151,6 +165,9 @@ class Assistant:
self.window.show_all()
self.notebook.set_current_page(0)
self.call_page_callback()
def destroy(self):
self.window.destroy()

View File

@ -0,0 +1,205 @@
from gettext import gettext as _
import sys,os
import const
import gtk
import Assistant
class ErrorReportAssistant:
def __init__(self,error_detail,rotate_handler):
self._error_detail = error_detail
self._rotate_handler = rotate_handler
self._sys_information_text_buffer = None
self._user_information_text_buffer = None
self._error_details_text_buffer = None
self._final_report_text_buffer = None
self.w = Assistant.Assistant(_('Report a bug'),self.complete)
self.w.set_intro(_("This is the Bug Reporting Assistant. It will "\
"help you to make a bug report to the Gramps "\
"developers that will be as detailed as possible.\n"\
"The assistant will ask you a few questions and will "\
"gather some information about the error that has "\
"occured and the operating environment. "\
"At then end of the assistent you will be asked to "\
"send an email to the Gramps bug reporting mailing list "\
"and the bug report will be placed on the clip board so "\
"that you can paste it into your email programme and review "\
"exactly what information is being sent."))
self.w.add_page(_("Error Details"), self.build_page2())
self.w.add_page(_("System Information"), self.build_page3())
self.w.add_page(_("Further Information"), self.build_page4())
self.w.add_page(_("Summary"), self.build_page5(),self.page5_update)
self.w.set_conclusion(_('Complete'),
_('The error report will be copied to your clipboard when you click OK. \n'
'Please paste the report into your favourite email client and send it to: \n\n'
'gramps-bugs@lists.sourceforge.net\n\n'
'GRAMPS is an Open Source project. Its success '
'depends on the users. User feedback is important. '
'Thankyou for taking the time to submit a bug report.'))
self.w.show()
def complete(self):
clipboard = gtk.Clipboard()
clipboard.set_text(
self._final_report_text_buffer.get_text(
self._final_report_text_buffer.get_start_iter(),
self._final_report_text_buffer.get_end_iter()))
clipboard = gtk.Clipboard(selection="PRIMARY")
clipboard.set_text(
self._final_report_text_buffer.get_text(
self._final_report_text_buffer.get_start_iter(),
self._final_report_text_buffer.get_end_iter()))
def _get_sys_information(self):
return "Python version: %s \n"\
"Gramps version: %s \n"\
"OS: %s\n"\
"Distribution: %s\n"\
% (str(sys.version).replace('\n',''),
str(const.version),
os.uname()[0],
os.uname()[2])
def build_page2(self):
box = gtk.VBox()
label = gtk.Label(_("This is the detail Gramps error information, don't worry if you "\
"do not understand it. If you can see that there is any personal "\
"informatin included in the error details please remove it, you "\
"will have the opportunity to add further detail about the error "\
"in the following pages of the assistant."))
label.set_line_wrap(True)
box.pack_start(label,False,False,5)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
textview = gtk.TextView()
self._error_details_text_buffer = textview.get_buffer()
self._error_details_text_buffer.set_text(self._error_detail)
sw.add(textview)
sw.show()
textview.show()
box.pack_start(sw)
box.show_all()
return box
def build_page3(self):
box = gtk.VBox()
label = gtk.Label(_("Please check the information below and correct anything that "\
"you know to be wrong or remove anything that you would rather not "\
"have included in the bug report."))
label.set_line_wrap(True)
box.pack_start(label,False,False,5)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
textview = gtk.TextView()
self._sys_information_text_buffer = textview.get_buffer()
self._sys_information_text_buffer.set_text(self._get_sys_information())
sw.add(textview)
sw.show()
textview.show()
box.pack_start(sw)
box.show_all()
return box
def build_page4(self):
box = gtk.VBox()
label = gtk.Label(_("Please provide as much information as you can "\
"about what you were doing when the error occured. "))
label.set_line_wrap(True)
box.pack_start(label,False,False,5)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
textview = gtk.TextView()
self._user_information_text_buffer = textview.get_buffer()
sw.add(textview)
sw.show()
textview.show()
box.pack_start(sw)
box.show_all()
return box
def build_page5(self):
box = gtk.VBox()
label = gtk.Label(_("The complete bug report is shown below. When you click Forward it will "\
"be copied onto the clickboard and you will be asked to email it.\n"\
"Please check that the information is correct, do not worry if you "\
"don't understand the detail of the error information. Just make sure "\
"that it does not contain anything that you do not want to be sent "\
"to the developers."))
label.set_line_wrap(True)
box.pack_start(label,False,False,5)
sw = gtk.ScrolledWindow()
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
textview = gtk.TextView()
textview.set_editable(False)
textview.set_cursor_visible(False)
self._final_report_text_buffer = textview.get_buffer()
sw.add(textview)
sw.show()
textview.show()
box.pack_start(sw)
box.show_all()
return box
def page5_update(self):
self._final_report_text_buffer.set_text(
"System Information: \n\n" +
self._sys_information_text_buffer.get_text(
self._sys_information_text_buffer.get_start_iter(),
self._sys_information_text_buffer.get_end_iter()) +
"Additional Information: \n\n" +
self._user_information_text_buffer.get_text(
self._user_information_text_buffer.get_start_iter(),
self._user_information_text_buffer.get_end_iter()) +
"\nError Details: \n\n" +
self._error_details_text_buffer.get_text(
self._error_details_text_buffer.get_start_iter(),
self._error_details_text_buffer.get_end_iter())
)

View File

@ -0,0 +1,74 @@
from gettext import gettext as _
import gtk
from _ErrorReportAssistant import ErrorReportAssistant
class ErrorView(object):
"""
A Dialog for displaying errors.
"""
def __init__(self, error_detail, rotate_handler):
"""
Initialize the handler with the buffer size.
"""
self._error_detail = error_detail
self._rotate_handler = rotate_handler
self.draw_window()
self.run()
def run(self):
self.response = self.top.run()
if self.response == gtk.RESPONSE_HELP:
self.help_clicked()
elif self.response == gtk.RESPONSE_YES:
ErrorReportAssistant(error_detail = self._error_detail,
rotate_handler = self._rotate_handler)
self.top.destroy()
def draw_window(self):
title = "%s - GRAMPS" % _("Error Report")
self.top = gtk.Dialog(title)
#self.top.set_default_size(400,350)
self.top.set_has_separator(False)
self.top.vbox.set_spacing(5)
label = gtk.Label('<span size="larger" weight="bold">%s</span>'
% _("An unexpected error has occured"))
label.set_use_markup(True)
self.top.vbox.pack_start(label,False,False,5)
sep = gtk.HSeparator()
self.top.vbox.pack_start(sep,False,False,5)
instructions_label = gtk.Label('<span weight="bold">%s</span>\n'\
'%s' % \
( _("Gramps has experienced an unexpected error."),
_("Your data will safe but it would be advisable to restart gramps immediately. "\
"If you would like to report the problem to the Gramps team "\
"please click Report and the Error Reporting Wizard will help you "\
"to make a bug report.")))
instructions_label.set_line_wrap(True)
instructions_label.set_use_markup(True)
self.top.vbox.pack_start(instructions_label,False,False,5)
tb_frame = gtk.Frame(_("Error Detail"))
tb_label = gtk.Label(self._error_detail)
tb_frame.add(tb_label)
tb_expander = gtk.Expander('<span weight="bold">%s</span>' % _("Error Detail"))
tb_expander.set_use_markup(True)
tb_expander.add(tb_frame)
self.top.vbox.pack_start(tb_expander,True,True,5)
self.top.add_button(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL)
self.top.add_button(_("Report"),gtk.RESPONSE_YES)
self.top.add_button(gtk.STOCK_HELP,gtk.RESPONSE_HELP)
self.top.show_all()

View File

@ -0,0 +1,27 @@
import logging
from _ErrorView import ErrorView
class GtkHandler(logging.Handler):
"""
A handler class which pops up a Gtk Window when a log message occurs.
"""
def __init__(self,rotate_handler=None):
"""
Initialize the handler with a optional rotate_logger instance.
"""
logging.Handler.__init__(self)
self._rotate_handler = rotate_handler
def emit(self, record):
"""
Add the record to the rotating buffer.
"""
ErrorView(error_detail=self.format(record),rotate_handler=self._rotate_handler)

View File

@ -0,0 +1,40 @@
import logging
class RotateHandler(logging.Handler):
"""
A handler class which buffers logging records in memory. A rotating
buffer is used so that the last X records are always available.
"""
def __init__(self, capacity):
"""
Initialize the handler with the buffer size.
"""
logging.Handler.__init__(self)
self.set_capacity(capacity)
def emit(self, record):
"""
Add the record to the rotating buffer.
"""
self._buffer[self._index] = record
self._index = (self._index + 1 ) % self._capacity
def get_buffer(self):
"""
Return the buffer with the records in the correct order.
"""
return [record for record in self._buffer[self._index:] + self._buffer[:self._index]
if record is not None]
def set_capacity(self,capacity):
"""
Set the number of log records that will be stored.
"""
self._capacity = capacity
self._index = 0
self._buffer = self._capacity * [None]

View File

@ -0,0 +1,48 @@
import unittest
import logging
import sys
import gtk
sys.path.append('../../src')
sys.path.append('../../src/GrampsLogger')
logger = logging.getLogger('Gramps.Tests.GrampsLogger')
import const
const.rootDir = "../../src"
import _GtkHandler
class GtkHandlerTest(unittest.TestCase):
"""Test the GtkHandler."""
def test_window(self):
"""Test that the window appears."""
rh = _GtkHandler.GtkHandler()
l = logging.getLogger("GtkHandlerTest")
l.setLevel(logging.ERROR)
l.addHandler(rh)
log_message = "Debug message"
try:
wibble
except:
l.error(log_message,exc_info=True)
l.removeHandler(rh)
gtk.main()
def testSuite():
suite = unittest.makeSuite(GtkHandlerTest,'test')
return suite
if __name__ == '__main__':
unittest.TextTestRunner().run(testSuite())

View File

@ -0,0 +1,87 @@
import unittest
import logging
import sys
sys.path.append('../../src/GrampsLogger')
logger = logging.getLogger('Gramps.Tests.GrampsLogger')
import _RotateHandler
class RotateHandlerTest(unittest.TestCase):
"""Test the RotateHandler."""
def test_buffer_recall(self):
"""Test that simple recall of messages works."""
rh = _RotateHandler.RotateHandler(10)
l = logging.getLogger("RotateHandlerTest")
l.setLevel(logging.DEBUG)
l.addHandler(rh)
log_message = "Debug message"
l.info(log_message)
assert len(rh.get_buffer()) == 1, "Message buffer wrong size, should be '1' is '%d'" % (len(rh.get_buffer()))
assert rh.get_buffer()[0].getMessage() == log_message, \
"Message buffer content is wrong, should be '%s' is '%s'" \
% (log_message, rh.get_buffer()[0].getMessage())
l.removeHandler(rh)
def test_buffer_rotation(self):
"""Test that buffer correctly rolls over when capacity is reached."""
rh = _RotateHandler.RotateHandler(10)
l = logging.getLogger("RotateHandlerTest")
l.setLevel(logging.DEBUG)
l.addHandler(rh)
log_messages = 20 * [None]
for i in xrange(0,20):
log_messages[i] = "Message %d" % (i)
[l.info(log_messages[i]) for i in xrange(0,10)]
assert len(rh.get_buffer()) == 10, "Message buffer wrong size, should be '10' is '%d'" % (len(rh.get_buffer()))
buffer = rh.get_buffer()
for i in xrange(0,10):
assert buffer[i].getMessage() == log_messages[i], \
"Message buffer content is wrong, should be '%s' is '%s'. i = '%d'" \
% (log_messages[i], buffer[i].getMessage(),i)
l.info(log_messages[10])
buffer = rh.get_buffer()
for i in xrange(0,10):
assert buffer[i].getMessage() == log_messages[i+1], \
"Message buffer content is wrong, should be '%s' is '%s'. i = '%d'" \
% (log_messages[i+1], buffer[i].getMessage(),i)
[l.info(log_messages[i]) for i in xrange(11,20)]
buffer = rh.get_buffer()
for i in xrange(0,10):
assert buffer[i].getMessage() == log_messages[i+10], \
"Message buffer content is wrong, should be '%s' is '%s'. i = '%d'" \
% (log_messages[i+10], buffer[i].getMessage(),i)
l.removeHandler(rh)
def testSuite():
suite = unittest.makeSuite(RotateHandlerTest,'test')
return suite
if __name__ == '__main__':
unittest.TextTestRunner().run(testSuite())