utils.logger - Logger Components

Convenience stuff for logging.

Main component of waeup.kofa.utils.logging is a mix-in class waeup.kofa.utils.logging.Logger. Classes derived (also) from that mix-in provide a logger attribute that returns a regular Python logger logging to a rotating log file stored in the datacenter storage path.

Deriving components (classes) should set their own logger_name and logger_filename attribute.

The logger_name tells under which name the logger should be registered Python-wise. This is usually a dotted name string like waeup.kofa.${sitename}.mycomponent which should be unique. If you pick a name already used by another component, trouble is ahead. The ${sitename} chunk of the name can be set literally like this. The logger machinery will turn it into some real site name at time of logging.

The logger_filename attribute tells how the logfile should be named. This should be some base filename like mycomponent.log. Please note, that some logfile names are already used: main.log, applications.log, and datacenter.log.

The Logger mix-in also cares for updating the logging handlers when a datacenter location moves. That means you do not have to write your own event handlers for the purpose. Just derive from Logger, set your logger_name and logger_filename attribute and off you go:

from waeup.kofa.utils.logger import Logger

class MyComponent(object, Logger):
    # Yes that's a complete working class
    logger_name = 'waeup.kofa.${sitename}.mycomponent
    logger_filename = 'mycomponent.log'

    def do_something(self):
         # demomstrate how to use logging from methods
         self.logger.info('About to do something')
         try:
             # Do something here
         except IOError:
             self.logger.warn('Something went wrong')
             return
         self.logger.info('I did it')

As you can see from that example, methods of the class can log messages simply by calling self.logger.

The datacenter and its storage are created automatically when you create a waeup.kofa.app.University. This also means that logging with the Logger mix-in will work only inside so-called sites (University instances put into ZODB are such sites).

Other components in this module help to make everything work.

class waeup.kofa.utils.logger.ContextFilter(name='')[source]

Bases: logging.Filter

This is a filter which injects contextual information into the log.

__doc__ = '\n This is a filter which injects contextual information into the log.\n\n '
__module__ = 'waeup.kofa.utils.logger'
filter(record)[source]
interface waeup.kofa.utils.logger.ILogger[source]
logger_filename

A filename for the log file to use (basename)

logger_setup(logger)

Setup a logger.

logger is an instance of logging.Logger.

logger_get_logfile_path()

Get path to logfile used.

Return None if the file path cannot be computed.

logger_get_logdir()

Get the directory of the logfile.

Return None if the directory path cannot be computed.

logger_name

A Python logger name

logger

Get a Python logger instance already set up

waeup.kofa.utils.logger.LEVEL = 20

Default logging level (logging.INFO)

class waeup.kofa.utils.logger.Logger[source]

Bases: object

Mixin-class that for logging support.

Classes that (also) inherit from this class provide support for logging with waeup sites.

By default a logger attribute is provided which returns a regular Python logger. This logger has already registered a file rotating log handler that writes log messages to a file main.log in datacenters log/ directory. This is the main log file also used by other components. Therefore you can pick another filename by setting the logger_filename attribute.

All methods and attributes of this mix-in start with logger_ in order not to interfere with already existing names of a class.

Method names do not follow the usual Zope habit (CamelCase) but PEP8 convention (lower_case_with_underscores).

__dict__ = dict_proxy({'__providedBy__': <_interface_coptimizations.ObjectSpecificationDescriptor object at 0x7f402dea22c0>, '__module__': 'waeup.kofa.utils.logger', 'logger_filename': 'main.log', '__provides__': <zope.interface.declarations.ClassProvides object at 0x7f402803bc50>, 'logger_setup': <function logger_setup at 0x7f4028042e60>, 'logger_get_logfile_path': <function logger_get_logfile_path at 0x7f4028042ed8>, 'logger_get_logdir': <function logger_get_logdir at 0x7f4028042f50>, 'logger_format_str': '%(asctime)s - %(levelname)s - %(user)s - %(message)s', 'logger_shutdown': <function logger_shutdown at 0x7f40280430c8>, 'logger_name': 'waeup.kofa.${sitename}', '__dict__': <attribute '__dict__' of 'Logger' objects>, 'logger': <property object at 0x7f40282b5fc8>, '__implemented__': <implementedBy waeup.kofa.utils.logger.Logger>, '__weakref__': <attribute '__weakref__' of 'Logger' objects>, '__doc__': 'Mixin-class that for logging support.\n\n Classes that (also) inherit from this class provide support for\n logging with waeup sites.\n\n By default a `logger` attribute is provided which returns a\n regular Python logger. This logger has already registered a file\n rotating log handler that writes log messages to a file `main.log`\n in datacenters ``log/`` directory. This is the main log file also\n used by other components. Therefore you can pick another filename\n by setting the `logger_filename` attribute.\n\n All methods and attributes of this mix-in start with ``logger_``\n in order not to interfere with already existing names of a class.\n\n Method names do not follow the usual Zope habit (CamelCase) but\n PEP8 convention (lower_case_with_underscores).\n ', 'logger_logfile_changed': <function logger_logfile_changed at 0x7f4028043050>})
__doc__ = 'Mixin-class that for logging support.\n\n Classes that (also) inherit from this class provide support for\n logging with waeup sites.\n\n By default a `logger` attribute is provided which returns a\n regular Python logger. This logger has already registered a file\n rotating log handler that writes log messages to a file `main.log`\n in datacenters ``log/`` directory. This is the main log file also\n used by other components. Therefore you can pick another filename\n by setting the `logger_filename` attribute.\n\n All methods and attributes of this mix-in start with ``logger_``\n in order not to interfere with already existing names of a class.\n\n Method names do not follow the usual Zope habit (CamelCase) but\n PEP8 convention (lower_case_with_underscores).\n '
__implemented__ = <implementedBy waeup.kofa.utils.logger.Logger>
__module__ = 'waeup.kofa.utils.logger'
__providedBy__

Special descriptor for class __provides__

The descriptor caches the implementedBy info, so that we can get declarations for objects without instance-specific interfaces a bit quicker.

For example:

>>> from zope.interface import Interface
>>> class IFooFactory(Interface):
...     pass
>>> class IFoo(Interface):
...     pass
>>> class C(object):
...     implements(IFoo)
...     classProvides(IFooFactory)
>>> [i.getName() for i in C.__provides__]
['IFooFactory']
>>> [i.getName() for i in C().__provides__]
['IFoo']
__provides__

Special descriptor for class __provides__

The descriptor caches the implementedBy info, so that we can get declarations for objects without instance-specific interfaces a bit quicker.

For example:

>>> from zope.interface import Interface
>>> class IFooFactory(Interface):
...     pass
>>> class IFoo(Interface):
...     pass
>>> class C(object):
...     implements(IFoo)
...     classProvides(IFooFactory)
>>> [i.getName() for i in C.__provides__]
['IFooFactory']
>>> [i.getName() for i in C().__provides__]
['IFoo']
__weakref__

list of weak references to the object (if defined)

logger

Get a logger instance.

Returns a standard logger object as provided by logging module from the standard library.

Other components can use this logger to perform log entries into the logfile of this component.

The logger is initialized the first time it is called.

The logger is only available when used inside a site.

Note

The logger default level is logging.WARN. Use logging.Logger.setLevel() to set a different level.

logger_filename = 'main.log'

The filename to use when logging.

logger_format_str = '%(asctime)s - %(levelname)s - %(user)s - %(message)s'

The format to use when logging.

logger_get_logdir()[source]

Get log dir where logfile should be put.

Returns the path to the logfile directory. If no site is set, None is returned. The same applies, if the site has no datacenter.

If the dir dies not exist already it will be created. Only the last part of the directory path will be created.

logger_get_logfile_path()[source]

Get the path to the logfile used.

Returns the path to a file in local sites datacenter log/ directory (dependent on logger_get_logdir()) and with logger_filename as basename.

Override this method if you want a complete different computation of the logfile path. If you only want a different logfile name, set logger_filename. If you only want a different path to the logfile override logger_get_logdir() instead.

Returns None if no logdir can be fetched.

Note

creates the logfile dir if it does not exist.

logger_logfile_changed()[source]

React on logfile location change.

If the logfile changed, we can set a different logfile. While changing the logfile is a rather critical operation you might not do often in production use, we have to cope with that especially in tests.

What this method does by default (unless you override it):

  • It fetches the current logger and
    • Removes flushes, closes, and removes all handlers
    • Sets up new handler(s).

All this, of course, requires to be ‘in a site’.

Use this method to handle moves of datacenters, for instance by writing an appropriate event handler.

logger_name = 'waeup.kofa.${sitename}'

The Python logger name used when logging. 'waeup.kofa.${sitename}' by default. You can use the ${sitename} placeholder in that string, which will be replaced by the actual used site name.

logger_setup(logger)[source]

Setup logger.

The logfile will be stored in the datacenter logs/ dir.

logger_shutdown()[source]

Remove all specific logger setup.

class waeup.kofa.utils.logger.LoggerCollector[source]

Bases: dict, grokcore.component.components.GlobalUtility

A global utility providing ILoggerCollector.

A logging collector collects logging components. This helps to inform them when a logfile location changes.

Logging components are registered per site they belong to.

__dict__ = dict_proxy({'getLoggers': <function getLoggers at 0x7f4028043230>, '__module__': 'waeup.kofa.utils.logger', '__provides__': <zope.interface.declarations.ClassProvides object at 0x7f402803bd50>, 'registerLogger': <function registerLogger at 0x7f40280432a8>, '__dict__': <attribute '__dict__' of 'LoggerCollector' objects>, '__implemented__': <implementedBy waeup.kofa.utils.logger.LoggerCollector>, '__weakref__': <attribute '__weakref__' of 'LoggerCollector' objects>, '__doc__': 'A global utility providing `ILoggerCollector`.\n\n A logging collector collects logging components. This helps to\n inform them when a logfile location changes.\n\n Logging components are registered per site they belong to.\n ', 'unregisterLogger': <function unregisterLogger at 0x7f4028043320>})
__doc__ = 'A global utility providing `ILoggerCollector`.\n\n A logging collector collects logging components. This helps to\n inform them when a logfile location changes.\n\n Logging components are registered per site they belong to.\n '
__implemented__ = <implementedBy waeup.kofa.utils.logger.LoggerCollector>
__module__ = 'waeup.kofa.utils.logger'
__provides__

Special descriptor for class __provides__

The descriptor caches the implementedBy info, so that we can get declarations for objects without instance-specific interfaces a bit quicker.

For example:

>>> from zope.interface import Interface
>>> class IFooFactory(Interface):
...     pass
>>> class IFoo(Interface):
...     pass
>>> class C(object):
...     implements(IFoo)
...     classProvides(IFooFactory)
>>> [i.getName() for i in C.__provides__]
['IFooFactory']
>>> [i.getName() for i in C().__provides__]
['IFoo']
__weakref__

list of weak references to the object (if defined)

getLoggers(site)[source]
registerLogger(site, logging_component)[source]
unregisterLogger(site, logging_component)[source]
waeup.kofa.utils.logger.handle_datacenter_storage_moved(obj, event)[source]

Event handler, in case datacenter storage moves.

By default all our logfiles (yes, we produce a whole bunch of it) are located in a log/ dir of a local datacenter, the datacenter ‘storage’. If this path changes because the datacenter is moved an appropriate event is triggered and we can react.

Via the global ILoggerCollector utility, a small piece that allows self-registering of logging components, we can lookup components whose logfile path has to be set up anew.

Each component we call has to provide ILogger or, more specific, the logger_logfile_changed() method of this interface.

waeup.kofa.utils.logger.handle_site_removed(obj, event)[source]