diff --git a/emperor.ini b/emperor.ini index c5c3810a1..3eeac3a53 100644 --- a/emperor.ini +++ b/emperor.ini @@ -3,6 +3,7 @@ strict-mode = true protocol = uwsgi master = true enable-threads = true +lazy-apps = true emperor = ./vassals/*/*.ini # See https://uwsgi-docs.readthedocs.io/en/latest/Emperor.html#passing-configuration-parameters-to-all-vassals @@ -13,3 +14,5 @@ emperor-on-demand-extension = .socket fastrouter = 127.0.0.1:8001 fastrouter-subscription-server = /tmp/sock2 vacuum = true + +log-format = %(host) - %(addr) - %(user) [%(ltime)] "%(method) %(uri) %(proto)" %(status) %(size) "%(referer)" "%(uagent)" diff --git a/entrypoint.sh b/entrypoint.sh index bcc1b78d3..a519b31d5 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -29,5 +29,5 @@ flask db upgrade flask initdb -exec uwsgi --http :5000 --workers 1 --threads 2 --wsgi-file subscribie.wsgi --touch-chain-reload subscribie.wsgi --chdir /usr/src/app/subscribie/ +exec uwsgi --http :5000 --workers 1 --threads 2 --py-call-uwsgi-fork-hooks --wsgi-file subscribie.wsgi --touch-chain-reload subscribie.wsgi --chdir /usr/src/app/subscribie/ diff --git a/pyproject.toml b/pyproject.toml index 72bd07b57..f3dfecf61 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,6 +39,7 @@ dependencies = [ "scikit-learn", "black", "strictyaml", + "sentry-sdk[flask]>=2.14.0", ] readme = "README.md" requires-python = ">= 3.12" diff --git a/requirements-dev.lock b/requirements-dev.lock index 3d15330bc..3615bbdb0 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -22,9 +22,11 @@ black==24.4.2 blinker==1.8.2 # via flask # via flask-mail + # via sentry-sdk # via subscribie certifi==2024.2.2 # via requests + # via sentry-sdk cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 @@ -50,6 +52,7 @@ flask==3.0.3 # via flask-reuploaded # via flask-sqlalchemy # via flask-wtf + # via sentry-sdk # via subscribie flask-babel==4.0.0 # via subscribie @@ -96,6 +99,7 @@ mako==1.3.5 markupsafe==2.1.5 # via jinja2 # via mako + # via sentry-sdk # via werkzeug # via wtforms mypy-extensions==1.0.0 @@ -148,6 +152,8 @@ scikit-learn==1.5.0 scipy==1.13.1 # via scikit-learn # via subscribie +sentry-sdk==2.14.0 + # via subscribie six==1.16.0 # via python-dateutil smmap==5.0.1 @@ -172,6 +178,7 @@ tzdata==2024.1 # via pandas urllib3==2.2.1 # via requests + # via sentry-sdk werkzeug==3.0.3 # via flask wheel==0.43.0 diff --git a/requirements.lock b/requirements.lock index 3d15330bc..3615bbdb0 100644 --- a/requirements.lock +++ b/requirements.lock @@ -22,9 +22,11 @@ black==24.4.2 blinker==1.8.2 # via flask # via flask-mail + # via sentry-sdk # via subscribie certifi==2024.2.2 # via requests + # via sentry-sdk cffi==1.16.0 # via cryptography charset-normalizer==3.3.2 @@ -50,6 +52,7 @@ flask==3.0.3 # via flask-reuploaded # via flask-sqlalchemy # via flask-wtf + # via sentry-sdk # via subscribie flask-babel==4.0.0 # via subscribie @@ -96,6 +99,7 @@ mako==1.3.5 markupsafe==2.1.5 # via jinja2 # via mako + # via sentry-sdk # via werkzeug # via wtforms mypy-extensions==1.0.0 @@ -148,6 +152,8 @@ scikit-learn==1.5.0 scipy==1.13.1 # via scikit-learn # via subscribie +sentry-sdk==2.14.0 + # via subscribie six==1.16.0 # via python-dateutil smmap==5.0.1 @@ -172,6 +178,7 @@ tzdata==2024.1 # via pandas urllib3==2.2.1 # via requests + # via sentry-sdk werkzeug==3.0.3 # via flask wheel==0.43.0 diff --git a/settings.yaml.example b/settings.yaml.example index 2f418867f..d353ad9db 100644 --- a/settings.yaml.example +++ b/settings.yaml.example @@ -6,6 +6,10 @@ FLASK_ENV: development # SESSION_COOKIE_HTTPONLY: True # SESSION_COOKIE_SAMESITE: None +# Sentry_sdk_dsn +SENTRY_SDK_DSN: "https://changeme@changeme.ingest.de.sentry.io/123456789" +SENTRY_SDK_SESSION_REPLAY_ID: "changeme" + # Software as a service (SAAS) SAAS_URL: https://subscribie.co.uk/ # SAAS_API_KEY is to allow subscribie platform to send authenticated diff --git a/subscribie/__init__.py b/subscribie/__init__.py index 51d8ac647..e2b3cb57b 100644 --- a/subscribie/__init__.py +++ b/subscribie/__init__.py @@ -7,6 +7,7 @@ :copyright: (c) 2018 by Karma Computing Ltd """ +import sentry_sdk from subscribie.settings import settings from .logger import logger # noqa: F401 import logging @@ -25,6 +26,17 @@ request, abort, ) + +sentry_sdk.init( + dsn=settings.get("SENTRY_SDK_DSN"), + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for tracing. + 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, +) from flask_babel import Babel, _ from subscribie.email import EmailMessageQueue from .Template import load_theme @@ -378,4 +390,14 @@ def alert_subscriber_update_choices(subscriber: Person): def test_language(): return _("Hello") + @app.route("/error") + def raise_error(): + 1 / 0 # raises an error + return "" + + @app.route("/ui-error") + def raise_ui_error(): + """Raises UI error""" + return render_template("errors/ui-error.html"), 200 + return app diff --git a/subscribie/blueprints/admin/templates/admin/layout.html b/subscribie/blueprints/admin/templates/admin/layout.html index ce890ee8f..42eccf2e4 100644 --- a/subscribie/blueprints/admin/templates/admin/layout.html +++ b/subscribie/blueprints/admin/templates/admin/layout.html @@ -8,6 +8,7 @@ + {% if integration.google_tag_manager_container_id and integration.google_tag_manager_active diff --git a/subscribie/settings.py b/subscribie/settings.py index 5870a8f2c..512bf788a 100644 --- a/subscribie/settings.py +++ b/subscribie/settings.py @@ -1,4 +1,5 @@ from strictyaml import load, Map, Email, Str, Url, Int, Bool, Regex, CommaSeparated +import os # Load application settings according to schema @@ -7,6 +8,8 @@ schema = Map( { "FLASK_ENV": Str(), + "SENTRY_SDK_DSN": Str(), + "SENTRY_SDK_SESSION_REPLAY_ID": Str(), "SAAS_URL": Url(), "SAAS_API_KEY": Str(), "SAAS_ACTIVATE_ACCOUNT_PATH": Str(), @@ -57,6 +60,10 @@ def load_settings(): with open("settings.yaml") as fp: settings_string = fp.read() settings = load(settings_string, schema) + for key in schema._required_keys: + if key in os.environ: + print(f"Overriding setting {key} with environ value: {os.getenv(key)}") + settings[key] = os.getenv(key) return settings diff --git a/subscribie/themes/theme-jesmond/jesmond/errors/ui-error.html b/subscribie/themes/theme-jesmond/jesmond/errors/ui-error.html new file mode 100644 index 000000000..15859d5ca --- /dev/null +++ b/subscribie/themes/theme-jesmond/jesmond/errors/ui-error.html @@ -0,0 +1,10 @@ +{% extends "layout.html" %} + +{% block body %} + + +{% endblock %} \ No newline at end of file diff --git a/subscribie/themes/theme-jesmond/jesmond/layout.html b/subscribie/themes/theme-jesmond/jesmond/layout.html index 2437ce134..32cfe9554 100644 --- a/subscribie/themes/theme-jesmond/jesmond/layout.html +++ b/subscribie/themes/theme-jesmond/jesmond/layout.html @@ -7,6 +7,7 @@ + {% if custom_code != "None" %} diff --git a/subscribie/views.py b/subscribie/views.py index eafa883f5..e08aae2ad 100644 --- a/subscribie/views.py +++ b/subscribie/views.py @@ -150,12 +150,14 @@ def check_if_inside_iframe(): @bp.app_context_processor def inject_template_globals(): + from subscribie.settings import settings as internal_settings company = Company.query.first() integration = Integration.query.first() plans = Plan.query.filter_by(archived=0) pages = Page.query.all() settings = Setting.query.first() custom_code = settings.custom_code + SENTRY_SDK_SESSION_REPLAY_ID = internal_settings.get("SENTRY_SDK_SESSION_REPLAY_ID") geo_currency_symbol = get_geo_currency_symbol() default_currency_symbol = get_shop_default_currency_symbol() currency_format = currencyFormat @@ -166,6 +168,7 @@ def inject_template_globals(): plans=plans, pages=pages, custom_code=Markup(custom_code), + SENTRY_SDK_SESSION_REPLAY_ID=SENTRY_SDK_SESSION_REPLAY_ID, geo_currency_symbol=geo_currency_symbol, get_geo_currency_code=get_geo_currency_code, default_currency_symbol=default_currency_symbol,