mirror of
https://github.com/minetest/contentdb.git
synced 2025-01-03 03:37:28 +01:00
Use Sentry instead of emailing errors
This commit is contained in:
parent
3a794fecbf
commit
7d18cdee95
@ -30,6 +30,28 @@ from flask_wtf.csrf import CSRFProtect
|
|||||||
|
|
||||||
from app.markdown import init_markdown, MARKDOWN_EXTENSIONS, MARKDOWN_EXTENSION_CONFIG
|
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")
|
app = Flask(__name__, static_folder="public/static")
|
||||||
|
|
||||||
|
|
||||||
@ -95,11 +117,6 @@ from .sass import init_app as sass
|
|||||||
sass(app)
|
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
|
from . import models, template_filters
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
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 "<pre>%s</pre>" % formatted_exception
|
|
||||||
def formatStack(self, stack_info):
|
|
||||||
return "<pre>%s</pre>" % 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 = "<pre>{}</pre>".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
|
|
@ -107,23 +107,3 @@ celery.conf.beat_schedule = CELERYBEAT_SCHEDULE
|
|||||||
|
|
||||||
|
|
||||||
from . import importtasks, forumtasks, emails, pkgtasks, usertasks
|
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)
|
|
||||||
|
@ -26,7 +26,6 @@ MAIL_DEFAULT_SENDER = ""
|
|||||||
MAIL_SERVER = ""
|
MAIL_SERVER = ""
|
||||||
MAIL_PORT = 587
|
MAIL_PORT = 587
|
||||||
MAIL_USE_TLS = True
|
MAIL_USE_TLS = True
|
||||||
MAIL_UTILS_ERROR_SEND_TO = [""]
|
|
||||||
|
|
||||||
UPLOAD_DIR = "/var/cdb/uploads/"
|
UPLOAD_DIR = "/var/cdb/uploads/"
|
||||||
THUMBNAIL_DIR = "/var/cdb/thumbnails/"
|
THUMBNAIL_DIR = "/var/cdb/thumbnails/"
|
||||||
|
@ -76,3 +76,4 @@ webencodings==0.5.1
|
|||||||
Werkzeug==2.2.3
|
Werkzeug==2.2.3
|
||||||
WTForms==3.0.1
|
WTForms==3.0.1
|
||||||
WTForms-SQLAlchemy==0.3
|
WTForms-SQLAlchemy==0.3
|
||||||
|
sentry-sdk[flask]==2.0.1
|
||||||
|
@ -48,3 +48,5 @@ validators
|
|||||||
gitdb
|
gitdb
|
||||||
|
|
||||||
deep-compare
|
deep-compare
|
||||||
|
|
||||||
|
sentry-sdk[flask]
|
||||||
|
Loading…
Reference in New Issue
Block a user