Nonblocking Log Handler
-----------------------

Provides a NonblockingLogHandler class consistent with the Python logging subsystem.

This handler acts as a proxy for the another log handler that may be slow to execute: e.g. the SMTPHandler, SocketHandler,
SysLogHandler - especially when they are talking to remote servers.

If you have a real-time system (i.e. one where a late response is a wrong response) and you are sending log messages via email,
http, syslog, etc., you should consider using this module to protect against unexpected delays.

It is intended to be a drop-in replacement (see provisos below) for the proxied handler which returns quickly, and executes
the actually logging in the background, in a separate thread.

Provisos:

* If you pass an objects to the logging functions, be aware that their __str__() functions should be fast. I/O bound str()
  calls are outside the scope of this module.

  Execution of str() functions on message parameters and string formatting is done immediately, in the calling thread. This is
  to guarantee both thread-safety of the logged objects and also that the log shows the object's values at the time of the call,
  not the time of the emit.

* If you subclass from Formatter, note that it will not have the user parameters from the logging call passed to it. It
  will only receive the resulting message string formatted according to the client's wishes. It can still format dates,
  threadnames, levels, etc.

* If you subclass from Filter, be aware that they should be fast. I/O-bound filters are outside of the scope of this module.

* Clients should not directly call format() or emit() on the NonblockingLogHandler class. Consider them private.

* Once the NonblockingLogHandler handler is initialised, any further calls to setLevel(), addFilter and removeFilter() made on
  the delegated handler are ignored by the proxy handler. Conversely, the delegated handler is not informed of calls made on
  the NonblockingLogHandler instance. proxy handler.
  
  Best practice would be to only update the NonblockingLogHandler handler, and not use the values stored in the delegated
  handler.
  
  
Example usage:
  nonblocking_email_handler = nonblockingloghandler.NonblockingLogHandler(
      logging.SMTPHandler("localhost", "logging_system@example.com", "admin@example.com", "Log message")
      )
  db_logger = logging.getLogger("database")
  db_logger.addHandler(nonblocking_email_handler)
  
  db_logger.critical("Database corrupted") # This operation will return immediately, before email is sent.

  nonblocking_email_handler.close()

