diff --git a/app/__init__.py b/app/__init__.py index 3820a3f9..95134d08 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -30,6 +30,28 @@ from flask_wtf.csrf import CSRFProtect from app.markdown import init_markdown, MARKDOWN_EXTENSIONS, MARKDOWN_EXTENSION_CONFIG +import sentry_sdk +from sentry_sdk.integrations.flask import FlaskIntegration + + +if os.getenv("SENTRY_DSN"): + environment = os.getenv("SENTRY_ENVIRONMENT") + assert environment is not None + sentry_sdk.init( + dsn=os.getenv("SENTRY_DSN"), + environment=environment, + + integrations=[FlaskIntegration()], + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + traces_sample_rate=1.0, + # Set profiles_sample_rate to 1.0 to profile 100% + # of sampled transactions. + # We recommend adjusting this value in production. + profiles_sample_rate=1.0, + ) + + app = Flask(__name__, static_folder="public/static") @@ -95,11 +117,6 @@ from .sass import init_app as sass sass(app) -if not app.debug and app.config["MAIL_UTILS_ERROR_SEND_TO"]: - from .maillogger import build_handler - app.logger.addHandler(build_handler(app)) - - from . import models, template_filters diff --git a/app/maillogger.py b/app/maillogger.py deleted file mode 100644 index 687a5081..00000000 --- a/app/maillogger.py +++ /dev/null @@ -1,115 +0,0 @@ -# ContentDB -# Copyright (C) rubenwardy -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -import logging - -from app.tasks.emails import send_user_email - - -def _has_newline(line): - """Used by has_bad_header to check for \\r or \\n""" - if line and ("\r" in line or "\n" in line): - return True - return False - - -def _is_bad_subject(subject): - """Copied from: flask_mail.py class Message def has_bad_headers""" - if _has_newline(subject): - for linenum, line in enumerate(subject.split("\r\n")): - if not line: - return True - if linenum > 0 and line[0] not in "\t ": - return True - if _has_newline(line): - return True - if len(line.strip()) == 0: - return True - return False - - -class FlaskMailSubjectFormatter(logging.Formatter): - def format(self, record): - record.message = record.getMessage() - if self.usesTime(): - record.asctime = self.formatTime(record, self.datefmt) - s = self.formatMessage(record) - return s - - -class FlaskMailTextFormatter(logging.Formatter): - pass - - -class FlaskMailHTMLFormatter(logging.Formatter): - def formatException(self, exc_info): - formatted_exception = logging.Handler.formatException(self, exc_info) - return "
%s
" % formatted_exception - def formatStack(self, stack_info): - return "
%s
" % stack_info - - -# see: https://github.com/python/cpython/blob/3.6/Lib/logging/__init__.py (class Handler) - -class FlaskMailHandler(logging.Handler): - def __init__(self, send_to, subject_template, level=logging.NOTSET): - logging.Handler.__init__(self, level) - self.send_to = send_to - self.subject_template = subject_template - - 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 != None, "At least one formatter should be provided" - if type(text_fmt)==str: - text_fmt = FlaskMailTextFormatter(text_fmt) - self.formatter = text_fmt - - def getSubject(self, record): - fmt = FlaskMailSubjectFormatter(self.subject_template) - subject = fmt.format(record) - # Since templates can cause header problems, and we rather have an incomplete email then an error, we fix this - if _is_bad_subject(subject): - subject="FlaskMailHandler log-entry from ContentDB [original subject is replaced, because it would result in a bad header]" - return subject - - def emit(self, record): - subject = self.getSubject(record) - text = self.format(record) if self.formatter else None - html = "
{}
".format(text) - - if "The recipient has exceeded message rate limit. Try again later" in subject: - return - - for email in self.send_to: - send_user_email.delay(email, "en", subject, text, html) - - -def build_handler(app): - subject_template = "ContentDB %(message)s (%(module)s > %(funcName)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(app.config["MAIL_UTILS_ERROR_SEND_TO"], subject_template) - mail_handler.setLevel(logging.ERROR) - mail_handler.setFormatter(text_template) - return mail_handler diff --git a/app/tasks/__init__.py b/app/tasks/__init__.py index 56d4a09f..dd181fdf 100644 --- a/app/tasks/__init__.py +++ b/app/tasks/__init__.py @@ -107,23 +107,3 @@ celery.conf.beat_schedule = CELERYBEAT_SCHEDULE from . import importtasks, forumtasks, emails, pkgtasks, usertasks - - -# 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/config.example.cfg b/config.example.cfg index 5ccea894..56a5c8c7 100644 --- a/config.example.cfg +++ b/config.example.cfg @@ -26,7 +26,6 @@ MAIL_DEFAULT_SENDER = "" MAIL_SERVER = "" MAIL_PORT = 587 MAIL_USE_TLS = True -MAIL_UTILS_ERROR_SEND_TO = [""] UPLOAD_DIR = "/var/cdb/uploads/" THUMBNAIL_DIR = "/var/cdb/thumbnails/" diff --git a/requirements.lock.txt b/requirements.lock.txt index d8a5fe31..5ed75927 100644 --- a/requirements.lock.txt +++ b/requirements.lock.txt @@ -76,3 +76,4 @@ webencodings==0.5.1 Werkzeug==2.2.3 WTForms==3.0.1 WTForms-SQLAlchemy==0.3 +sentry-sdk[flask]==2.0.1 diff --git a/requirements.txt b/requirements.txt index 23cd581a..8afc4379 100644 --- a/requirements.txt +++ b/requirements.txt @@ -48,3 +48,5 @@ validators gitdb deep-compare + +sentry-sdk[flask]