summaryrefslogtreecommitdiff
path: root/logger.py
diff options
context:
space:
mode:
Diffstat (limited to 'logger.py')
-rw-r--r--logger.py313
1 files changed, 313 insertions, 0 deletions
diff --git a/logger.py b/logger.py
new file mode 100644
index 0000000..7ee3e5e
--- /dev/null
+++ b/logger.py
@@ -0,0 +1,313 @@
+#!/usr/bin/python
+
+from threading import Thread, Lock
+import re, time, sys, string, socket, os, platform, traceback, Queue, ssl, urllib2
+
+class LogRotate(Thread):
+ def __init__(self, logger):
+ self.logger=logger
+ Thread.__init__(self)
+ def run(self):
+ Y, M, D, h, m, s, w, d, dst=time.localtime()
+ nextrotate=int(time.mktime((Y, M, D+1, 0, 0, 0, 0, 0, -1)))
+ #print time.time()-nextrotate
+ #print time.localtime(), time.localtime(nextrotate)
+ while True:
+ #print "LogRotate will sleep until %d/%d/%d %d:%02d:%02d"%(time.localtime(nextrotate)[:6])
+ while nextrotate>time.time(): ### May need to do this in a loop in case the following time.sleep command wakes up a second too early.
+ time.sleep(max(0.25, nextrotate-time.time()))
+ self.logger.rotatelock.acquire()
+ if all([not log or log.closed for log in self.logger.consolelogs.values()+self.logger.channellogs.values()]):
+ ### If there are no logs to rotate
+ self.logger.logrotate=None
+ self.logger.rotatelock.release()
+ break
+ self.logger.rotatelock.release()
+ #print "Rotating Logs"
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ for network in self.logger.labels.keys():
+ #network.loglock.acquire()
+ if network.connected:
+ network.lock.acquire()
+ self.logger.rotateConsoleLog(network)
+ if network.identity:
+ for channel in network.identity.channels:
+ self.logger.rotateChannelLog(channel)
+ network.lock.release()
+ nextrotate+=3600*24
+
+class Logger(object):
+ def __init__(self, logroot, **networks):
+ self.logroot=logroot
+ path=[logroot]
+ #print path
+ while not os.path.isdir(path[0]):
+ split=os.path.split(path[0])
+ path.insert(1,split[1])
+ path[0]=split[0]
+ #print path
+ while len(path)>1:
+ path[0]=os.path.join(*path[:2])
+ del path[1]
+ #print path
+ os.mkdir(path[0])
+ #return
+ self.consolelogs={}
+ self.channellogs={}
+ self.networks=networks
+ self.labels={}
+ for (label,network) in networks.items():
+ if not os.path.isdir(os.path.join(self.logroot, label)):
+ os.mkdir(os.path.join(self.logroot, label))
+ if network in self.labels.keys():
+ raise BaseException, "Network already exists"
+ self.labels[network]=label
+ network.lock.acquire()
+ network.modules.append(self)
+ network.lock.release()
+ self.rotatelock=Lock()
+ self.logrotate=None
+ def addNetworks(self, **networks):
+ for (label,network) in networks.items():
+ if not os.path.isdir(os.path.join(self.logroot, label)):
+ os.mkdir(os.path.join(self.logroot, label))
+ if label in self.labels.values():
+ raise BaseException, "Label already exists"
+ if network in self.networks.keys():
+ raise BaseException, "Network already exists"
+ for (label,network) in networks.items():
+ self.labels[network]=label
+ network.lock.acquire()
+ network.modules.append(self)
+ if network.connected:
+ openConsoleLog(network)
+ network.lock.release()
+ def removeNetworks(self, *networks):
+ for network in networks:
+ if network not in self.networks.keys():
+ raise BaseException, "Network not added"
+ for network in networks:
+ network.lock.acquire()
+ network.modules.append(self)
+ if network.connected:
+ closeConsoleLog(network)
+ network.lock.release()
+ del self.labels[network]
+ del self.consolelogs[network]
+ def openConsoleLog(self, network):
+ self.rotatelock.acquire()
+ if not self.logrotate or not self.logrotate.isAlive():
+ self.logrotate=LogRotate(self)
+ self.logrotate.daemon=True
+ self.logrotate.start()
+ self.rotatelock.release()
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ self.consolelogs[network]=open(os.path.join(self.logroot, self.labels[network], "console-%04d.%02d.%02d.log"%now[:3]), "a")
+ print >>self.consolelogs[network], "%s %s ### Log session started" % (timestamp, time.tzname[now[-1]])
+ self.consolelogs[network].flush()
+ def closeConsoleLog(self, network):
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ print >>self.consolelogs[network], "%s %s ### Log session ended" % (timestamp, time.tzname[now[-1]])
+ self.consolelogs[network].close()
+ def rotateConsoleLog(self, network):
+ self.closeConsoleLog(network)
+ self.openConsoleLog(network)
+
+ def openChannelLog(self, channel):
+ self.rotatelock.acquire()
+ if not self.logrotate or not self.logrotate.isAlive():
+ self.logrotate=LogRotate(self)
+ self.logrotate.daemon=True
+ self.logrotate.start()
+ self.rotatelock.release()
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ label=self.labels[channel.context]
+ self.channellogs[channel]=open(os.path.join(self.logroot, label, "channel-%s-%04d.%02d.%02d.log"%((urllib2.quote(channel.name.lower()).replace("/","%2f"),)+now[:3])), "a")
+ print >>self.channellogs[channel], "%s %s ### Log session started" % (timestamp, time.tzname[now[-1]])
+ self.channellogs[channel].flush()
+ if channel.context.identity in channel.users:
+ if channel.topic: print >>self.channellogs[channel], "%s %s <<< :%s 332 %s %s :%s" % (timestamp, time.tzname[now[-1]], channel.context.serv, channel.context.identity.nick, channel.name, channel.topic)
+ if channel.topicsetby and channel.topictime: print >>self.channellogs[channel], "%s %s <<< :%s 333 %s %s %s %s" % (timestamp, time.tzname[now[-1]], channel.context.serv, channel.context.identity.nick, channel.name, channel.topicsetby, channel.topictime)
+ if channel.users:
+ secret="s" in channel.modes.keys() and channel.modes["s"]
+ private="p" in channel.modes.keys() and channel.modes["p"]
+ namesusers=[]
+ modes, symbols=channel.context.supports["PREFIX"]
+ print >>self.channellogs[channel], "%s %s <<< :%s 353 %s %s %s :%s" % (timestamp, time.tzname[now[-1]],
+ channel.context.serv,
+ channel.context.identity.nick,
+ "@" if secret else ("*" if private else "="),
+ channel.name,
+ " ".join(["".join([symbols[k] if modes[k] in channel.modes.keys() and user in channel.modes[modes[k]] else "" for k in xrange(len(modes))])+user.nick for user in channel.users]))
+ if channel.modes:
+ modes=channel.modes.keys()
+ modestr="".join([mode for mode in modes if mode not in channel.context.supports["CHANMODES"][0]+channel.context.supports["PREFIX"][0] and channel.modes[mode]])
+ params=" ".join([channel.modes[mode] for mode in modes if mode in channel.context.supports["CHANMODES"][1]+channel.context.supports["CHANMODES"][2] and channel.modes[mode]])
+ print >>self.channellogs[channel], "%s %s <<< :%s 324 %s %s +%s %s" % (timestamp, time.tzname[now[-1]], channel.context.server, channel.context.identity.nick, channel.name, modestr, params)
+ if channel.created: print >>self.channellogs[channel], "%s %s <<< :%s 329 %s %s %s" % (timestamp, time.tzname[now[-1]], channel.context.serv, channel.context.identity.nick, channel.name, channel.created)
+ self.channellogs[channel].flush()
+ def closeChannelLog(self, channel):
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ print >>self.channellogs[channel], "%s %s ### Log session ended" % (timestamp, time.tzname[now[-1]])
+ self.channellogs[channel].close()
+ def rotateChannelLog(self, channel):
+ self.closeChannelLog(channel)
+ self.openChannelLog(channel)
+ def onRecv(self, IRC, line, data):
+ modemapping=dict(Y="ircop", q="owner", a="admin", o="op", h="halfop", v="voice")
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ if data==None:
+ print >>self.consolelogs[IRC], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.consolelogs[IRC].flush()
+ return
+ (origin, ident, host, cmd, target, params, extinfo)=data
+ if re.match("^\\d+$",cmd): cmd=int(cmd)
+ if cmd in (324, 329):
+ modeparams=params.split()
+ channame=modeparams[0]
+ channel=IRC.channel(channame)
+ if channel in self.channellogs.keys() and not self.channellogs[channel].closed: log=self.channellogs[channel]
+ else: log=self.consolelogs[IRC]
+ print >>log, "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ log.flush()
+ elif cmd == 332:
+ channel=IRC.channel(params)
+ if channel in self.channellogs.keys() and not self.channellogs[channel].closed: log=self.channellogs[channel]
+ else: log=self.consolelogs[IRC]
+ print >>log, "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ log.flush()
+ elif cmd == 333:
+ (channame,nick,dt)=params.split()
+ channel=IRC.channel(channame)
+ if not self.channellogs[channel].closed:
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif cmd == 353:
+ (flag, channame)=params.split()
+ channel=IRC.channel(channame)
+ if not self.channellogs[channel].closed:
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif cmd=="JOIN":
+ user=IRC.user(origin)
+ channel=IRC.channel(target if len(target) else extinfo)
+ if user==IRC.identity:
+ self.openChannelLog(channel)
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif cmd == "PRIVMSG":
+ if target and target[0] in IRC.supports["CHANTYPES"]:
+ channel=IRC.channel(target)
+ if ident and host:
+ user=IRC.user(origin)
+ classes=" ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and user in channel.modes[mode]])
+ else:
+ classes="server"
+ if classes: print >>self.channellogs[channel], "%s %s %s <<< %s" % (timestamp, time.tzname[now[-1]], classes, line)
+ else: print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif cmd == "NOTICE":
+ if target and (target[0] in IRC.supports["CHANTYPES"] or (len(target)>1 and target[0] in IRC.supports["PREFIX"][1] and target[1] in IRC.supports["CHANTYPES"])):
+ if target[0] in IRC.supports["PREFIX"][1]:
+ channel=IRC.channel(target[1:])
+ else:
+ channel=IRC.channel(target)
+ if ident and host:
+ user=IRC.user(origin)
+ classes=" ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and user in channel.modes[mode]])
+ else:
+ classes="server"
+ if classes: print >>self.channellogs[channel], "%s %s %s <<< %s" % (timestamp, time.tzname[now[-1]], classes, line)
+ else: print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif target.lower()==IRC.identity.nick.lower() and not ident and not host:
+ print >>self.consolelogs[IRC], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.consolelogs[IRC].flush()
+ elif cmd == "TOPIC":
+ channel=IRC.channel(target)
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ elif cmd == "PART":
+ user=IRC.user(origin)
+ channel=IRC.channel(target)
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ if user==IRC.identity:
+ self.closeChannelLog(channel)
+ elif cmd == "KICK":
+ kicked=IRC.user(params)
+ channel=IRC.channel(target)
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ if kicked==IRC.identity:
+ self.closeChannelLog(channel)
+ elif cmd == "MODE":
+ if target and target[0] in IRC.supports["CHANTYPES"]:
+ channel=IRC.channel(target)
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ else:
+ print >>self.consolelogs[IRC], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.consolelogs[IRC].flush()
+ elif cmd in ("NICK", "QUIT"):
+ user=IRC.user(origin)
+ for channel in user.channels:
+ print >>self.channellogs[channel], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.channellogs[channel].flush()
+ else:
+ print >>self.consolelogs[IRC], "%s %s <<< %s" % (timestamp, time.tzname[now[-1]], line)
+ self.consolelogs[IRC].flush()
+ def onConnectAttempt(self, IRC):
+ if IRC not in self.consolelogs.keys() or (not self.consolelogs[IRC]) or self.consolelogs[IRC].closed:
+ self.openConsoleLog(IRC)
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ print >>self.consolelogs[IRC], "%s %s *** Attempting connection to %s:%s." % (timestamp, time.tzname[now[-1]], IRC.server, IRC.port)
+ def onConnect(self, IRC):
+ if IRC not in self.consolelogs.keys() or (not self.consolelogs[IRC]) or self.consolelogs[IRC].closed:
+ self.openConsoleLog(IRC)
+ #self.openConsoleLog(IRC)
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ print >>self.consolelogs[IRC], "%s %s *** Connection to %s:%s established." % (timestamp, time.tzname[now[-1]], IRC.server, IRC.port)
+ def onDisconnect(self, IRC):
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ for channel in IRC.identity.channels:
+ print >>self.channellogs[channel], "%s %s *** Connection to %s:%s terminated." % (timestamp, time.tzname[now[-1]], IRC.server, IRC.port)
+ self.channellogs[channel].flush()
+ self.closeChannelLog(channel)
+ print >>self.consolelogs[IRC], "%s %s *** Connection %s:%s terminated." % (timestamp, time.tzname[now[-1]], IRC.server, IRC.port)
+ self.consolelogs[IRC].flush()
+ self.closeConsoleLog(IRC)
+ def onSend(self, IRC, line, data, origin):
+ modemapping=dict(Y="ircop", q="owner", a="admin", o="op", h="halfop", v="voice")
+ now=time.localtime()
+ timestamp=reduce(lambda x,y: x+":"+y,[str(t).rjust(2,"0") for t in now[0:6]])
+ (cmd, target, params, extinfo)=data
+ if IRC.registered and cmd=="PRIVMSG" and "CHANTYPES" in IRC.supports.keys() and len(target) and target[0] in IRC.supports["CHANTYPES"]:
+ channel=IRC.channel(target)
+ if channel in IRC.identity.channels:
+ classes=" ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and IRC.identity in channel.modes[mode]])
+ if classes: print >>self.channellogs[channel], "%s %s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], classes, IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ else: print >>self.channellogs[channel], "%s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ self.channellogs[channel].flush()
+ else:
+ print >>self.consolelogs[IRC], "%s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ self.consolelogs[IRC].flush()
+ if IRC.registered and len(target) and (target[0] in IRC.supports["CHANTYPES"] or (len(target)>1 and target[0] in IRC.supports["PREFIX"][1] and target[1] in IRC.supports["CHANTYPES"])) and cmd=="NOTICE":
+ channel=IRC.channel(target[1:] if target[0] in IRC.supports["PREFIX"][1] else target)
+ if channel in IRC.identity.channels:
+ classes=" ".join([modemapping[mode] for mode in IRC.supports["PREFIX"][0] if mode in channel.modes.keys() and IRC.identity in channel.modes[mode]])
+ if classes: print >>self.channellogs[channel], "%s %s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], classes, IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ else: print >>self.channellogs[channel], "%s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ self.channellogs[channel].flush()
+ else:
+ print >>self.consolelogs[IRC], "%s %s >>> :%s!%s@%s %s" % (timestamp, time.tzname[now[-1]], IRC.identity.nick, IRC.identity.idnt, IRC.identity.host, line)
+ self.consolelogs[IRC].flush()