You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何限制Django与Celery日志量,保留错误日志并限制每秒日志条数?

方案结论

你提出的日志规则完全可落地,无需侵入业务代码,通过Python标准日志库的自定义过滤器即可实现「ERROR及以上级别错误日志全量留存、INFO/DEBUG等非错误日志每秒最多存储5条」的效果,同时覆盖Django请求访问日志、Celery任务执行日志两类冗余日志场景。

第一步:实现自定义限流过滤器

Python logging原生支持过滤器扩展,我们只需要写一个通用过滤器,对错误级别日志直接放行,非错误日志按1秒时间窗口做计数限流即可。
在你的项目代码目录下新建utils/log_filters.py文件,写入以下代码:

import logging
import time
from collections import deque

class RateLimitFilter(logging.Filter):
    def __init__(self, max_per_second=5):
        super().__init__()
        self.max_per_second = max_per_second
        self.log_timestamps = deque()
        # ERROR及以上级别为错误日志,直接放行
        self.error_threshold = logging.ERROR

    def filter(self, record):
        if record.levelno >= self.error_threshold:
            return True
        # 非错误日志走滑动窗口限流
        now = time.time()
        # 清理1秒窗口外的过期时间戳
        while self.log_timestamps and self.log_timestamps[0] < now - 1:
            self.log_timestamps.popleft()
        # 未到阈值则放行,记录当前时间戳
        if len(self.log_timestamps) < self.max_per_second:
            self.log_timestamps.append(now)
            return True
        # 超过阈值直接丢弃日志
        return False
第二步:配置Django侧日志规则

修改Django项目的settings.py文件,调整LOGGING配置,将限流过滤器绑定到日志输出处理器上,覆盖所有Django相关日志(包括你看到的POST格式访问请求日志):

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "filters": {
        "rate_limit": {
            "()": "backend.utils.log_filters.RateLimitFilter",
            "max_per_second": 5,
        }
    },
    "formatters": {
        "standard": {
            "format": "%(levelname)s %(asctime)s %(module)s %(message)s"
        },
    },
    "handlers": {
        "app_log": {
            "level": "INFO",
            "class": "logging.handlers.RotatingFileHandler",
            "filename": "/var/log/app/django.log",
            "formatter": "standard",
            "filters": ["rate_limit"],
            "maxBytes": 1024*1024*100,
            "backupCount": 10,
        },
    },
    "loggers": {
        "django": {
            "handlers": ["app_log"],
            "level": "INFO",
            "propagate": True,
        },
        # 单独绑定请求访问日志对应的logger
        "django.request": {
            "handlers": ["app_log"],
            "level": "INFO",
            "propagate": False,
        }
    },
}

如果你用Gunicorn、uWSGI等Web服务器托管Django,需要给Web服务器的访问日志处理器也加上同一个限流过滤器,不然服务器层面输出的access log不会被限流。

第三步:配置Celery侧日志规则

Celery默认复用Python标准日志体系,直接在Celery初始化文件(一般是项目根目录的celery.py)中,给Celery相关logger绑定同一个限流过滤器即可,覆盖你看到的任务接收、任务执行成功类日志:

import logging
from logging.handlers import RotatingFileHandler
from celery import Celery
from .utils.log_filters import RateLimitFilter

app = Celery("backend")
app.config_from_object("django.conf:settings", namespace="CELERY")
app.autodiscover_tasks()

@app.on_after_configure.connect
def setup_celery_logging(**kwargs):
    celery_logger = logging.getLogger("celery")
    log_handler = RotatingFileHandler(
        "/var/log/app/celery.log",
        maxBytes=1024*1024*100,
        backupCount=10
    )
    log_handler.setFormatter(logging.Formatter("%(levelname)s:%(name)s:%(message)s"))
    log_handler.addFilter(RateLimitFilter(max_per_second=5))
    celery_logger.addHandler(log_handler)
    celery_logger.setLevel(logging.INFO)
配置注意事项
  • 上述实现是单进程维度限流:如果你启动了多个Django服务进程、多个Celery worker进程,每个进程会独立按照每秒5条的阈值输出非错误日志,总日志量会随进程数同步上升。如果需要全局精准限流,把过滤器内的时间窗口计数逻辑替换为Redis共享计数即可,绝大多数场景下单进程限流已经能压减99%以上的冗余日志。
  • 配置完成后可以做简单验证:循环打印100条INFO级别日志+20条ERROR级别日志,检查输出结果是否符合「INFO日志每秒仅保留5条、ERROR日志全部留存」的规则。
  • 如果你已经接入了第三方日志采集服务,也可以不在应用层做限流,直接在日志采集规则侧配置采样策略:ERROR级别全量采集,INFO/DEBUG级别按每秒5条的阈值采样,效果完全一致,还不用修改应用代码。

内容的提问来源于stack exchange,提问作者sinys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 22:06:51