Refactor exception handling for logger

- Handle exceptions inside write() instead of propagating the
    exception
- Add error message to exception
- Add dispatch() method in logger
This commit is contained in:
Philipp Hörist 2017-04-08 22:53:50 +02:00
parent 54eb1cbbb8
commit a51ea32dc6
9 changed files with 80 additions and 150 deletions

View File

@ -1623,14 +1623,9 @@ class ChatControl(ChatControlBase):
pending_how_many += len(gajim.events.get_events(self.account,
self.contact.get_full_jid(), ['chat', 'pm']))
try:
rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
pending_how_many, timeout, self.account)
except exceptions.DatabaseMalformed:
dialogs.ErrorDialog(_('Database Error'),
_('The database file (%s) cannot be read. Try to repair it or '
'remove it (all history will be lost).') % logger.LOG_DB_PATH)
rows = []
rows = gajim.logger.get_last_conversation_lines(jid, restore_how_many,
pending_how_many, timeout, self.account)
local_old_kind = None
self.conv_textview.just_cleared = True
for row in rows: # row[0] time, row[1] has kind, row[2] the message, row[3] subject, row[4] additional_data

View File

@ -529,20 +529,10 @@ class CommonConnection:
kind = 'chat_msg_sent'
else:
kind = 'single_msg_sent'
try:
gajim.logger.write(
kind, obj.jid, message, subject=obj.subject,
additional_data=obj.additional_data)
except exceptions.PysqliteOperationalError as error:
self.dispatch('DB_ERROR', (_('Disk Write Error'), str(error)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try'
' to repair it (see '
'https://dev.gajim.org/gajim/gajim/wikis/help/DatabaseBackup)'
' or remove it (all history will be lost).') % \
common.logger.LOG_DB_PATH
self.dispatch('DB_ERROR', (pritext, sectext))
gajim.logger.write(
kind, obj.jid, message, subject=obj.subject,
additional_data=obj.additional_data)
def ack_subscribed(self, jid):
"""

View File

@ -1069,17 +1069,7 @@ class ConnectionHandlersBase:
if gajim.config.get('log_contact_status_changes') and \
gajim.config.should_log(self.name, obj.jid):
try:
gajim.logger.write('status', obj.jid, obj.status, obj.show)
except exceptions.PysqliteOperationalError as e:
self.dispatch('DB_ERROR', (_('Disk Write Error'), str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % LOG_DB_PATH
self.dispatch('DB_ERROR', (pritext, sectext))
our_jid = gajim.get_jid_from_account(self.name)
gajim.logger.write('status', obj.jid, obj.status, obj.show)
def _nec_gc_presence_received(self, obj):
if obj.conn.name != self.name:
@ -1244,18 +1234,8 @@ class ConnectionHandlersBase:
subject = msg.getSubject()
if session.is_loggable():
try:
gajim.logger.write('error', frm, error_msg, tim=tim,
subject=subject)
except exceptions.PysqliteOperationalError as e:
self.dispatch('DB_ERROR', (_('Disk Write Error'), str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % \
common.logger.LOG_DB_PATH
self.dispatch('DB_ERROR', (pritext, sectext))
gajim.logger.write('error', frm, error_msg, tim=tim,
subject=subject)
gajim.nec.push_incoming_event(MessageErrorEvent(None, conn=self,
fjid=frm, error_code=msg.getErrorCode(), error_msg=error_msg,
msg=msgtxt, time_=tim, session=session, stanza=msg))

View File

@ -946,18 +946,7 @@ class GcPresenceReceivedEvent(nec.NetworkIncomingEvent, HelperEvent):
if jid:
# we know real jid, save it in db
st += ' (%s)' % jid
try:
gajim.logger.write('gcstatus', self.fjid, st, self.show)
except exceptions.PysqliteOperationalError as e:
self.conn.dispatch('DB_ERROR', (_('Disk Write Error'), str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. '
'Try to repair it (see '
'http://trac.gajim.org/wiki/DatabaseBackup) or '
'remove it (all history will be lost).') % \
LOG_DB_PATH
self.conn.dispatch('DB_ERROR', (pritext, sectext))
gajim.logger.write('gcstatus', self.fjid, st, self.show)
if self.avatar_sha == '':
# contact has no avatar
puny_nick = helpers.sanitize_filename(self.nick)

View File

@ -38,11 +38,15 @@ class DatabaseMalformed(Exception):
The databas can't be read
"""
def __init__(self):
def __init__(self, path=''):
Exception.__init__(self)
self.path = path
def __str__(self):
return _('Database cannot be read.')
return _('The database file (%s) cannot be read. '
'Try to repair it (see '
'https://dev.gajim.org/gajim/gajim/wikis/help/DatabaseBackup)'
' or remove it (all history will be lost).') % self.path
class ServiceNotAvailable(Exception):
"""

View File

@ -121,6 +121,9 @@ class Logger:
gajim.ged.register_event_handler('gc-message-received',
ged.POSTCORE, self._nec_gc_message_received)
def dispatch(self, event, error):
gajim.ged.raise_event(event, None, str(error))
def close_db(self):
if self.con:
self.con.close()
@ -191,7 +194,7 @@ class Logger:
# list of tuples: [('aaa@bbb',), ('cc@dd',)]
rows = self.cur.fetchall()
except sqlite.DatabaseError:
raise exceptions.DatabaseMalformed
raise exceptions.DatabaseMalformed(LOG_DB_PATH)
self.jids_already_in = []
for row in rows:
# row[0] is first item of row (the only result here, the jid)
@ -416,7 +419,7 @@ class Logger:
except sqlite.OperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
except sqlite.DatabaseError:
raise exceptions.DatabaseMalformed
raise exceptions.DatabaseMalformed(LOG_DB_PATH)
message_id = None
if write_unread:
try:
@ -531,58 +534,53 @@ class Logger:
show)
write_unread = False
# now we may have need to do extra care for some values in columns
if kind == 'status': # we store (not None) time, jid, show, msg
# status for roster items
try:
try:
# now we may have need to do extra care for some values in columns
if kind == 'status': # we store (not None) time, jid, show, msg
# status for roster items
jid_id = self.get_jid_id(jid)
except exceptions.PysqliteOperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
if show is None: # show is None (xmpp), but we say that 'online'
show_col = ShowConstant.ONLINE
if show is None: # show is None (xmpp), but we say that 'online'
show_col = ShowConstant.ONLINE
elif kind == 'gcstatus':
# status in ROOM (for pm status see status)
if show is None: # show is None (xmpp), but we say that 'online'
show_col = ShowConstant.ONLINE
jid, nick = jid.split('/', 1)
try:
# re-get jid_id for the new jid
jid_id = self.get_jid_id(jid, 'ROOM')
except exceptions.PysqliteOperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
contact_name_col = nick
elif kind == 'gc_msg':
if jid.find('/') != -1: # if it has a /
elif kind == 'gcstatus':
# status in ROOM (for pm status see status)
if show is None: # show is None (xmpp), but we say that 'online'
show_col = ShowConstant.ONLINE
jid, nick = jid.split('/', 1)
else:
# it's server message f.e. error message
# when user tries to ban someone but he's not allowed to
nick = None
try:
# re-get jid_id for the new jid
jid_id = self.get_jid_id(jid, 'ROOM')
except exceptions.PysqliteOperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
contact_name_col = nick
else:
try:
contact_name_col = nick
elif kind == 'gc_msg':
if jid.find('/') != -1: # if it has a /
jid, nick = jid.split('/', 1)
else:
# it's server message f.e. error message
# when user tries to ban someone but he's not allowed to
nick = None
# re-get jid_id for the new jid
jid_id = self.get_jid_id(jid, 'ROOM')
contact_name_col = nick
else:
jid_id = self.get_jid_id(jid)
except exceptions.PysqliteOperationalError as e:
raise exceptions.PysqliteOperationalError(str(e))
if kind == 'chat_msg_recv':
if not self.jid_is_from_pm(jid) and not mam_query:
# Save in unread table only if it's not a pm
write_unread = True
if kind == 'chat_msg_recv':
if not self.jid_is_from_pm(jid) and not mam_query:
# Save in unread table only if it's not a pm
write_unread = True
if show_col == 'UNKNOWN': # unknown show, do not log
return
if show_col == 'UNKNOWN': # unknown show, do not log
return
values = (jid_id, contact_name_col, time_col, kind_col, show_col,
message_col, subject_col, additional_data_col)
return self.commit_to_db(values, write_unread)
values = (jid_id, contact_name_col, time_col, kind_col, show_col,
message_col, subject_col, additional_data_col)
return self.commit_to_db(values, write_unread)
except (exceptions.DatabaseMalformed,
exceptions.PysqliteOperationalError) as error:
self.dispatch('DB_ERROR', error)
def get_last_conversation_lines(self, jid, restore_how_many_rows,
pending_how_many, timeout, account):
@ -621,7 +619,9 @@ class Logger:
parsed_entry = entry[:4] + (additional_data, ) + entry[5:]
messages.append(parsed_entry)
except sqlite.DatabaseError:
raise exceptions.DatabaseMalformed
self.dispatch('DB_ERROR',
exceptions.DatabaseMalformed(LOG_DB_PATH))
return []
messages.reverse()
return messages
@ -1186,19 +1186,8 @@ class Logger:
# if not obj.nick, it means message comes from room itself
# usually it hold description and can be send at each connection
# so don't store it in logs
try:
self.write('gc_msg', obj.fjid, obj.msgtxt, tim=obj.timestamp, additional_data=obj.additional_data)
# store in memory time of last message logged.
# this will also be saved in rooms_last_message_time table
# when we quit this muc
obj.conn.last_history_time[obj.jid] = tim_f
except exceptions.PysqliteOperationalError as e:
obj.conn.dispatch('DB_ERROR', (_('Disk Write Error'), str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % \
LOG_DB_PATH
obj.conn.dispatch('DB_ERROR', (pritext, sectext))
self.write('gc_msg', obj.fjid, obj.msgtxt, tim=obj.timestamp, additional_data=obj.additional_data)
# store in memory time of last message logged.
# this will also be saved in rooms_last_message_time table
# when we quit this muc
obj.conn.last_history_time[obj.jid] = tim_f

View File

@ -142,17 +142,14 @@ class GajimApplication(Gtk.Application):
gajim.logger = logger.Logger()
caps_cache.initialize(gajim.logger)
check_paths.check_and_possibly_create_paths()
except exceptions.DatabaseMalformed:
except exceptions.DatabaseMalformed as error:
dlg = Gtk.MessageDialog(
None,
Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.MODAL,
Gtk.MessageType.ERROR,
Gtk.ButtonsType.OK,
_('Database Error'))
dlg.format_secondary_text(
_('The database file (%s) cannot be read. Try to repair it '
'(see http://trac.gajim.org/wiki/DatabaseBackup) or remove it '
'(all history will be lost).') % gajim.gajimpaths['LOG_DB'])
dlg.format_secondary_text(str(error))
dlg.run()
dlg.destroy()
sys.exit()

View File

@ -109,11 +109,11 @@ class Interface:
### Methods handling events from connection
################################################################################
def handle_event_db_error(self, unused, data):
#('DB_ERROR', account, (title_text, section_text))
def handle_event_db_error(self, unused, error):
#('DB_ERROR', account, error)
if self.db_error_dialog:
return
self.db_error_dialog = dialogs.ErrorDialog(data[0], data[1])
self.db_error_dialog = dialogs.ErrorDialog(_('Database Error'), error)
def destroyed(win):
self.db_error_dialog = None
self.db_error_dialog.connect('destroy', destroyed)

View File

@ -95,26 +95,12 @@ class ChatControlSession(stanza_session.EncryptedStanzaSession):
log_type += end
if self.is_loggable() and obj.msgtxt:
try:
if obj.xhtml and gajim.config.get('log_xhtml_messages'):
msg_to_log = obj.xhtml
else:
msg_to_log = obj.msgtxt
obj.msg_log_id = gajim.logger.write(log_type, obj.fjid,
msg_to_log, tim=obj.timestamp, subject=obj.subject, additional_data=obj.additional_data)
except exceptions.PysqliteOperationalError as e:
gajim.nec.push_incoming_event(InformationEvent(None,
conn=self.conn, level='error', pri_txt=_('Disk Write Error'),
sec_txt=str(e)))
except exceptions.DatabaseMalformed:
pritext = _('Database Error')
sectext = _('The database file (%s) cannot be read. Try to '
'repair it (see http://trac.gajim.org/wiki/DatabaseBackup) '
'or remove it (all history will be lost).') % \
gajim.logger.LOG_DB_PATH
gajim.nec.push_incoming_event(InformationEvent(None,
conn=self.conn, level='error', pri_txt=pritext,
sec_txt=sectext))
if obj.xhtml and gajim.config.get('log_xhtml_messages'):
msg_to_log = obj.xhtml
else:
msg_to_log = obj.msgtxt
obj.msg_log_id = gajim.logger.write(log_type, obj.fjid,
msg_to_log, tim=obj.timestamp, subject=obj.subject, additional_data=obj.additional_data)
treat_as = gajim.config.get('treat_incoming_messages')
if treat_as: