comment 0

Django + Celery – Send email to admin when error occurs

In this case, I have a Django project which using celery to handle asynchronous task queue/job queue. Since we must not set DEBUG on production side, to notice admin whenever error occurs is send an email with traceback info.

There are some steps to set up email admin notification due to error occurs. First, we need to setup mail configuration in our settings.

# settings.py
import os
import configparser

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))

CONFIG = configparser.ConfigParser()

CONFIG.read("%s/development.cfg" % (PROJECT_DIR))

# mail admin conf.
ADMINS = (
    # ("name", "email"),
    # ("name", "email"),
)

EMAIL_HOST = CONFIG["email"]["EMAIL_HOST"]

EMAIL_HOST_USER = CONFIG["email"]["EMAIL_HOST_USER"]

DEFAULT_FROM_EMAIL = CONFIG["email"]["EMAIL_HOST_USER"]

EMAIL_HOST_PASSWORD = CONFIG["email"]["EMAIL_HOST_PASSWORD"]

EMAIL_PORT = CONFIG.getint("email", "EMAIL_PORT")

EMAIL_USE_TLS = CONFIG.getboolean("email", "EMAIL_USE_TLS")

# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error when DEBUG=False.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {
        "require_debug_false": {"()": "django.utils.log.RequireDebugFalse"},
        "require_debug_true": {"()": "django.utils.log.RequireDebugTrue"},
    },
    "handlers": {
        "console": {
            "level": "DEBUG",
            "class": "logging.StreamHandler",
            "filters": ["require_debug_true"],
        },
        "mail_admins": {
            "level": "ERROR",
            "filters": ["require_debug_false"],
            "class": "django.utils.log.AdminEmailHandler",
            "include_html": True,
        },
    },
    "loggers": {
        "django.request": {
            "handlers": ["mail_admins"],
            "level": "ERROR",
            "propagate": True,
        },
        "debugmsg": {"handlers": ["console"], "level": "DEBUG", "propagate": False},
    },
}

I also created development.cfg to store my configuration.

[email]
EMAIL_HOST_USER: yourmail@gmail.com
EMAIL_HOST: smtp.gmail.com
EMAIL_HOST_PASSWORD: password
EMAIL_PORT: 587
EMAIL_USE_TLS: True

in this case, I am using google smtp, you can set up with your own.

and then in your task.py, you can use celery signal ( http://docs.celeryproject.org/en/latest/userguide/signals.html#task-failure ) and send email

# task.py
from celery.signals import task_failure

@task_failure.connect()
def celery_task_failure_email(**kwargs):
    from django.core.mail import mail_admins
    import socket

    """ celery 4.0 onward has no method to send emails on failed tasks
    so this event handler is intended to replace it
    """

    subject = "[Django][{queue_name}@{host}] Error: Task {sender.name} ({task_id}): {exception}".format(
        queue_name="celery",  # `sender.queue` doesn't exist in 4.1?
        host=socket.gethostname(),
        **kwargs
    )

    message = """Task {sender.name} with id {task_id} raised exception:
{exception!r}

Task was called with args: {args} kwargs: {kwargs}.

The contents of the full traceback was:

{einfo}
    """.format(
        **kwargs
    )

    mail_admins(subject, message)

Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *


 

This site uses Akismet to reduce spam. Learn how your comment data is processed.