123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- """
- basic logging functionality based on a producer/consumer scheme.
- XXX implement this API: (maybe put it into slogger.py?)
- log = Logger(
- info=py.log.STDOUT,
- debug=py.log.STDOUT,
- command=None)
- log.info("hello", "world")
- log.command("hello", "world")
- log = Logger(info=Logger(something=...),
- debug=py.log.STDOUT,
- command=None)
- """
- import py
- import sys
- class Message(object):
- def __init__(self, keywords, args):
- self.keywords = keywords
- self.args = args
- def content(self):
- return " ".join(map(str, self.args))
- def prefix(self):
- return "[%s] " % (":".join(self.keywords))
- def __str__(self):
- return self.prefix() + self.content()
- class Producer(object):
- """ (deprecated) Log producer API which sends messages to be logged
- to a 'consumer' object, which then prints them to stdout,
- stderr, files, etc. Used extensively by PyPy-1.1.
- """
- Message = Message # to allow later customization
- keywords2consumer = {}
- def __init__(self, keywords, keywordmapper=None, **kw):
- if hasattr(keywords, 'split'):
- keywords = tuple(keywords.split())
- self._keywords = keywords
- if keywordmapper is None:
- keywordmapper = default_keywordmapper
- self._keywordmapper = keywordmapper
- def __repr__(self):
- return "<py.log.Producer %s>" % ":".join(self._keywords)
- def __getattr__(self, name):
- if '_' in name:
- raise AttributeError(name)
- producer = self.__class__(self._keywords + (name,))
- setattr(self, name, producer)
- return producer
- def __call__(self, *args):
- """ write a message to the appropriate consumer(s) """
- func = self._keywordmapper.getconsumer(self._keywords)
- if func is not None:
- func(self.Message(self._keywords, args))
- class KeywordMapper:
- def __init__(self):
- self.keywords2consumer = {}
- def getstate(self):
- return self.keywords2consumer.copy()
- def setstate(self, state):
- self.keywords2consumer.clear()
- self.keywords2consumer.update(state)
- def getconsumer(self, keywords):
- """ return a consumer matching the given keywords.
- tries to find the most suitable consumer by walking, starting from
- the back, the list of keywords, the first consumer matching a
- keyword is returned (falling back to py.log.default)
- """
- for i in range(len(keywords), 0, -1):
- try:
- return self.keywords2consumer[keywords[:i]]
- except KeyError:
- continue
- return self.keywords2consumer.get('default', default_consumer)
- def setconsumer(self, keywords, consumer):
- """ set a consumer for a set of keywords. """
- # normalize to tuples
- if isinstance(keywords, str):
- keywords = tuple(filter(None, keywords.split()))
- elif hasattr(keywords, '_keywords'):
- keywords = keywords._keywords
- elif not isinstance(keywords, tuple):
- raise TypeError("key %r is not a string or tuple" % (keywords,))
- if consumer is not None and not py.builtin.callable(consumer):
- if not hasattr(consumer, 'write'):
- raise TypeError(
- "%r should be None, callable or file-like" % (consumer,))
- consumer = File(consumer)
- self.keywords2consumer[keywords] = consumer
- def default_consumer(msg):
- """ the default consumer, prints the message to stdout (using 'print') """
- sys.stderr.write(str(msg)+"\n")
- default_keywordmapper = KeywordMapper()
- def setconsumer(keywords, consumer):
- default_keywordmapper.setconsumer(keywords, consumer)
- def setstate(state):
- default_keywordmapper.setstate(state)
- def getstate():
- return default_keywordmapper.getstate()
- #
- # Consumers
- #
- class File(object):
- """ log consumer wrapping a file(-like) object """
- def __init__(self, f):
- assert hasattr(f, 'write')
- # assert isinstance(f, file) or not hasattr(f, 'open')
- self._file = f
- def __call__(self, msg):
- """ write a message to the log """
- self._file.write(str(msg) + "\n")
- if hasattr(self._file, 'flush'):
- self._file.flush()
- class Path(object):
- """ log consumer that opens and writes to a Path """
- def __init__(self, filename, append=False,
- delayed_create=False, buffering=False):
- self._append = append
- self._filename = str(filename)
- self._buffering = buffering
- if not delayed_create:
- self._openfile()
- def _openfile(self):
- mode = self._append and 'a' or 'w'
- f = open(self._filename, mode)
- self._file = f
- def __call__(self, msg):
- """ write a message to the log """
- if not hasattr(self, "_file"):
- self._openfile()
- self._file.write(str(msg) + "\n")
- if not self._buffering:
- self._file.flush()
- def STDOUT(msg):
- """ consumer that writes to sys.stdout """
- sys.stdout.write(str(msg)+"\n")
- def STDERR(msg):
- """ consumer that writes to sys.stderr """
- sys.stderr.write(str(msg)+"\n")
- class Syslog:
- """ consumer that writes to the syslog daemon """
- def __init__(self, priority=None):
- if priority is None:
- priority = self.LOG_INFO
- self.priority = priority
- def __call__(self, msg):
- """ write a message to the log """
- import syslog
- syslog.syslog(self.priority, str(msg))
- try:
- import syslog
- except ImportError:
- pass
- else:
- for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split():
- _prio = "LOG_" + _prio
- try:
- setattr(Syslog, _prio, getattr(syslog, _prio))
- except AttributeError:
- pass
|