How to force error reporting from django management commands?
Asked Answered
O

2

6

We are running custom management commands periodically on the server.

Is there any way to get something like error reporting via email working for the command?

Outwit answered 1/6, 2011 at 20:13 Comment(0)
B
5

You could use django logging handler AdminEmailHandler:

https://docs.djangoproject.com/en/dev/topics/logging/#django.utils.log.AdminEmailHandler

As the docs say:

This handler sends an email to the site admins for each log message it receives.

So you could use this to log an error on any exception raised in the management command, and the exception would be automatically send to the admins

Blende answered 1/6, 2011 at 20:28 Comment(0)
L
0

Let us say I have this simple management command in which I want to handle exception and send mail:

test_command.py

from django.core.management.base import BaseCommand


class Command(BaseCommand):

    def handle(self, *args, **options):
        x = 1 / 0
        print("x: ", x)

As you can see above command will generate division by zero exception we can handle this exception in the command itself but then what if we have many such commands we will have to repeat exception handling for each one by one. A better way is to handle the exception in manage.py as all commands are run through it like this:

manage.py

#!/usr/bin/env python
import os
import sys

from django.core.management import execute_from_command_line
from app_name.exception_reporter import AdminExceptionMailReporter

CRON_JOBS = ['test_command']


def execute_command(args):
    if args and len(args) >= 2 and args[1] in CRON_JOBS:
        try:
            execute_from_command_line(args)
        except Exception:
            command_name = args[1]
            # SENDING MAIL TO ADMIN INFORMING ABOUT THE EXCEPTION
            AdminExceptionMailReporter(sys.exc_info(),  command_name).send()
            raise
    else:
        execute_from_command_line(args)


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")

    execute_command(sys.argv)

Now let us define our AdminExceptionMailReporter:

exception_reporter.py

from django.core import mail
from django.views.debug import ExceptionReporter

DEFAULT_SUBJECT = "The '%s' cron job has failed with an exception."
DEFAULT_MESSAGE = "Please find the below reason for failure:"


class AdminExceptionMailReporter:

    def __init__(self, exception, command_name, subject=None, message=None):
        self.exception = exception
        self.command_name = command_name
        self.subject = subject
        self.message = message

    def set_subject(self, subject):
        self.subject = subject

    def set_message(self, message):
        self.message = message

    def _set_default_html(self):
        if self.subject is None:
            subject = DEFAULT_SUBJECT % self.command_name
            self.set_subject(subject)
        if self.message is None:
            self.set_message(DEFAULT_MESSAGE)

    def get_reporter(self, is_email=True):
        exception_class, exception_name, traceback = self.exception
        reporter = ExceptionReporter(
               None, exc_type=exception_class, 
               exc_value=exception_name, tb=traceback, 
               is_email=is_email
        )
        return reporter

    def send(self, fail_silently=False):
        self._set_default_html()
        mail.mail_admins(
            self.subject, self.message, fail_silently=fail_silently,
            html_message=self.get_reporter().get_traceback_html()
        )

Now the final step is to add AdminEmailHandler in logging and adding your mail name email tuple in ADMIN setting variable.

Lebbie answered 17/8, 2023 at 9:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.