diff --git a/api/.env-ci b/api/.env-ci index aca344b74e0d..cbc64251524f 100644 --- a/api/.env-ci +++ b/api/.env-ci @@ -1,5 +1,4 @@ DATABASE_URL=postgresql://postgres:password@localhost:5432/flagsmith ANALYTICS_DATABASE_URL=postgresql://postgres:password@localhost:5433/analytics PYTEST_ADDOPTS=--cov . --cov-report xml -n auto --ci -GUNICORN_LOGGER_CLASS=util.logging.GunicornJsonCapableLogger COVERAGE_CORE=sysmon diff --git a/api/app/settings/common.py b/api/app/settings/common.py index c75fae2fbf34..cd660dd4b3d7 100644 --- a/api/app/settings/common.py +++ b/api/app/settings/common.py @@ -11,7 +11,7 @@ """ import importlib -import json +import logging import os import warnings from datetime import datetime, time, timedelta @@ -19,7 +19,6 @@ import dj_database_url import django_stubs_ext -import prometheus_client import pytz from common.core import ReplicaReadStrategy from corsheaders.defaults import default_headers # type: ignore[import-untyped] @@ -610,61 +609,11 @@ CHARGEBEE_API_KEY = env("CHARGEBEE_API_KEY", default=None) CHARGEBEE_SITE = env("CHARGEBEE_SITE", default=None) -# Logging configuration -ACCESS_LOG_EXTRA_ITEMS = env.list("ACCESS_LOG_EXTRA_ITEMS", subcast=str, default=[]) -LOGGING_CONFIGURATION_FILE = env.str("LOGGING_CONFIGURATION_FILE", default=None) -if LOGGING_CONFIGURATION_FILE: - with open(LOGGING_CONFIGURATION_FILE, "r") as f: - LOGGING = json.loads(f.read()) -else: - LOG_FORMAT = env.str("LOG_FORMAT", default="generic") - LOG_LEVEL = env.str("LOG_LEVEL", default="WARNING") - LOGGING = { - "version": 1, - "disable_existing_loggers": False, - "formatters": { - "generic": {"format": "%(name)-12s %(levelname)-8s %(message)s"}, - "json": { - "()": "util.logging.JsonFormatter", - "datefmt": "%Y-%m-%d %H:%M:%S", - }, - }, - "handlers": { - "console": { - "level": LOG_LEVEL, - "class": "logging.StreamHandler", - "formatter": LOG_FORMAT, - } - }, - "loggers": { - "": {"level": LOG_LEVEL, "handlers": ["console"]}, - # Not sure why the following loggers are necessary, but it doesn't seem to - # write log messages for e.g. features.workflows.core.models without adding - # them explicitly. - # TODO: move all apps to a parent 'apps' directory and configure the logger - # for that dir - "features": { - "level": LOG_LEVEL, - "handlers": ["console"], - "propagate": False, - }, - "task_processor": { - "level": LOG_LEVEL, - "handlers": ["console"], - "propagate": False, - }, - "app_analytics": { - "level": LOG_LEVEL, - "handlers": ["console"], - "propagate": False, - }, - "webhooks": { - "level": LOG_LEVEL, - "handlers": ["console"], - "propagate": False, - }, - }, - } +# Logging is configured by flagsmith-common's setup_logging() in ensure_cli_env(), +# before Django loads. Disable Django's logging config to preserve our setup. +LOGGING_CONFIG = None +LOG_FORMAT = env.str("LOG_FORMAT", default="generic") +LOG_LEVEL = env.str("LOG_LEVEL", default="WARNING") ENABLE_DB_LOGGING = env.bool("DJANGO_ENABLE_DB_LOGGING", default=False) if ENABLE_DB_LOGGING: @@ -672,10 +621,7 @@ warnings.warn("Setting DEBUG=True to ensure DB logging functions correctly.") DEBUG = True - LOGGING["loggers"]["django.db.backends"] = { - "level": "DEBUG", - "handlers": ["console"], - } + logging.getLogger("django.db.backends").setLevel(logging.DEBUG) CACHE_FLAGS_SECONDS = env.int("CACHE_FLAGS_SECONDS", default=0) FLAGS_CACHE_LOCATION = "environment-flags" @@ -1442,12 +1388,6 @@ INSTALLED_APPS.append("licensing") PROMETHEUS_ENABLED = env.bool("PROMETHEUS_ENABLED", False) -PROMETHEUS_HISTOGRAM_BUCKETS = tuple( - env.list( - "PROMETHEUS_HISTOGRAM_BUCKETS", - default=prometheus_client.Histogram.DEFAULT_BUCKETS, - ) -) DOCGEN_MODE = env.bool("DOCGEN_MODE", default=False) diff --git a/api/organisations/urls.py b/api/organisations/urls.py index 963978cc095f..95ac0febdc23 100644 --- a/api/organisations/urls.py +++ b/api/organisations/urls.py @@ -161,7 +161,7 @@ ] if settings.LICENSING_INSTALLED: # pragma: no cover - from licensing.views import ( # type: ignore[import-not-found] + from licensing.views import ( # type: ignore[import-not-found,import-untyped,unused-ignore] create_or_update_licence, ) diff --git a/api/poetry.lock b/api/poetry.lock index 191c8bef65d1..abebe6950a72 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -967,7 +967,7 @@ description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] -markers = "platform_system == \"Windows\" or sys_platform == \"win32\"" +markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -1109,61 +1109,61 @@ toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "cryptography" -version = "46.0.6" +version = "46.0.5" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = "!=3.9.0,!=3.9.1,>=3.8" groups = ["main", "dev", "licensing", "saml"] files = [ - {file = "cryptography-46.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:64235194bad039a10bb6d2d930ab3323baaec67e2ce36215fd0952fad0930ca8"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:26031f1e5ca62fcb9d1fcb34b2b60b390d1aacaa15dc8b895a9ed00968b97b30"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9a693028b9cbe51b5a1136232ee8f2bc242e4e19d456ded3fa7c86e43c713b4a"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:67177e8a9f421aa2d3a170c3e56eca4e0128883cf52a071a7cbf53297f18b175"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d9528b535a6c4f8ff37847144b8986a9a143585f0540fbcb1a98115b543aa463"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:22259338084d6ae497a19bae5d4c66b7ca1387d3264d1c2c0e72d9e9b6a77b97"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:760997a4b950ff00d418398ad73fbc91aa2894b5c1db7ccb45b4f68b42a63b3c"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3dfa6567f2e9e4c5dceb8ccb5a708158a2a871052fa75c8b78cb0977063f1507"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:cdcd3edcbc5d55757e5f5f3d330dd00007ae463a7e7aa5bf132d1f22a4b62b19"}, - {file = "cryptography-46.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:d4e4aadb7fc1f88687f47ca20bb7227981b03afaae69287029da08096853b738"}, - {file = "cryptography-46.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2b417edbe8877cda9022dde3a008e2deb50be9c407eef034aeeb3a8b11d9db3c"}, - {file = "cryptography-46.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:380343e0653b1c9d7e1f55b52aaa2dbb2fdf2730088d48c43ca1c7c0abb7cc2f"}, - {file = "cryptography-46.0.6-cp311-abi3-win32.whl", hash = "sha256:bcb87663e1f7b075e48c3be3ecb5f0b46c8fc50b50a97cf264e7f60242dca3f2"}, - {file = "cryptography-46.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:6739d56300662c468fddb0e5e291f9b4d084bead381667b9e654c7dd81705124"}, - {file = "cryptography-46.0.6-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:2ef9e69886cbb137c2aef9772c2e7138dc581fad4fcbcf13cc181eb5a3ab6275"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7f417f034f91dcec1cb6c5c35b07cdbb2ef262557f701b4ecd803ee8cefed4f4"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d24c13369e856b94892a89ddf70b332e0b70ad4a5c43cf3e9cb71d6d7ffa1f7b"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:aad75154a7ac9039936d50cf431719a2f8d4ed3d3c277ac03f3339ded1a5e707"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:3c21d92ed15e9cfc6eb64c1f5a0326db22ca9c2566ca46d845119b45b4400361"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:4668298aef7cddeaf5c6ecc244c2302a2b8e40f384255505c22875eebb47888b"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:8ce35b77aaf02f3b59c90b2c8a05c73bac12cea5b4e8f3fbece1f5fddea5f0ca"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:c89eb37fae9216985d8734c1afd172ba4927f5a05cfd9bf0e4863c6d5465b013"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:ed418c37d095aeddf5336898a132fba01091f0ac5844e3e8018506f014b6d2c4"}, - {file = "cryptography-46.0.6-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:69cf0056d6947edc6e6760e5f17afe4bea06b56a9ac8a06de9d2bd6b532d4f3a"}, - {file = "cryptography-46.0.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8e7304c4f4e9490e11efe56af6713983460ee0780f16c63f219984dab3af9d2d"}, - {file = "cryptography-46.0.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b928a3ca837c77a10e81a814a693f2295200adb3352395fad024559b7be7a736"}, - {file = "cryptography-46.0.6-cp314-cp314t-win32.whl", hash = "sha256:97c8115b27e19e592a05c45d0dd89c57f81f841cc9880e353e0d3bf25b2139ed"}, - {file = "cryptography-46.0.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c797e2517cb7880f8297e2c0f43bb910e91381339336f75d2c1c2cbf811b70b4"}, - {file = "cryptography-46.0.6-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:12cae594e9473bca1a7aceb90536060643128bb274fcea0fc459ab90f7d1ae7a"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:639301950939d844a9e1c4464d7e07f902fe9a7f6b215bb0d4f28584729935d8"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ed3775295fb91f70b4027aeba878d79b3e55c0b3e97eaa4de71f8f23a9f2eb77"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8927ccfbe967c7df312ade694f987e7e9e22b2425976ddbf28271d7e58845290"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b12c6b1e1651e42ab5de8b1e00dc3b6354fdfd778e7fa60541ddacc27cd21410"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:063b67749f338ca9c5a0b7fe438a52c25f9526b851e24e6c9310e7195aad3b4d"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:02fad249cb0e090b574e30b276a3da6a149e04ee2f049725b1f69e7b8351ec70"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e6142674f2a9291463e5e150090b95a8519b2fb6e6aaec8917dd8d094ce750d"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:456b3215172aeefb9284550b162801d62f5f264a081049a3e94307fe20792cfa"}, - {file = "cryptography-46.0.6-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:341359d6c9e68834e204ceaf25936dffeafea3829ab80e9503860dcc4f4dac58"}, - {file = "cryptography-46.0.6-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9a9c42a2723999a710445bc0d974e345c32adfd8d2fac6d8a251fa829ad31cfb"}, - {file = "cryptography-46.0.6-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6617f67b1606dfd9fe4dbfa354a9508d4a6d37afe30306fe6c101b7ce3274b72"}, - {file = "cryptography-46.0.6-cp38-abi3-win32.whl", hash = "sha256:7f6690b6c55e9c5332c0b59b9c8a3fb232ebf059094c17f9019a51e9827df91c"}, - {file = "cryptography-46.0.6-cp38-abi3-win_amd64.whl", hash = "sha256:79e865c642cfc5c0b3eb12af83c35c5aeff4fa5c672dc28c43721c2c9fdd2f0f"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:2ea0f37e9a9cf0df2952893ad145fd9627d326a59daec9b0802480fa3bcd2ead"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a3e84d5ec9ba01f8fd03802b2147ba77f0c8f2617b2aff254cedd551844209c8"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:12f0fa16cc247b13c43d56d7b35287ff1569b5b1f4c5e87e92cc4fcc00cd10c0"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:50575a76e2951fe7dbd1f56d181f8c5ceeeb075e9ff88e7ad997d2f42af06e7b"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:90e5f0a7b3be5f40c3a0a0eafb32c681d8d2c181fc2a1bdabe9b3f611d9f6b1a"}, - {file = "cryptography-46.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6728c49e3b2c180ef26f8e9f0a883a2c585638db64cf265b49c9ba10652d430e"}, - {file = "cryptography-46.0.6.tar.gz", hash = "sha256:27550628a518c5c6c903d84f637fbecf287f6cb9ced3804838a1295dc1fd0759"}, + {file = "cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0"}, + {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731"}, + {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82"}, + {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1"}, + {file = "cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48"}, + {file = "cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4"}, + {file = "cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0"}, + {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663"}, + {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826"}, + {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d"}, + {file = "cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a"}, + {file = "cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4"}, + {file = "cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d"}, + {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c"}, + {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4"}, + {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9"}, + {file = "cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72"}, + {file = "cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257"}, + {file = "cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7"}, + {file = "cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d"}, ] [package.dependencies] @@ -1176,7 +1176,7 @@ nox = ["nox[uv] (>=2024.4.15)"] pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] sdist = ["build (>=1.0.0)"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi (>=2024)", "cryptography-vectors (==46.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] test-randomorder = ["pytest-randomly"] [[package]] @@ -2033,14 +2033,14 @@ resolved_reference = "b7fa1f42c333b443763548ea1fe0054f07cdf641" [[package]] name = "flagsmith-common" -version = "3.3.0" +version = "3.5.0" description = "Flagsmith's common library" optional = false python-versions = "<4.0,>=3.11" groups = ["main", "dev", "licensing", "workflows"] files = [ - {file = "flagsmith_common-3.3.0-py3-none-any.whl", hash = "sha256:dcb94458c7fd1bbc7762080d5c11c1d97507beac48a71132209f322112d8c60d"}, - {file = "flagsmith_common-3.3.0.tar.gz", hash = "sha256:e2839eda7091f13794efbaa7e20895110f9fbf5953dd67f70585b93e7c5864fa"}, + {file = "flagsmith_common-3.5.0-py3-none-any.whl", hash = "sha256:6a23c863264351e575d077c9aacf4ab3932975c7d550ef1b33b515f5618b6066"}, + {file = "flagsmith_common-3.5.0.tar.gz", hash = "sha256:fdeebd3b66c079f5e1dc100141470dda0265fa3659bd6723d5bcd53633aad64e"}, ] [package.dependencies] @@ -2059,11 +2059,13 @@ psycopg2-binary = {version = ">=2.9,<3", optional = true, markers = "extra == \" pyfakefs = {version = ">=5,<6", optional = true, markers = "extra == \"test-tools\""} pytest-django = {version = ">=4,<5", optional = true, markers = "extra == \"test-tools\""} requests = {version = "*", optional = true, markers = "extra == \"common-core\""} +sentry-sdk = {version = ">=2.0.0,<3.0.0", optional = true, markers = "extra == \"common-core\""} simplejson = {version = ">=3,<4", optional = true, markers = "extra == \"common-core\" and extra == \"flagsmith-schemas\""} -typing-extensions = {version = "*", optional = true, markers = "extra == \"flagsmith-schemas\""} +structlog = {version = ">=24.4,<26", optional = true, markers = "extra == \"common-core\""} +typing-extensions = {version = "*", optional = true, markers = "extra == \"common-core\" or extra == \"flagsmith-schemas\""} [package.extras] -common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "requests", "simplejson (>=3,<4)"] +common-core = ["django (>4,<6)", "django-health-check", "djangorestframework", "djangorestframework-recursive", "drf-spectacular (>=0.28.0,<1)", "drf-writable-nested", "environs (<15)", "gunicorn (>=19.1)", "prometheus-client (>=0.0.16)", "psycopg2-binary (>=2.9,<3)", "requests", "sentry-sdk (>=2.0.0,<3.0.0)", "simplejson (>=3,<4)", "structlog (>=24.4,<26)", "typing-extensions"] flagsmith-schemas = ["flagsmith-flag-engine (>6)", "simplejson", "typing-extensions"] task-processor = ["backoff (>=2.2.1,<3.0.0)", "django (>4,<6)", "django-health-check", "prometheus-client (>=0.0.16)"] test-tools = ["pyfakefs (>=5,<6)", "pytest-django (>=4,<5)"] @@ -4255,7 +4257,6 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, @@ -4467,14 +4468,14 @@ files = [ [[package]] name = "requests" -version = "2.33.0" +version = "2.33.1" description = "Python HTTP for Humans." optional = false python-versions = ">=3.10" groups = ["main", "dev", "saml"] files = [ - {file = "requests-2.33.0-py3-none-any.whl", hash = "sha256:3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b"}, - {file = "requests-2.33.0.tar.gz", hash = "sha256:c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652"}, + {file = "requests-2.33.1-py3-none-any.whl", hash = "sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a"}, + {file = "requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517"}, ] [package.dependencies] @@ -4485,7 +4486,6 @@ urllib3 = ">=1.26,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] -test = ["PySocks (>=1.5.6,!=1.5.7)", "pytest (>=3)", "pytest-cov", "pytest-httpbin (==2.1.0)", "pytest-mock", "pytest-xdist"] use-chardet-on-py3 = ["chardet (>=3.0.2,<8)"] [[package]] @@ -5671,4 +5671,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = ">3.11,<3.14" -content-hash = "16599cda4178234d12de9910adfba08c54802e6e4f43b2d499b33eeebdb555df" +content-hash = "be68d9e58505506bea67c09d1d96dcf5ba4ce14ee09e6fe7f8d43fbfb6ff9353" diff --git a/api/pyproject.toml b/api/pyproject.toml index 392d981bb40d..86c1dd2c667d 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -163,7 +163,7 @@ pygithub = "~2.8" hubspot-api-client = "^12.0.0" djangorestframework-dataclasses = "^1.3.1" pyotp = "^2.9.0" -flagsmith-common = { version = "^3.3.0", extras = [ +flagsmith-common = { version = ">=3.5.0,<4", extras = [ "common-core", "flagsmith-schemas", "task-processor", diff --git a/api/scripts/run-docker.sh b/api/scripts/run-docker.sh index ae99547f7f1f..7e1bf2e2e47e 100755 --- a/api/scripts/run-docker.sh +++ b/api/scripts/run-docker.sh @@ -3,6 +3,7 @@ set -e # common environment variables ACCESS_LOG_FORMAT=${ACCESS_LOG_FORMAT:-'%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %({origin}i)s %({access-control-allow-origin}o)s'} +APPLICATION_LOGGERS=${APPLICATION_LOGGERS:-"common,features,task_processor,app_analytics,webhooks"} waitfordb() { if [ -z "${SKIP_WAIT_FOR_DB}" ]; then diff --git a/api/tests/unit/util/test_logging.py b/api/tests/unit/util/test_logging.py deleted file mode 100644 index c8c81603fe1e..000000000000 --- a/api/tests/unit/util/test_logging.py +++ /dev/null @@ -1,140 +0,0 @@ -import json -import logging -import logging.config -import os -from datetime import datetime - -import pytest -from gunicorn.config import AccessLogFormat, Config # type: ignore[import-untyped] -from pytest_django.fixtures import SettingsWrapper - -from util.logging import GunicornAccessLogJsonFormatter, JsonFormatter - - -@pytest.mark.freeze_time("2023-12-08T06:05:47.000000+00:00") -def test_json_formatter__info_and_error_logs__outputs_expected_json( - inspecting_handler: logging.Handler, - request: pytest.FixtureRequest, -) -> None: - # Given - json_formatter = JsonFormatter() - - inspecting_handler.setFormatter(json_formatter) - logger = logging.getLogger("test_json_formatter__outputs_expected") - logger.addHandler(inspecting_handler) - logger.setLevel(logging.INFO) - - expected_pid = os.getpid() - expected_module_path = os.path.abspath(request.path) - expected_tb_string = ( - "Traceback (most recent call last):\n" - f' File "{expected_module_path}",' - " line 38, in _log_traceback\n" - " raise Exception()\nException" - ) - - def _log_traceback() -> None: - try: - raise Exception() - except Exception as exc: - logger.error("this is an error", exc_info=exc) - - # When - logger.info("hello %s, %d", "arg1", 22.22) - _log_traceback() - - # Then - assert [json.loads(message) for message in inspecting_handler.messages] == [ # type: ignore[attr-defined] - { - "levelname": "INFO", - "message": "hello arg1, 22", - "timestamp": "2023-12-08 06:05:47,000", - "logger_name": "test_json_formatter__outputs_expected", - "process_id": expected_pid, - "thread_name": "MainThread", - }, - { - "levelname": "ERROR", - "message": "this is an error", - "timestamp": "2023-12-08 06:05:47,000", - "logger_name": "test_json_formatter__outputs_expected", - "process_id": expected_pid, - "thread_name": "MainThread", - "exc_info": expected_tb_string, - }, - ] - - -@pytest.mark.freeze_time("2023-12-08T06:05:47.000000+00:00") -def test_gunicorn_access_log_json_formatter__access_log_record__outputs_expected_json() -> ( - None -): - # Given - gunicorn_access_log_json_formatter = GunicornAccessLogJsonFormatter() - log_record = logging.LogRecord( - name="gunicorn.access", - level=logging.INFO, - pathname="", - lineno=1, - msg=AccessLogFormat.default, - args={ - "a": "requests", - "b": "-", - "B": None, - "D": 1000000, - "f": "-", - "h": "192.168.0.1", - "H": None, - "l": "-", - "L": "1.0", - "m": "GET", - "M": 1000, - "p": "<42>", - "q": "foo=bar", - "r": "GET", - "s": 200, - "T": 1, - "t": datetime.fromisoformat("2023-12-08T06:05:47.000+00:00").strftime( - "[%d/%b/%Y:%H:%M:%S %z]" - ), - "u": "-", - "U": "/test", - }, - exc_info=None, - ) - expected_pid = os.getpid() - - # When - json_log = gunicorn_access_log_json_formatter.get_json_record(log_record) - - # Then - assert json_log == { - "duration_in_ms": 1000, - "levelname": "INFO", - "logger_name": "gunicorn.access", - "message": '192.168.0.1 - - [08/Dec/2023:06:05:47 +0000] "GET" 200 - "-" "requests"', - "method": "GET", - "path": "/test?foo=bar", - "pid": "<42>", - "process_id": expected_pid, - "referer": "-", - "remote_ip": "192.168.0.1", - "status": "200", - "thread_name": "MainThread", - "time": "2023-12-08T06:05:47+00:00", - "timestamp": "2023-12-08 06:05:47,000", - "user_agent": "requests", - } - - -def test_gunicorn_json_capable_logger__non_existent_setting__not_raises( - settings: SettingsWrapper, -) -> None: - # Given - del settings.LOG_FORMAT - config = Config() - - # When & Then - from util.logging import GunicornJsonCapableLogger - - GunicornJsonCapableLogger(config) diff --git a/api/util/logging.py b/api/util/logging.py deleted file mode 100644 index ae986132fcbd..000000000000 --- a/api/util/logging.py +++ /dev/null @@ -1,70 +0,0 @@ -import json -import logging -import sys -from datetime import datetime -from typing import Any - -from django.conf import settings -from gunicorn.config import Config # type: ignore[import-untyped] -from gunicorn.instrument.statsd import ( # type: ignore[import-untyped] - Statsd as GunicornLogger, -) - - -class JsonFormatter(logging.Formatter): - """Custom formatter for json logs.""" - - def get_json_record(self, record: logging.LogRecord) -> dict[str, Any]: - formatted_message = record.getMessage() - json_record = { - "levelname": record.levelname, - "message": formatted_message, - "timestamp": self.formatTime(record, self.datefmt), - "logger_name": record.name, - "process_id": record.process, - "thread_name": record.threadName, - } - if record.exc_info: - json_record["exc_info"] = self.formatException(record.exc_info) - return json_record - - def format(self, record: logging.LogRecord) -> str: - return json.dumps(self.get_json_record(record)) - - -class GunicornAccessLogJsonFormatter(JsonFormatter): - def get_json_record(self, record: logging.LogRecord) -> dict[str, Any]: - args = record.args - url = args["U"] # type: ignore[call-overload,index] - if q := args["q"]: # type: ignore[call-overload,index] - url += f"?{q}" # type: ignore[operator] - - return { - **super().get_json_record(record), - "time": datetime.strptime(args["t"], "[%d/%b/%Y:%H:%M:%S %z]").isoformat(), # type: ignore[arg-type,call-overload,index] # noqa: E501 # noqa: E501 - "path": url, - "remote_ip": args["h"], # type: ignore[call-overload,index] - "method": args["m"], # type: ignore[call-overload,index] - "status": str(args["s"]), # type: ignore[call-overload,index] - "user_agent": args["a"], # type: ignore[call-overload,index] - "referer": args["f"], # type: ignore[call-overload,index] - "duration_in_ms": args["M"], # type: ignore[call-overload,index] - "pid": args["p"], # type: ignore[call-overload,index] - } - - -class GunicornJsonCapableLogger(GunicornLogger): # type: ignore[misc] - def setup(self, cfg: Config) -> None: - super().setup(cfg) - if getattr(settings, "LOG_FORMAT", None) == "json": - self._set_handler( - self.error_log, - cfg.errorlog, - JsonFormatter(), - ) - self._set_handler( - self.access_log, - cfg.accesslog, - GunicornAccessLogJsonFormatter(), - stream=sys.stdout, - )