diff --git a/aurweb/asgi.py b/aurweb/asgi.py index ad0b7ca0..fa2526ed 100644 --- a/aurweb/asgi.py +++ b/aurweb/asgi.py @@ -74,6 +74,10 @@ async def app_startup(): if not session_secret: raise Exception("[fastapi] session_secret must not be empty") + if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): + logger.warning("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " + "endpoint is disabled.") + app.mount("/static/css", StaticFiles(directory="web/html/css"), name="static_css") diff --git a/aurweb/routers/html.py b/aurweb/routers/html.py index b9d291d2..d31a32c7 100644 --- a/aurweb/routers/html.py +++ b/aurweb/routers/html.py @@ -13,7 +13,7 @@ from sqlalchemy import and_, case, or_ import aurweb.config import aurweb.models.package_request -from aurweb import cookies, db, models, time, util +from aurweb import cookies, db, logging, models, time, util from aurweb.cache import db_count_cache from aurweb.exceptions import handle_form_exceptions from aurweb.models.account_type import TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID @@ -21,6 +21,7 @@ from aurweb.models.package_request import PENDING_ID from aurweb.packages.util import query_notified, query_voted, updated_packages from aurweb.templates import make_context, render_template +logger = logging.get_logger(__name__) router = APIRouter() @@ -230,9 +231,12 @@ async def archive_sha256(request: Request, archive: str): @router.get("/metrics") async def metrics(request: Request): + if not os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): + return Response("Prometheus metrics are not enabled.", + status_code=HTTPStatus.SERVICE_UNAVAILABLE) + registry = CollectorRegistry() - if os.environ.get("PROMETHEUS_MULTIPROC_DIR", None): # pragma: no cover - multiprocess.MultiProcessCollector(registry) + multiprocess.MultiProcessCollector(registry) data = generate_latest(registry) headers = { "Content-Type": CONTENT_TYPE_LATEST, diff --git a/test/test_asgi.py b/test/test_asgi.py index 667ae871..c693a3a9 100644 --- a/test/test_asgi.py +++ b/test/test_asgi.py @@ -104,6 +104,17 @@ async def test_asgi_app_unsupported_backends(): await aurweb.asgi.app_startup() +@pytest.mark.asyncio +async def test_asgi_app_disabled_metrics(caplog: pytest.LogCaptureFixture): + env = {"PROMETHEUS_MULTIPROC_DIR": str()} + with mock.patch.dict(os.environ, env): + await aurweb.asgi.app_startup() + + expected = ("$PROMETHEUS_MULTIPROC_DIR is not set, the /metrics " + "endpoint is disabled.") + assert expected in caplog.text + + @pytest.fixture def use_traceback(): config_getboolean = aurweb.config.getboolean diff --git a/test/test_html.py b/test/test_html.py index b97d3571..ffe2a9f2 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -160,12 +160,23 @@ def test_archive_sig_404(client: TestClient): def test_metrics(client: TestClient): - with client as request: - resp = request.get("/metrics") + with tempfile.TemporaryDirectory() as tmpdir: + env = {"PROMETHEUS_MULTIPROC_DIR": tmpdir} + with mock.patch.dict(os.environ, env): + with client as request: + resp = request.get("/metrics") assert resp.status_code == int(HTTPStatus.OK) assert resp.headers.get("Content-Type").startswith("text/plain") +def test_disabled_metrics(client: TestClient): + env = {"PROMETHEUS_MULTIPROC_DIR": str()} + with mock.patch.dict(os.environ, env): + with client as request: + resp = request.get("/metrics") + assert resp.status_code == int(HTTPStatus.SERVICE_UNAVAILABLE) + + def test_rtl(client: TestClient): responses = {} expected = [