Added log.firewall and log.MetaFirewall, and converted several classes to use them.

This commit is contained in:
Jeremy Fincher 2004-02-06 09:20:47 +00:00
parent 4fec15f40e
commit 47d81547aa
6 changed files with 64 additions and 49 deletions

View File

@ -83,11 +83,7 @@ class AsyncoreDriver(asynchat.async_chat, object):
def writable(self): def writable(self):
while self.connected: while self.connected:
try:
m = self.irc.takeMsg() m = self.irc.takeMsg()
except Exception, e:
log.exception('Uncaught exception in irclib.Irc.takeMsg:')
return
if m: if m:
self.push(str(m)) self.push(str(m))
else: else:

View File

@ -434,13 +434,7 @@ class IrcObjectProxy(RichReplyMethods):
log.debug('Finished calling invalidCommand: %s', cb.name()) log.debug('Finished calling invalidCommand: %s', cb.name())
return return
if hasattr(cb, 'invalidCommand'): if hasattr(cb, 'invalidCommand'):
try:
cb.invalidCommand(self, self.msg, self.args) cb.invalidCommand(self, self.msg, self.args)
except Exception, e:
cb.log.exception('Uncaught exception in invalidCommand:')
log.warning('Uncaught exception in %s.invalidCommand, '
'continuing to call other invalidCommands.' %
cb.name())
def _callCommand(self, name, command, cb): def _callCommand(self, name, command, cb):
try: try:
@ -669,6 +663,8 @@ class ConfigIrcProxy(RichReplyMethods):
class Privmsg(irclib.IrcCallback): class Privmsg(irclib.IrcCallback):
"""Base class for all Privmsg handlers.""" """Base class for all Privmsg handlers."""
__metaclass__ = log.MetaFirewall
__firewalled__ = {'invalidCommand': None} # Eventually callCommand.
threaded = False threaded = False
public = True public = True
alwaysCall = () alwaysCall = ()

View File

@ -75,6 +75,13 @@ class IrcCallback(IrcCommandDispatcher):
# priority means the callback is called *earlier* on the inFilter chain, # priority means the callback is called *earlier* on the inFilter chain,
# *earlier* on the __call__ chain, and *later* on the outFilter chain. # *earlier* on the __call__ chain, and *later* on the outFilter chain.
priority = 99 priority = 99
__metaclass__ = log.MetaFirewall
__firewalled__ = {'die': None,
'reset': None,
'__call__': None,
'inFilter': lambda self, irc, msg: msg,
'outFilter': lambda self, irc, msg: msg,
'name': lambda self: self.__class__.__name__,}
def name(self): def name(self):
"""Returns the name of the callback.""" """Returns the name of the callback."""
return self.__class__.__name__ return self.__class__.__name__
@ -99,11 +106,7 @@ class IrcCallback(IrcCommandDispatcher):
"""Used for handling each message.""" """Used for handling each message."""
method = self.dispatchCommand(msg.command) method = self.dispatchCommand(msg.command)
if method is not None: if method is not None:
try:
method(irc, msg) method(irc, msg)
except Exception, e:
s = 'Exception caught in generic IrcCallback.__call__:'
log.exception(s)
def reset(self): def reset(self):
"""Resets the callback. Called when reconnecting to the server.""" """Resets the callback. Called when reconnecting to the server."""
@ -263,6 +266,8 @@ class IrcState(IrcCommandDispatcher):
"""Maintains state of the Irc connection. Should also become smarter. """Maintains state of the Irc connection. Should also become smarter.
""" """
__slots__ = ('history', 'nicksToHostmasks', 'channels') __slots__ = ('history', 'nicksToHostmasks', 'channels')
__metaclass__ = log.MetaFirewall
__firewalled__ = {'addMsg': None}
def __init__(self): def __init__(self):
self.history = RingBuffer(conf.supybot.maxHistoryLength()) self.history = RingBuffer(conf.supybot.maxHistoryLength())
self.reset() self.reset()
@ -411,6 +416,10 @@ class Irc(IrcCommandDispatcher):
Handles PING commands already. Handles PING commands already.
""" """
__metaclass__ = log.MetaFirewall
__firewalled__ = {'die': None,
'feedMsg': None,
'takeMsg': None,}
_nickSetters = sets.Set(['001', '002', '003', '004', '250', '251', '252', _nickSetters = sets.Set(['001', '002', '003', '004', '250', '251', '252',
'254', '255', '265', '266', '372', '375', '376', '254', '255', '265', '266', '372', '375', '376',
'333', '353', '332', '366', '005']) '333', '353', '332', '366', '005'])
@ -520,31 +529,16 @@ class Irc(IrcCommandDispatcher):
if msg: if msg:
log.debug(repr(msg)) log.debug(repr(msg))
for callback in reviter(self.callbacks): for callback in reviter(self.callbacks):
try: msg = callback.outFilter(self, msg)
outFilter = getattr(callback, 'outFilter')
except AttributeError, e:
continue
try:
msg = outFilter(self, msg)
except:
log.exception('Exception caught in outFilter:')
continue
if msg is None: if msg is None:
log.debug('%s.outFilter returned None' % callback.name()) log.debug('%s.outFilter returned None.' % callback.name())
return self.takeMsg() return self.takeMsg()
if len(str(msg)) > 512: if len(str(msg)) > 512:
# Yes, this violates the contract, but at this point it doesn't # Yes, this violates the contract, but at this point it doesn't
# matter. That's why we gotta go munging in private attributes # matter. That's why we gotta go munging in private attributes
msg._str = msg._str[:500] + '\r\n' msg._str = msg._str[:500] + '\r\n'
msg._len = len(str(msg)) msg._len = len(str(msg))
try:
self.state.addMsg(self, msg) self.state.addMsg(self, msg)
except Exception, e:
log.exception('Uncaught exception in IrcState.addMsg. This '
'could be a bug, but it could also be the '
'result of an invalid message being sent via '
'Owner.ircquote.')
return
log.debug('Outgoing message: ' + str(msg).rstrip('\r\n')) log.debug('Outgoing message: ' + str(msg).rstrip('\r\n'))
return msg return msg
else: else:
@ -668,10 +662,7 @@ class Irc(IrcCommandDispatcher):
log.info('Irc object for %s dying.' % self.server) log.info('Irc object for %s dying.' % self.server)
if self in world.ircs: if self in world.ircs:
for cb in self.callbacks: for cb in self.callbacks:
try:
cb.die() cb.die()
except Exception, e:
log.exception('Uncaught exception in %s.die:', cb.name())
world.ircs.remove(self) world.ircs.remove(self)
else: else:
log.warning('Irc object killed twice.') log.warning('Irc object killed twice.')

View File

@ -42,6 +42,7 @@ import logging
import ansi import ansi
import conf import conf
import utils
import registry import registry
deadlyExceptions = [KeyboardInterrupt, SystemExit] deadlyExceptions = [KeyboardInterrupt, SystemExit]
@ -166,6 +167,45 @@ def timestamp(when=None):
format = conf.supybot.log.timestampFormat() format = conf.supybot.log.timestampFormat()
return time.strftime(format, time.localtime(when)) return time.strftime(format, time.localtime(when))
def firewall(f, errorHandler=None):
def logException(self, s=None):
if s is None:
s = 'Uncaught exception'
if hasattr(self, 'log'):
self.log.exception('%s:', s)
else:
exception('%s in %s.%s:', s, self.__class__.__name__, f.func_name)
def m(self, *args, **kwargs):
try:
return f(self, *args, **kwargs)
except Exception, e:
logException(self)
if errorHandler is not None:
try:
errorHandler(self, *args, **kwargs)
except Exception, e:
logException(self, 'Uncaught exception in errorHandler')
m = utils.changeFunctionName(m, f.func_name, f.__doc__)
return m
class MetaFirewall(type):
def __new__(cls, name, bases, dict):
firewalled = {}
for base in bases:
if hasattr(base, '__firewalled__'):
firewalled.update(base.__firewalled__)
if '__firewalled__' in dict:
firewalled.update(dict['__firewalled__'])
for attr in firewalled:
if attr in dict:
try:
errorHandler = firewalled[attr]
except:
errorHandler = None
dict[attr] = firewall(dict[attr], errorHandler)
return type.__new__(cls, name, bases, dict)
class LogLevel(registry.Value): class LogLevel(registry.Value):
def set(self, s): def set(self, s):

View File

@ -75,11 +75,7 @@ class SocketDriver(drivers.IrcDriver):
self.reconnect() self.reconnect()
def _sendIfMsgs(self): def _sendIfMsgs(self):
try:
msgs = [self.irc.takeMsg()] msgs = [self.irc.takeMsg()]
except Exception, e:
log.exception('Uncaught exception in irclib.Irc.takeMsg:')
return
while msgs[-1] is not None: while msgs[-1] is not None:
msgs.append(self.irc.takeMsg()) msgs.append(self.irc.takeMsg())
del msgs[-1] del msgs[-1]

View File

@ -69,11 +69,7 @@ class SupyIrcProtocol(LineReceiver):
def checkIrcForMsgs(self): def checkIrcForMsgs(self):
if self.connected: if self.connected:
try:
msg = self.irc.takeMsg() msg = self.irc.takeMsg()
except Exception, e:
log.exception('Uncaught exception in irclib.Irc.takeMsg:')
return
if msg: if msg:
self.transport.write(str(msg)) self.transport.write(str(msg))
self.mostRecentCall = reactor.callLater(1, self.checkIrcForMsgs) self.mostRecentCall = reactor.callLater(1, self.checkIrcForMsgs)