187 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
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, 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 """
 | 
						|
        py.std.syslog.syslog(self.priority, str(msg))
 | 
						|
 | 
						|
for _prio in "EMERG ALERT CRIT ERR WARNING NOTICE INFO DEBUG".split():
 | 
						|
    _prio = "LOG_" + _prio
 | 
						|
    try:
 | 
						|
        setattr(Syslog, _prio, getattr(py.std.syslog, _prio))
 | 
						|
    except AttributeError:
 | 
						|
        pass
 |