On Wed, 2009-04-22 at 10:54 -0400, William McVey wrote:
> I'm using py.execnet with the SshGateway and I'd like to fire off
> logging messages that get sent over the ssh connection. I was wondering
> if someone has already coded up a logging handler for this.

After a bit of frustration, I have remote logging over an execnet
channel working, with no changes to the py.execnet code itself to
support this. I had to resort to a nasty trick in order to get the
channel to send and receive the logging.LogRecord objects. I think this
could be made a lot cleaner if py.execnet were tweaked to allow defining
a dictionary of namespaces to use when deserializing objects coming over
a channel. If there is any interest in this by the py lib maintainers,
I'll go ahead and fork the code using bitbucket, add this capability in
(probably as a new method on the channel object) and issue a pull
notification.

Anyway, attached is a simple demo script that shows the ExecNetHandler
logging handler in action. I'd love to hear feedback on this. 

  -- William
import py, time, logging

remote_code = """
import logging

class FakeLogRecord(object):
    "Fakes a LogRecord's repr for passing over an execnet channel"
    def __init__(self, log):
        self.log = log

    def __repr__(self):
        l = self.log
	# Serialization of objects going over a channel happens by calling
	# repr() on the object. Deserialization happens with an 
        # eval(mesg, {}). With a minimal namespace, I need to handle the
        # importing of the module myself as an expression encoded in the repr
	# of the  object. Currently, I ignore specified traceback objects
	# attached to a LogRecord via exc_info=True.
        return "__import__('logging').LogRecord(%r, %r, %r, %r, %r, %r, ())" % (
               l.name, l.levelno, l.pathname, l.lineno, l.msg, l.args)


class ExecNetHandler(logging.Handler):
    "Send logging messages over an py.execnet connection"
    
    def __init__(self, channel):
        logging.Handler.__init__(self)
        self.channel = channel

    def emit(self, record):
        obj = FakeLogRecord(record)
        self.channel.send(obj)

# A testrun
log = logging.getLogger("remote")
log.setLevel(logging.DEBUG)
log.addHandler(ExecNetHandler(channel))

log.debug("Starting up")
channel.send("Look ma, I'm home")
log.info("I'm running on the remote side")
try:
    raise RuntimeError("just an exception")
except:
    log.error("Somebody set up us the bomb", exc_info=True)
log.debug("Closing down")
"""

logging.basicConfig(format="%(name)s: %(levelname)s: %(message)s")
remote_log = logging.getLogger("remote")
handler = logging.StreamHandler() 
handler.setLevel(logging.INFO)
remote_log.addHandler(handler)


gw = py.execnet.PopenGateway()
channel = gw.remote_exec(remote_code)

time.sleep(2)
for mesg in channel:
    if isinstance(mesg, logging.LogRecord):
        remote_log.handle(mesg)
        continue
    print "From the remote side:", `mesg`

_______________________________________________
py-dev mailing list
py-dev@codespeak.net
http://codespeak.net/mailman/listinfo/py-dev

Reply via email to