如何限制 Django 错误邮件

Posted

技术标签:

【中文标题】如何限制 Django 错误邮件【英文标题】:How to throttle Django error emails 【发布时间】:2011-01-04 08:50:56 【问题描述】:

我通过电子邮件使用 django 错误报告。这通常是一个非常有用的功能,除了现在我们有 5 分钟的数据库停机时间并且我收到了 2000 封电子邮件。是否有任何中间件可以帮助我限制 django 每分钟可以发送的电子邮件数量?

【问题讨论】:

【参考方案1】:

以 Gattster 的优秀答案为例,我基于 django 的内置缓存函数编写了一个简单的实现。

# -*- coding: utf-8 -*-

from django.utils.log import AdminEmailHandler
from django.core.cache import cache


class ThrottledAdminEmailHandler(AdminEmailHandler):

    PERIOD_LENGTH_IN_SECONDS = 10
    MAX_EMAILS_IN_PERIOD = 1
    COUNTER_CACHE_KEY = "email_admins_counter"

    def increment_counter(self):
        try:
            cache.incr(self.COUNTER_CACHE_KEY)
        except ValueError:
            cache.set(self.COUNTER_CACHE_KEY, 1, self.PERIOD_LENGTH_IN_SECONDS)
        return cache.get(self.COUNTER_CACHE_KEY)

    def emit(self, record):
        try:
            counter = self.increment_counter()
        except Exception:
            pass
        else:
            if counter > self.MAX_EMAILS_IN_PERIOD:
                return
        super(ThrottledAdminEmailHandler, self).emit(record)

在 Django 1.9 中日志配置也发生了变化,所以为了让这个处理程序工作,你需要将日志配置为:

LOGGING = 
    'version': 1,
    'disable_existing_loggers': True,
    'handlers': 
        'mail_admins': 
            'level': 'ERROR',
            'class': 'fully.qualified.path.to.handler.ThrottledAdminEmailHandler'
        
    ,
    'loggers': 
        'django': 
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        ,
    

这里的更改只是将记录器的名称从django.request 更改为django。如果您查看日志系统文档,这可能会通过实现logging filter 以更简洁(?)的方式实现。

【讨论】:

不错。我喜欢这个不依赖redis连接,使用django的核心缓存框架 get_cache 现在已被删除(从 Django 1.9 开始)。改用from django.core.cache import cache——但跨多个线程或进程似乎存在问题......仍在处理...... Django 1.9 更改了默认日志配置,以便通过 django logger 和 not django.request logger 记录 Django 相关内容,如下所示。如果您要复制/粘贴@Gattster 提供的配置,请确保修复该问题。日志记录部分应如下所示:``` 'loggers': 'django': 'handlers': ['mail_admins'], 'level': 'ERROR', 'propagate': True, , ``` @sebhaase 随时更新答案以反映 django 的变化 @miha 随时更新答案以反映 django 的变化【参考方案2】:

也许Nagios' page关于拍打值得一读

【讨论】:

【参考方案3】:

我通过执行以下操作将电子邮件限制为每分钟 10 封。这使用了我的安装独有的 redis 连接功能。我建议修改 incr_counter 函数以满足您的需要。为了安全起见,为此使用直接 redis 或 memcache 连接,而不是任何 django.cache 包装器。

settings.py

LOGGING = 
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': 
        'mail_admins': 
            'level': 'ERROR',
            'class': 'error_email_limiter.handler.MyAdminEmailHandler'
        
    ,
    'loggers': 
        'django.request': 
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
            ,
        

error_email_limiter/handlers.py

class MyAdminEmailHandler(AdminEmailHandler):
    def incr_counter(self):
        c = get_redis_connection()
        key = self._redis_key()
        res = c.incr(key)
        c.expire(key, 300)
        return res

    def _redis_key(self):
        return time.strftime('error_email_limiter:%Y-%m-%d_%H:%M',
                             datetime.datetime.now().timetuple())

    def emit(self, record):
        try:
            ctr = self.incr_counter()
        except Exception:
            pass
        else:
            if ctr >= 10:
                return
        super(MyAdminEmailHandler, self).emit(record)

【讨论】:

【参考方案4】:

一种选择是切换到ErrorStack 之类的东西来报告错误。我写了一个django app 以使其集成到您的项目中变得非常简单。

【讨论】:

这听起来不错。您是否也评估了 hoptoad.com?我需要决定选择哪个服务。 不,我没有详细看过hoptoad。【参考方案5】:

我认为数据库停机不是故意的,在这种情况下,您可能应该将 Django 进程放入某种 maintenance mode 或使其脱机?

否则,通常的邮件应用程序是 django-mailer,它可能对您有所帮助,因为它将外发邮件存储在您的数据库中,因此会失败:)

如果您确实需要限制速率,最好在您的 MTA 中这样做。这可能意味着能够只关闭负责发送邮件的 MTA 进程部分或使用 this patch for qmail to throttle incoming connections as a means of fighting spam 等奇异的东西。

【讨论】:

以上是关于如何限制 Django 错误邮件的主要内容,如果未能解决你的问题,请参考以下文章

限制 Elmah 发送的电子邮件数量

将 django FloatField 限制为 2 位小数

Celeryd时间限制错误

django/celery - 芹菜状态:错误:在时间限制内没有节点回复

如何解决 excel vba 中的 Find(what:=) 字符限制

如何限制每秒 Web 请求以避免垃圾邮件和拒绝服务