89 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			89 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Python
		
	
	
	
"""
 | 
						|
py lib's basic logging/tracing functionality 
 | 
						|
 | 
						|
    EXPERIMENTAL EXPERIMENTAL EXPERIMENTAL (especially the dispatching) 
 | 
						|
 | 
						|
WARNING: this module is not allowed to contain any 'py' imports, 
 | 
						|
         Instead, it is very self-contained and should not depend on 
 | 
						|
         CPython/stdlib versions, either.  One reason for these 
 | 
						|
         restrictions is that this module should be sendable
 | 
						|
         via py.execnet across the network in an very early phase.  
 | 
						|
"""
 | 
						|
 | 
						|
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):
 | 
						|
    """ Log producer API which sends messages to be logged
 | 
						|
        to a 'consumer' object, which then prints them to stdout,
 | 
						|
        stderr, files, etc.
 | 
						|
    """
 | 
						|
    
 | 
						|
    Message = Message  # to allow later customization 
 | 
						|
    keywords2consumer = {}
 | 
						|
 | 
						|
    def __init__(self, keywords): 
 | 
						|
        if isinstance(keywords, str): 
 | 
						|
            keywords = tuple(keywords.split())
 | 
						|
        self.keywords = keywords
 | 
						|
 | 
						|
    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.get_consumer(self.keywords)
 | 
						|
        if func is not None: 
 | 
						|
            func(self.Message(self.keywords, args))
 | 
						|
   
 | 
						|
    def get_consumer(self, keywords): 
 | 
						|
        """ return a consumer matching 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(self.keywords), 0, -1): 
 | 
						|
            try: 
 | 
						|
                return self.keywords2consumer[self.keywords[:i]]
 | 
						|
            except KeyError: 
 | 
						|
                continue
 | 
						|
        return self.keywords2consumer.get('default', default_consumer)
 | 
						|
 | 
						|
    def set_consumer(self, consumer): 
 | 
						|
        """ register a consumer matching our own keywords """
 | 
						|
        self.keywords2consumer[self.keywords] = consumer 
 | 
						|
 | 
						|
default = Producer('default')
 | 
						|
 | 
						|
def _getstate(): 
 | 
						|
    return Producer.keywords2consumer.copy()
 | 
						|
 | 
						|
def _setstate(state): 
 | 
						|
    Producer.keywords2consumer.clear()
 | 
						|
    Producer.keywords2consumer.update(state) 
 | 
						|
 | 
						|
def default_consumer(msg): 
 | 
						|
    """ the default consumer, prints the message to stdout (using 'print') """
 | 
						|
    print str(msg) 
 | 
						|
 | 
						|
Producer.keywords2consumer['default'] = default_consumer 
 |