LogPy

Unorthodox logging for Python
Download

LogPy Ranking & Summary

Advertisement

  • Rating:
  • License:
  • BSD License
  • Price:
  • FREE
  • Publisher Name:
  • Michal Hordecki
  • Publisher web site:
  • http://github.com/MHordecki

LogPy Tags


LogPy Description

Unorthodox logging for Python LogPy is an alternative for standard Python logging facilities, loosely based on Lisp's log5. It is based on KISS principles - therefore I wanted it to be as most transparent as possible.The main difference when compared to stdlib's logging is tag-based architecture. In logging, each log has assigned a certain level (be it debug, error, etc.). That's all. LogPy, on the other hand, sports tags - you can attach short strings to each message. Tag can represent variety of things: severity level, module name, or some custom log categorization.LogPy requires Python 2.6 or higher. It works seamlessly on Python 3 too (in fact, it's developed with py3k in mind and then backported to Python 2.6).Getting startedUsing LogPy is dead simple:from logpy import LogPyimport syslog = LogPy()log.add_output(sys.stderr.write)log('debug')('Hello World!')Voila! LogPy instances are callable. To output a log, call log "twice" - in first call pass all tags of the log, and everything passed to the second one will be considered a part of the message. The example will output logs to the standard error output. Easy, isn't it?Under the hoodLogPy has a few layers of abstraction: 1. LogPy - it accepts data from the user, combines them into a Message instance and passes them down to all outputs. 2. Output - it filters messages based on some predefined conditions, and if the message passes them all, it's formatted by the Formatter and then passed to the actual output. 3. Formatter - takes message and formats it ;) (in standard implementation it uses string.format for the job). 4. Actual output - a callable that, for example, outputs the Formatter's output to the screen.All those layers/objects are callables.Common tasksOutput filteringWith multiple outputs, you probably want to filter out some logs in each of them. There is support for that:log = LogPy()log.add_output(my_output, filter = lambda m: 'error' in m.tags)# Equivalent to:log.add_output(my_output, filter = )As you can see, filters are callables, taking Message object as an argument and returning bool. Multiple filters can be provided by a list.Custom formattingYou can customize formatting by either replacing the format string or by replacing the Formatting object altogether. Your choice.Custom format stringThis one will meet 90% of your needs. You can change your format string with keyword argument to the add_output method of LogPy (also possible when directly instantiating Output objects):log.add_output(..., formatter = 'my custom format string!')When processing a message, method format of the string will be called with following, predefined arguments: * date - datetime object * tags - space-delimited list of tags (string) * args - list of arguments in the message * kwargs - dict of keyword arguments in the message * message - the actual message object. All arguments above are actually just a syntactic sugar, as they are all attributes of this object.Default format string looks like this: {date} : {tags} : {args} {kwargs}\nDon't forget to put a newline at the ending, or your logs will look crippled.Working with multiple modulesYou can help yourself while using LogPy with multiple modules by predefining some of the tags:# Main modulelog = LogPy()# Child moduleimport mainmodulelog = mainmodule.log('module:childmodule', curry = True)# Now:log('debug')('Hello World!')# is equivalent tolog('module:childmodule', 'debug')('Hello World')Custom format objectIn case you want the full power - you can get rid of the default formatter:log.add_output(..., formatter = my_formatter_object)Formatter objects must comply to the simple protocol:class Formatter: def __call__(message: Message) -> Someting reasonable: passclass Message: tags = set(str) args = [] # passed by the user kwargs = {} # passed by the user date = datetime.datetime(I have no idea whatsoever if there's standard formal notation for describing protocols in Python besides things like zope.interface. I hope my ramblings are clear.)Where something reasonable means: everything that will be accepted by the output of the Output (sounds kinda silly) - it usually means str, but not always.Custom Output objectIf you're willing to scrap 50% of the LOC of LogPy, feel free to do so:log.add_raw_output(my_customized_output_object)Worth mentioning is the fact that LogPy.add_output is just a wrapper for:log.add_output(...)# Equivalent tolog.add_raw_output(Output(...))Output protocol looks as follows:class Output: def __call__(message: Message): passIn other words: you will be called with every log issued by the user.Note: Please, treat messages as immutable objects - they are being reused for all Outputs.Thread safetyLogPy employs some basic thread safety; a threading.Lock is used in __call__ method of LogPy. It can be easily replaced:from threading import RLocklog = LogPy()log.lock = RLock() Requirements: · Python


LogPy Related Software