Logging and Errors

Logging and error-handling are built in and ready when you are.

Logging

Edmunds comes with logging built in. You can activate it in your settings:

from edmunds.log.drivers.file import File
from edmunds.log.drivers.stream import Stream
from edmunds.log.drivers.syslog import SysLog
from edmunds.log.drivers.timedfile import TimedFile
from edmunds.log.drivers.googleappengine import GoogleAppEngine
from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT
from logging import WARNING
from socket import SOCK_DGRAM
import sys

APP = {
    'logging':
    {
        'enabled': True,
        'instances':
        [
            {
                'name': 'file',
                'driver': File,
                # 'directory': 'logs',      # Optional, default: 'logs'
                # 'prefix': 'Myapp.',       # Optional, default: ''
                # 'max_bytes': 0,           # Optional, default: 0
                # 'backup_count': 0,        # Optional, default: 0
                # 'level': WARNING,         # Optional, default: WARNING
                # 'format': '%(message)s',  # Optional, default: '[%(asctime)s] %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
            },
            {
                'name': 'timedfile',
                'driver': TimedFile,
                # 'directory': 'logs',                  # Optional, default: 'logs'
                # 'prefix': 'Myapp.',                   # Optional, default: ''
                # 'when': 'H',                          # Optional, default: 'D'
                # 'interval': 12,                       # Optional, default: 1
                # 'backup_count': 0,                    # Optional, default: 0
                # 'level': WARNING,                     # Optional, default: WARNING
                # 'format': '%(message)s',              # Optional, default: '[%(asctime)s] %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
            },
            {
                'name': 'syslog',
                'driver': SysLog,
                # 'address': '/dev/log',                # Optional, default: ('localhost', SYSLOG_UDP_PORT)
                # 'facility': SysLogHandler.LOG_USER,   # Optional, default: SysLogHandler.LOG_USER
                # 'socktype': SOCK_DGRAM,               # Optional, default: SOCK_DGRAM
                # 'level': WARNING,                     # Optional, default: WARNING
                # 'format': '%(message)s',              # Optional, default: '[%(asctime)s] %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
            },
            {
                'name': 'stream',
                'driver': Stream,
                # 'stream': sys.stderr,                 # Optional, default: sys.stderr
                # 'level': WARNING,                     # Optional, default: WARNING
                # 'format': '%(message)s',              # Optional, default: '[%(asctime)s] %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
            },
            {
                'name': 'googleappengine',
                'driver': GoogleAppEngine,
                # 'level': WARNING,                     # Optional, default: WARNING
            },
        ],
    },
}

The instances will all be used for logging, so you can have multiple at once.

The available drivers are:

  • File: Print logs to file which can be separated by size.
  • TimedFile: Print logs to file which can be separated by time-interval.
  • SysLog: Print logs to syslog.
  • Stream: Pring logs to given stream.
  • GoogleAppEngine: Pring logs to the Google App Engine stream when running in Google App Engine runtime.

Errors

Even the best programming logic and tests can't always foresee every possible scenario where errors can occure. You can report and render these exceptions by registering your own exception-handler.

If logging is enabled, errors that pass through the handler will automatically be logged to your provider logging-services.

Define

Define your Handler like so:

from edmunds.exceptions.handler import Handler as EdmundsHandler

class Handler(EdmundsHandler):
    """
    Exception handler
    """

    def report(self, exception):
        """
        Report the exception
        :param exception:   The exception
        :type  exception:   Exception
        """
        if super(Handler, self).report(exception):
            # Additional reporting
            pass

    def render(self, exception):
        """
        Render the exception
        :param exception:   The exception
        :type  exception:   Exception
        :return:            The response
        """
        return super(Handler, self).render(exception)

Important!: The report-function of the edmunds-super-class will log the error to self.app.logger. You defined loggers will by default pick up caught exceptions as described above.

Register

Register the Handler for usage in config/app.py:

from app.exceptions.handler import Handler

APP = {
    'exceptions':
    {
        'handler': Handler,
    },
}

This way the application knows to use your handler in case of an exception.