from __future__ import annotations import logging import os SCANNER_PATH_PREFIXES = ( "/.env", "/.git", "/.streamlit", "/_debug", "/_profiler", "/_stcore", "/actuator", "/admin", "/api/config", "/api/credentials", "/api/env", "/api/keys", "/api/predict", "/api/queue/status", "/api/secrets", "/api/settings", "/api/v1/", "/api-docs", "/app.py", "/backup/", "/config", "/debug", "/docs", "/elmah", "/file", "/graphql", "/horizon", "/info", "/internal", "/main.py", "/manifest.json", "/metrics", "/openapi.json", "/phpinfo", "/proc/", "/prometheus", "/redoc", "/run/predict", "/server-", "/settings", "/swagger", "/telescope", "/trace", "/upload?upload_id=", "/wp-config", "/__phpinfo", ) class ScannerNoiseFilter(logging.Filter): def filter(self, record: logging.LogRecord) -> bool: try: path = str(record.args[2]).lower() status_code = int(record.args[4]) except (IndexError, TypeError, ValueError): return True if status_code not in {404, 405}: return True return not path.startswith(SCANNER_PATH_PREFIXES) def install_access_log_filter() -> None: enabled = os.getenv("SUPPRESS_SCANNER_ACCESS_LOGS", "true").lower() in { "1", "true", "yes", } if not enabled: return logger = logging.getLogger("uvicorn.access") if not any(isinstance(item, ScannerNoiseFilter) for item in logger.filters): logger.addFilter(ScannerNoiseFilter())