From f7b3f4573d590fd4bdb0c9f9bed5aa069cc96108 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Mon, 7 Dec 2020 18:06:34 +0000 Subject: [PATCH] Add celery task maillogging --- app/__init__.py | 6 +-- app/maillogger.py | 57 ++++++++----------------- app/tasks/__init__.py | 37 ++++++++++++---- app/templates/packages/screenshots.html | 2 +- 4 files changed, 51 insertions(+), 51 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 14eb1bd..89aa1fa 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -57,8 +57,8 @@ sass(app) if not app.debug and app.config["MAIL_UTILS_ERROR_SEND_TO"]: - from .maillogger import register_mail_error_handler - register_mail_error_handler(app, mail) + from .maillogger import build_handler + app.logger.addHandler(build_handler(app)) from .markdown import init_app @@ -68,7 +68,7 @@ init_app(app) # def get_locale(): # return request.accept_languages.best_match(app.config['LANGUAGES'].keys()) -from . import models, tasks, template_filters +from . import models, template_filters @login_manager.user_loader def load_user(user_id): diff --git a/app/maillogger.py b/app/maillogger.py index 23c4587..3b20949 100644 --- a/app/maillogger.py +++ b/app/maillogger.py @@ -36,10 +36,9 @@ class FlaskMailTextFormatter(logging.Formatter): pass class FlaskMailHTMLFormatter(logging.Formatter): - pre_template = "

%s

%s
" def formatException(self, exc_info): formatted_exception = logging.Handler.formatException(self, exc_info) - return FlaskMailHTMLFormatter.pre_template % ("Exception information", formatted_exception) + return "
%s
" % formatted_exception def formatStack(self, stack_info): return "
%s
" % stack_info @@ -47,66 +46,46 @@ class FlaskMailHTMLFormatter(logging.Formatter): # see: https://github.com/python/cpython/blob/3.6/Lib/logging/__init__.py (class Handler) class FlaskMailHandler(logging.Handler): - def __init__(self, mailer, subject_template, level=logging.NOTSET): + def __init__(self, send_to, subject_template, level=logging.NOTSET): logging.Handler.__init__(self, level) - self.mailer = mailer - self.send_to = mailer.app.config["MAIL_UTILS_ERROR_SEND_TO"] + self.send_to = send_to self.subject_template = subject_template - self.html_formatter = None - def setFormatter(self, text_fmt, html_fmt=None): + def setFormatter(self, text_fmt): """ Set the formatters for this handler. Provide at least one formatter. When no text_fmt is provided, no text-part is created for the email body. """ - assert (text_fmt, html_fmt) != (None, None), "At least one formatter should be provided" + assert text_fmt != None, "At least one formatter should be provided" if type(text_fmt)==str: text_fmt = FlaskMailTextFormatter(text_fmt) self.formatter = text_fmt - if type(html_fmt)==str: - html_fmt = FlaskMailHTMLFormatter(html_fmt) - self.html_formatter = html_fmt def getSubject(self, record): fmt = FlaskMailSubjectFormatter(self.subject_template) subject = fmt.format(record) - #Since templates can cause header problems, and we rather have a incomplete email then an error, we fix this + # Since templates can cause header problems, and we rather have a incomplete email then an error, we fix this if _is_bad_subject(subject): - subject="FlaskMailHandler log-entry from %s [original subject is replaced, because it would result in a bad header]" % self.mailer.app.name + subject="FlaskMailHandler log-entry from ContentDB [original subject is replaced, because it would result in a bad header]" return subject def emit(self, record): - record.stack_info = record.exc_text - record.exc_text = None - record.exc_info = None - text = self.format(record) if self.formatter else None - html = self.html_formatter.format(record) if self.html_formatter else None + html = "
{}
".format(text) for email in self.send_to: send_user_email.delay(email, self.getSubject(record), text, html) -def register_mail_error_handler(app, mailer): +def build_handler(app): subject_template = "ContentDB %(message)s (%(module)s > %(funcName)s)" - text_template = """ -Message type: %(levelname)s -Location: %(pathname)s:%(lineno)d -Module: %(module)s -Function: %(funcName)s -Time: %(asctime)s -Message: -%(message)s""" - html_template = """ - - - - - - -
Message type:%(levelname)s
Location:%(pathname)s:%(lineno)d
Module:%(module)s
Function:%(funcName)s
Time:%(asctime)s
-

%(message)s

""" + text_template = ("Message type: %(levelname)s\n" + "Location: %(pathname)s:%(lineno)d\n" + "Module: %(module)s\n" + "Function: %(funcName)s\n" + "Time: %(asctime)s\n" + "Message: %(message)s\n\n") - mail_handler = FlaskMailHandler(mailer, subject_template) + mail_handler = FlaskMailHandler(app.config["MAIL_UTILS_ERROR_SEND_TO"], subject_template) mail_handler.setLevel(logging.ERROR) - mail_handler.setFormatter(text_template, html_template) - app.logger.addHandler(mail_handler) + mail_handler.setFormatter(text_template) + return mail_handler diff --git a/app/tasks/__init__.py b/app/tasks/__init__.py index 4cd0048..17409fb 100644 --- a/app/tasks/__init__.py +++ b/app/tasks/__init__.py @@ -13,12 +13,13 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . - +from logging import Filter import flask -from celery import Celery +from celery import Celery, signals from celery.schedules import crontab -from app.models import * +from app import app + class TaskError(Exception): def __init__(self, value): @@ -35,18 +36,18 @@ class FlaskCelery(Celery): self.init_app(kwargs['app']) def patch_task(self): - TaskBase = self.Task + BaseTask : celery.Task = self.Task _celery = self - class ContextTask(TaskBase): + class ContextTask(BaseTask): abstract = True def __call__(self, *args, **kwargs): if flask.has_app_context(): - return TaskBase.__call__(self, *args, **kwargs) + return super(BaseTask, self).__call__(*args, **kwargs) else: with _celery.app.app_context(): - return TaskBase.__call__(self, *args, **kwargs) + return super(BaseTask, self).__call__(*args, **kwargs) self.Task = ContextTask @@ -83,4 +84,24 @@ CELERYBEAT_SCHEDULE = { } celery.conf.beat_schedule = CELERYBEAT_SCHEDULE -from . import importtasks, forumtasks, emails, pkgtasks +from . import importtasks, forumtasks, emails, pkgtasks, celery + + +# noinspection PyUnusedLocal +@signals.after_setup_logger.connect +def on_after_setup_logger(**kwargs): + from app.maillogger import build_handler + + class ExceptionFilter(Filter): + def filter(self, record): + if record.exc_info: + exc, _, _ = record.exc_info + if exc == TaskError: + return False + + return True + + logger = celery.log.get_default_logger() + handler = build_handler(app) + handler.addFilter(ExceptionFilter()) + logger.addHandler(handler) diff --git a/app/templates/packages/screenshots.html b/app/templates/packages/screenshots.html index ad403b9..f3fa164 100644 --- a/app/templates/packages/screenshots.html +++ b/app/templates/packages/screenshots.html @@ -66,7 +66,7 @@ {% endblock %} {% block scriptextra %} - +