added initial logging framwork.
svn: r5673
This commit is contained in:
parent
85da63c33b
commit
7f56bd88c7
@ -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 :-)
|
||||
|
@ -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()
|
||||
|
||||
|
205
gramps2/src/GrampsLogger/_ErrorReportAssistant.py
Normal file
205
gramps2/src/GrampsLogger/_ErrorReportAssistant.py
Normal 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())
|
||||
)
|
74
gramps2/src/GrampsLogger/_ErrorView.py
Normal file
74
gramps2/src/GrampsLogger/_ErrorView.py
Normal 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()
|
27
gramps2/src/GrampsLogger/_GtkHandler.py
Normal file
27
gramps2/src/GrampsLogger/_GtkHandler.py
Normal 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)
|
40
gramps2/src/GrampsLogger/_RotateHandler.py
Normal file
40
gramps2/src/GrampsLogger/_RotateHandler.py
Normal 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]
|
48
gramps2/test/GrampsLogger/GtkHandler_Test.py
Normal file
48
gramps2/test/GrampsLogger/GtkHandler_Test.py
Normal 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())
|
87
gramps2/test/GrampsLogger/RotateLogger_Test.py
Normal file
87
gramps2/test/GrampsLogger/RotateLogger_Test.py
Normal 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())
|
Loading…
Reference in New Issue
Block a user