tahoe-lafs/misc/logtool.py

202 lines
6.0 KiB
Python
Raw Normal View History

#! /usr/bin/python
2007-11-19 01:32:04 +00:00
import os.path, time, pickle
import foolscap
2007-11-19 01:32:04 +00:00
from foolscap import RemoteInterface
from foolscap.eventual import fireEventually
from foolscap.schema import DictOf, Any
2007-11-19 01:32:04 +00:00
from twisted.internet import reactor, defer
from zope.interface import implements
2007-11-19 01:32:04 +00:00
from twisted.python import usage
#from twisted.python import log
#import sys
#log.startLogging(sys.stderr)
2007-11-19 01:32:04 +00:00
class Options(usage.Options):
longdesc = """
logtool tail FURL : follow logs of the target node
logtool gather : run as a daemon, record all logs to the current directory
logtool dump FILE : dump the logs recorded by 'logtool gather'
"""
2007-11-19 01:32:04 +00:00
def parseArgs(self, mode, *args):
self.mode = mode
if mode == "tail":
target = args[0]
if target.startswith("pb:"):
self.target_furl = target
elif os.path.isfile(target):
self.target_furl = open(target, "r").read().strip()
elif os.path.isdir(target):
fn = os.path.join(target, "logport.furl")
self.target_furl = open(fn, "r").read().strip()
else:
raise RuntimeError("Can't use tail target: %s" % target)
elif mode == "dump":
self.dumpfile = args[0]
class RILogObserver(RemoteInterface):
def msg(logmsg=DictOf(str, Any())):
return None
2007-11-19 01:32:04 +00:00
class RISubscription(RemoteInterface):
pass
2007-11-19 01:32:04 +00:00
class RILogPublisher(RemoteInterface):
def get_versions():
return DictOf(str, str)
def subscribe_to_all(observer=RILogObserver):
return RISubscription
def unsubscribe(subscription=Any()):
# I don't know how to get the constraint right: unsubscribe() should
# accept return value of subscribe_to_all()
return None
class RILogGatherer(RemoteInterface):
def logport(nodeid=str, logport=RILogPublisher):
return None
class LogPrinter(foolscap.Referenceable):
implements(RILogObserver)
2007-11-19 01:32:04 +00:00
def remote_msg(self, d):
print d
class LogTail:
def start(self, target_furl):
print "Connecting.."
2007-11-19 01:32:04 +00:00
d = defer.maybeDeferred(self.setup_tub)
d.addCallback(self._tub_ready, target_furl)
return d
def setup_tub(self):
self._tub = foolscap.Tub()
self._tub.startService()
2007-11-19 01:32:04 +00:00
def _tub_ready(self, res, target_furl):
d = self._tub.getReference(target_furl)
d.addCallback(self._got_logpublisher)
2007-11-19 01:32:04 +00:00
return d
def _got_logpublisher(self, publisher):
print "Connected"
2007-11-19 01:32:04 +00:00
lp = LogPrinter()
d = publisher.callRemote("subscribe_to_all", lp)
return d
def remote_msg(self, d):
print d
2007-11-19 01:32:04 +00:00
class LogSaver(foolscap.Referenceable):
implements(RILogObserver)
def __init__(self, nodeid, savefile):
self.nodeid = nodeid
self.f = savefile
def remote_msg(self, d):
e = {"from": self.nodeid,
"rx_time": time.time(),
"d": d,
}
pickle.dump(e, self.f)
def disconnected(self):
del self.f
from allmydata.util.idlib import shortnodeid_b2a
print "LOGPORT CLOSED", shortnodeid_b2a(self.nodeid)
class LogGatherer(foolscap.Referenceable):
implements(RILogGatherer)
def start(self, res):
self._savefile = open("logs.pickle", "ab", 0)
d = self.setup_tub()
d.addCallback(self._tub_ready)
return d
def setup_tub(self):
from allmydata.util import iputil
self._tub = foolscap.Tub(certFile="gatherer.pem")
self._tub.startService()
portnumfile = "portnum"
try:
portnum = int(open(portnumfile, "r").read())
except (EnvironmentError, ValueError):
portnum = 0
self._tub.listenOn("tcp:%d" % portnum)
d = defer.maybeDeferred(iputil.get_local_addresses_async)
d.addCallback(self._set_location)
return d
def _set_location(self, local_addresses):
l = self._tub.getListeners()[0]
portnum = l.getPortnum()
portnumfile = "portnum"
open(portnumfile, "w").write("%d\n" % portnum)
local_addresses = [ "%s:%d" % (addr, portnum,)
for addr in local_addresses ]
location = ",".join(local_addresses)
self._tub.setLocation(location)
def _tub_ready(self, res):
me = self._tub.registerReference(self, furlFile="log_gatherer.furl")
print "Gatherer waiting at:", me
def remote_logport(self, nodeid, publisher):
from allmydata.util.idlib import shortnodeid_b2a
short = shortnodeid_b2a(nodeid)
print "GOT LOGPORT", short
ls = LogSaver(nodeid, self._savefile)
publisher.callRemote("subscribe_to_all", ls)
publisher.notifyOnDisconnect(ls.disconnected)
class LogDumper:
def start(self, options):
from allmydata.util.idlib import shortnodeid_b2a
fn = options.dumpfile
f = open(fn, "rb")
while True:
try:
e = pickle.load(f)
short = shortnodeid_b2a(e['from'])
when = e['rx_time']
print "%s %r: %r" % (short, when, e['d'])
except EOFError:
break
class LogTool:
def run(self, options):
mode = options.mode
if mode == "tail":
lt = LogTail()
d = fireEventually(options.target_furl)
d.addCallback(lt.start)
d.addErrback(self._error)
print "starting.."
reactor.run()
elif mode == "gather":
lg = LogGatherer()
d = fireEventually()
d.addCallback(lg.start)
d.addErrback(self._error)
print "starting.."
reactor.run()
elif mode == "dump":
ld = LogDumper()
ld.start(options)
else:
print "unknown mode '%s'" % mode
raise NotImplementedError
def _error(self, f):
print "ERROR", f
reactor.stop()
2007-11-19 01:32:04 +00:00
if __name__ == '__main__':
o = Options()
o.parseOptions()
lt = LogTool()
lt.run(o)