Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Django exception middleware for exception not in a view

Whenever an exception is caught in my django app, I'd like to use a custom middleware class to process the exception and send an email.

import logging
from django.core.mail import send_mail


class ErrorMiddleware(object):
    logger = logging.getLogger(__name__)

    def process_exception(self, request, exception):
        self.logger.debug("Middleware has caught an exception. exception={}".format(exception.message))

        # send_mail("Your Subject", "This is a simple text email body.",
        #           "Yamil Asusta <[email protected]>", ["[email protected]"])

    return None

I've added the middleware to my settings file,

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'django.middleware.security.SecurityMiddleware',

    # custom middleware
    'buildconfig.middleware.ErrorMiddleware.ErrorMiddleware',
)

And written the following test case to test the that the middleware processes my exception...

from django.test import TestCase
from mock import patch
from mock import Mock

class TestErrorMiddleware(TestCase):

    def test_process_exception_catches_exceptions(self):
        raise Exception

However, when I run my test through manage.py, I don't see my log message showing up in my log.

What am I missing?

like image 897
jsuzuki Avatar asked Oct 21 '25 08:10

jsuzuki


1 Answers

Every Middleware is initialised once the web server starts. but for that to happen you need an __init__() in the middleware.

def __init__(self, get_response):
  self.get_response = get_response

After the Middleware gets initialised, it needs to have a __call__() method which gets called on every request from the client. It is this method that is responsible for passing the controller over to the underlying middleware or calling the actual view after the last layer i.e. the view middleware.

def __call__(self, request):
    # Code to be executed for each request before
    # the view (and later middleware) are called.

    response = self.get_response(request)

    # Code to be executed for each request/response after
    # the view is called.

    return response

You need to return an HTTPResponse() from the process_exception() that will be to the middleware's __call__() in the response variable in the above code before passing it to the middleware above it on the way out.

Since you don't have the __init__() and the __call__() in your middleware class, your middleware is not getting initialised and thus handling each request as its passing to and fro the middleware layer.

Reference: https://docs.djangoproject.com/en/2.0/topics/http/middleware/#init-get-response

like image 184
cdx530 Avatar answered Oct 23 '25 23:10

cdx530



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!