From: Giorgio Ravera Date: Wed, 11 Mar 2026 18:35:43 +0000 (+0100) Subject: better version of logger management X-Git-Url: http://git.giorgioravera.it/?a=commitdiff_plain;h=c92e23241803034e0c3ef3d72ed430b1646eb063;p=network-manager.git better version of logger management --- diff --git a/backend/app.py b/backend/app.py new file mode 100644 index 0000000..41eef47 --- /dev/null +++ b/backend/app.py @@ -0,0 +1,239 @@ +# backend/app.py + +# import standard modules +from contextlib import asynccontextmanager +from fastapi import FastAPI, Request, status +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import FileResponse, RedirectResponse, JSONResponse, Response +from starlette.middleware.base import BaseHTTPMiddleware +from typing import Callable +import os + +# Import Routers +from backend.routes.about import router as about_router +from backend.routes.backup import router as backup_router +from backend.routes.health import router as health_router +from backend.routes.login import router as login_router +from backend.routes.hosts import router as hosts_router +from backend.routes.aliases import router as aliases_router +from backend.routes.dns import router as dns_router +from backend.routes.dhcp import router as dhcp_router + +# Import Security +from backend.security import is_logged_in, apply_session + +# Import Settings & Logging +from settings.settings import settings +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) + +# ------------------------------------------------------------------------------ +# Security Headers middleware (basic hardening) +# ------------------------------------------------------------------------------ +class SecurityHeadersMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next: Callable): + response: Response = await call_next(request) + + # Hardening base + response.headers["X-Content-Type-Options"] = "nosniff" + response.headers["X-Frame-Options"] = "DENY" + response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin" + response.headers["Permissions-Policy"] = ( + "geolocation=(), microphone=(), camera=(), payment=(), usb=(), " + "accelerometer=(), autoplay=(), clipboard-read=(), clipboard-write=()" + ) + + # HSTS (richiede HTTPS) + response.headers["Strict-Transport-Security"] = ( + "max-age=31536000; includeSubDomains; preload" + ) + + # COOP / CORP isolano la pagina (protezione anti-XSS/XFO) + response.headers["Cross-Origin-Opener-Policy"] = "same-origin" + response.headers["Cross-Origin-Resource-Policy"] = "same-origin" + + # CSP rigida per produzione + response.headers["Content-Security-Policy"] = ( + "default-src 'self'; " + "base-uri 'self'; " + "object-src 'none'; " + "frame-ancestors 'none'; " + "img-src 'self' data:; " + "font-src 'self' data:; " + "style-src 'self'; " + "script-src 'self'; " + "connect-src 'self'; " + "manifest-src 'self'; " + "worker-src 'self'" + ) + return response + +# ------------------------------------------------------------------------------ +# Public paths +# ------------------------------------------------------------------------------ +PUBLIC_PATHS = ( + "/login", + "/api/login", + "/logout", + "/api/logout", + "/about", + "/api/health", + "/docs", + "/openapi.json", +) + +STATIC_PREFIXES = ( + "/css", + "/js", + "/static", +) + +STATIC_SUFFIXES = (".js", ".css", ".png", ".jpg", ".jpeg", ".ico", ".svg", ".map") + +# ------------------------------------------------------------------------------ +# Session / Auth middleware +# ------------------------------------------------------------------------------ +async def session_middleware(request: Request, call_next): + path = request.url.path + method = request.method.upper() + + # 1) Always let CORS preflight through (browsers send OPTIONS before real requests) + if method == "OPTIONS": + return await call_next(request) + + # 2) Skip public endpoints (login/logout/about/health/docs/openapi) + if path.startswith(PUBLIC_PATHS): + return await call_next(request) + + # 3) Skip static assets + if path.startswith(STATIC_PREFIXES) or path.endswith(STATIC_SUFFIXES): + return await call_next(request) + + # 4) Read session token from cookie (adjust name if different) + token = request.cookies.get("session") + + # 5) Check authentication (your function should validate the cookie/session) + authenticated = is_logged_in(request) + + # 6) Protect JSON APIs + if path.startswith("/api"): + if not authenticated: + logger.warning("API access denied - not logged in: %s %s", method, path) + return JSONResponse( + status_code=status.HTTP_401_UNAUTHORIZED, + headers={"WWW-Authenticate": "Session"}, + content={ + "detail": { + "code": "UNAUTHORIZED", + "status": "failure", + "message": "Unauthorized", + "path": path, + } + }, + ) + + # Optionally attach user info to request.state for downstream handlers + # request.state.user = + + # Call the downstream route/handler + response = await call_next(request) + + # Apply sliding expiration only on successful responses (2xx) and if a token exists + if token and 200 <= response.status_code < 300: + apply_session(response, username=None, token=token) + return response + + # 7) Protect HTML pages (non-API): redirect unauthenticated users to login + if not authenticated: + # 303 See Other avoids reusing POST/other methods + return RedirectResponse("/login", status_code=status.HTTP_303_SEE_OTHER) + + # 8) Authenticated HTML request ? proceed + response = await call_next(request) + + # 9) Apply sliding expiration only on successful responses (2xx) + if token and 200 <= response.status_code < 300: + apply_session(response, username=None, token=token) + + return response + +# ------------------------------------------------------------------------------ +# FRONTEND Handlers +# ------------------------------------------------------------------------------ +# Homepage +def home(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "hosts.html")) + +# CSS variables +def css_variables(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "css/variables.css")) + +# CSS Layout +def css_layout(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "css/layout.css")) + +# JS Common +def js_common(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "js/common.js")) + +# JS Services +def js_services(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "js/services.js")) + +# favicon +def favicon(request: Request): + return FileResponse(os.path.join(settings.FRONTEND_DIR, "favicon.ico")) + +# ------------------------------------------------------------------------------ +# Creates and configures the FastAPI app +# ------------------------------------------------------------------------------ +def create_app() -> FastAPI: + + # App init + app = FastAPI( + title=settings.APP_NAME, + version=settings.APP_VERSION, + ) + + # Routers + app.include_router(about_router) + app.include_router(backup_router) + app.include_router(health_router) + app.include_router(login_router) + app.include_router(hosts_router) + app.include_router(aliases_router) + app.include_router(dns_router) + app.include_router(dhcp_router) + + # CORS + cors_origins = [ + f"http://localhost:{settings.HTTP_PORT}", + f"http://127.0.0.1:{settings.HTTP_PORT}", + # Aggiungi qui eventuali host reali: + # "http://miohost:8000", "https://dominio.tld" + ] + app.add_middleware( + CORSMiddleware, + allow_origins=cors_origins, + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_headers=["Content-Type", "Authorization"], + allow_credentials=True, + ) + + # Security headers (GRGR -> to be enabled in production) + # app.add_middleware(SecurityHeadersMiddleware) + + # Session/Auth middleware (funzionale) + app.middleware("http")(session_middleware) + + # Route per file del frontend + app.add_api_route("/", home, methods=["GET"]) + app.add_api_route("/css/variables.css", css_variables, methods=["GET"]) + app.add_api_route("/css/layout.css", css_layout, methods=["GET"]) + app.add_api_route("/js/common.js", js_common, methods=["GET"]) + app.add_api_route("/js/services.js", js_services, methods=["GET"]) + app.add_api_route("/favicon.ico", favicon, methods=["GET"]) + + return app diff --git a/backend/db/aliases.py b/backend/db/aliases.py index 4c5a7cd..2852ff4 100644 --- a/backend/db/aliases.py +++ b/backend/db/aliases.py @@ -8,11 +8,13 @@ import re import sqlite3 # Import local modules from backend.db.db import get_db, register_init -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Log from log.log import get_logger +# Logger initialization +logger = get_logger(__name__) + # ----------------------------- # Check Data Input # ----------------------------- @@ -151,7 +153,6 @@ def delete_alias(alias_id: int) -> bool: # ----------------------------- @register_init def init_db_alias_table(cur): - logger = get_logger(__name__) # ALIASES TABLE cur.execute(""" diff --git a/backend/db/db.py b/backend/db/db.py index d818501..608874b 100644 --- a/backend/db/db.py +++ b/backend/db/db.py @@ -3,14 +3,19 @@ # Import standard modules import os import sqlite3 -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Log from log.log import get_logger +# Logger initialization +logger = get_logger(__name__) + _connection = None _init_functions = [] +# ----------------------------- +# Register DB Init Function +# ----------------------------- def register_init(func): _init_functions.append(func) return func @@ -31,7 +36,7 @@ def get_db(): # Init Database # ----------------------------- def init_db(): - logger = get_logger(__name__) + logger.info("Starting DB Initialization") conn = get_db() diff --git a/backend/db/hosts.py b/backend/db/hosts.py index 6decded..eed87e9 100644 --- a/backend/db/hosts.py +++ b/backend/db/hosts.py @@ -8,11 +8,13 @@ import re import sqlite3 # Import local modules from backend.db.db import get_db, register_init -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Log from log.log import get_logger +# Logger initialization +logger = get_logger(__name__) + # Regex for MAC check MAC_RE = re.compile(r"^([0-9A-Fa-f]{2}([:\-])){5}([0-9A-Fa-f]{2})$") @@ -187,7 +189,6 @@ def delete_host(host_id: int) -> bool: # ----------------------------- @register_init def init_db_hosts_table(cur): - logger = get_logger(__name__) # SETTINGS TABLE cur.execute(""" diff --git a/backend/db/users.py b/backend/db/users.py index 9b74a45..111d870 100644 --- a/backend/db/users.py +++ b/backend/db/users.py @@ -7,11 +7,13 @@ import logging import os # Import local modules from backend.db.db import get_db, register_init -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Log from log.log import get_logger +# Logger initialization +logger = get_logger(__name__) + # ================================ # Create hash password # ================================ @@ -34,7 +36,6 @@ def get_user_by_username(username): # ----------------------------- @register_init def init_db_users_table(cur): - logger = get_logger(__name__) # USERS TABLE cur.execute(""" diff --git a/backend/main.py b/backend/main.py deleted file mode 100644 index 846847e..0000000 --- a/backend/main.py +++ /dev/null @@ -1,324 +0,0 @@ -# backend/main.py - -# import standard modules -from contextlib import asynccontextmanager -from fastapi import FastAPI, Request, status -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse, RedirectResponse, JSONResponse, Response -from starlette.middleware.base import BaseHTTPMiddleware -import logging -import os -# Import Routers -from backend.routes.about import router as about_router -from backend.routes.backup import router as backup_router -from backend.routes.health import router as health_router -from backend.routes.login import router as login_router -from backend.routes.hosts import router as hosts_router -from backend.routes.aliases import router as aliases_router -from backend.routes.dns import router as dns_router -from backend.routes.dhcp import router as dhcp_router -# Import Security -from backend.security import is_logged_in, apply_session -# Import Settings -from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger - -# ------------------------------------------------------------------------------ -# Logging setup -# ------------------------------------------------------------------------------ -setup_logging(level=settings.LOG_LEVEL, to_file=settings.LOG_TO_FILE, log_file=settings.LOG_FILE, log_access_file=settings.LOG_ACCESS_FILE) -logger = get_logger("backend.main") - -# ------------------------------------------------------------------------------ -# Welcome log -# ------------------------------------------------------------------------------ -def print_welcome(): - masked_secret = "****" if settings.SECRET_KEY else "undefined" - masked_admin_pwd = "****" if settings.ADMIN_PASSWORD else "undefined" - masked_admin_hash = "****" if settings.ADMIN_PASSWORD_HASH else "undefined" - - logger.info( - "%s starting | app_version=%s | baseimg_version=%s", - settings.APP_NAME, settings.APP_VERSION, settings.BASEIMG_VERSION - ) - logger.info( - "App settings: frontend=%s | port=%d | secret=%s", - settings.FRONTEND_DIR, settings.HTTP_PORT, masked_secret - ) - logger.info( - "Database: file=%s | reset=%s", - settings.DB_FILE, settings.DB_RESET - ) - logger.info( - "Log: level=%s, to_file=%s, file=%s", - settings.LOG_LEVEL, settings.LOG_TO_FILE, settings.LOG_FILE - ) - logger.info( - "Users: admin=%s | password=%s | hash=%s | hash_file=%s", - settings.ADMIN_USER, masked_admin_pwd, masked_admin_hash, settings.ADMIN_PASSWORD_HASH_FILE - ) - logger.info( - "DNS: host file=%s | alias file=%s | reverse file=%s", - settings.DNS_HOST_FILE, settings.DNS_ALIAS_FILE, settings.DNS_REVERSE_FILE - ) - logger.info( - "DHCP: ipv4 host file=%s | ipv4 leases file=%s | ipv6 host file=%s | ipv6 leases file=%s", - settings.DHCP4_HOST_FILE, settings.DHCP4_LEASES_FILE, settings.DHCP6_HOST_FILE, settings.DHCP6_LEASES_FILE - ) - -# ------------------------------------------------------------------------------ -# Shutdown log -# ------------------------------------------------------------------------------ -def print_goodbye(): - logger = get_logger("backend.main") - - logger.info( - "Application %s shutting down | app_version=%s", - settings.APP_NAME, settings.APP_VERSION - ) - -# ------------------------------------------------------------------------------ -# Lifespan for startup and shutdown events -# ------------------------------------------------------------------------------ -@asynccontextmanager -async def lifespan(app: FastAPI): - # STARTUP - print_welcome() - - try: - yield - finally: - # SHUTDOWN - print_goodbye() - -# ------------------------------------------------------------------------------ -# App init -# ------------------------------------------------------------------------------ -app = FastAPI( - title=settings.APP_NAME, - version=settings.APP_VERSION, - lifespan=lifespan, -) - -# ------------------------------------------------------------------------------ -# Routers -# ------------------------------------------------------------------------------ -app.include_router(about_router) -app.include_router(backup_router) -app.include_router(health_router) -app.include_router(login_router) -app.include_router(hosts_router) -app.include_router(aliases_router) -app.include_router(dns_router) -app.include_router(dhcp_router) - -# ------------------------------------------------------------------------------ -# CORS -# ------------------------------------------------------------------------------ -cors_origins = [ - f"http://localhost:{settings.HTTP_PORT}", - f"http://127.0.0.1:{settings.HTTP_PORT}", - # aggiungi qui host reali quando servi da hostname: - # "http://miohost:8000", "https://dominio.tld" -] -app.add_middleware( - CORSMiddleware, - allow_origins=cors_origins, - allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allow_headers=["Content-Type", "Authorization"], - allow_credentials=True, -) - -# ------------------------------------------------------------------------------ -# Security Headers middleware (basic hardening) -# ------------------------------------------------------------------------------ -class SecurityHeadersMiddleware(BaseHTTPMiddleware): - async def dispatch(self, request: Request, call_next): - response: Response = await call_next(request) - - # Hardening base - response.headers["X-Content-Type-Options"] = "nosniff" - response.headers["X-Frame-Options"] = "DENY" - response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin" - response.headers["Permissions-Policy"] = ( - "geolocation=(), microphone=(), camera=(), payment=(), usb=(), " - "accelerometer=(), autoplay=(), clipboard-read=(), clipboard-write=()" - ) - - # HSTS (richiede HTTPS) - response.headers["Strict-Transport-Security"] = ( - "max-age=31536000; includeSubDomains; preload" - ) - - # COOP / CORP isolano la pagina (protezione anti-XSS/XFO) - response.headers["Cross-Origin-Opener-Policy"] = "same-origin" - response.headers["Cross-Origin-Resource-Policy"] = "same-origin" - - # CSP rigida per produzione - response.headers["Content-Security-Policy"] = ( - "default-src 'self'; " - "base-uri 'self'; " - "object-src 'none'; " - "frame-ancestors 'none'; " - "img-src 'self' data:; " - "font-src 'self' data:; " - "style-src 'self'; " - "script-src 'self'; " - "connect-src 'self'; " - "manifest-src 'self'; " - "worker-src 'self'" - ) - return response - -# GRGR -> to be enabled in production -#app.add_middleware(SecurityHeadersMiddleware) - -# ------------------------------------------------------------------------------ -# Public paths -# ------------------------------------------------------------------------------ -PUBLIC_PATHS = ( - "/login", - "/api/login", - "/logout", - "/api/logout", - "/about", - "/api/health", - "/docs", - "/openapi.json", -) - -STATIC_PREFIXES = ( - "/css", - "/js", - "/static", -) - -STATIC_SUFFIXES = (".js", ".css", ".png", ".jpg", ".jpeg", ".ico", ".svg", ".map") - -# ------------------------------------------------------------------------------ -# Session / Auth middleware -# ------------------------------------------------------------------------------ -@app.middleware("http") -async def session_middleware(request: Request, call_next): - path = request.url.path - method = request.method.upper() - - # 1) Always let CORS preflight through (browsers send OPTIONS before real requests) - if method == "OPTIONS": - return await call_next(request) - - # 2) Skip public endpoints (login/logout/about/health/docs/openapi) - if path.startswith(PUBLIC_PATHS): - return await call_next(request) - - # 3) Skip static assets - if path.startswith(STATIC_PREFIXES) or path.endswith(STATIC_SUFFIXES): - return await call_next(request) - - # 4) Read session token from cookie (adjust name if different) - token = request.cookies.get("session") - - # 5) Check authentication (your function should validate the cookie/session) - authenticated = is_logged_in(request) - - # 6) Protect JSON APIs - if path.startswith("/api"): - if not authenticated: - logger.warning("API access denied - not logged in: %s %s", method, path) - return JSONResponse( - status_code=status.HTTP_401_UNAUTHORIZED, - headers={"WWW-Authenticate": "Session"}, - content={ - "detail": { - "code": "UNAUTHORIZED", - "status": "failure", - "message": "Unauthorized", - "path": path, - } - }, - ) - - # Optionally attach user info to request.state for downstream handlers - # request.state.user = - - # Call the downstream route/handler - response = await call_next(request) - - # Apply sliding expiration only on successful responses (2xx) and if a token exists - if token and 200 <= response.status_code < 300: - apply_session(response, username=None, token=token) - return response - - # 7) Protect HTML pages (non-API): redirect unauthenticated users to login - if not authenticated: - # 303 See Other avoids reusing POST/other methods - return RedirectResponse("/login", status_code=status.HTTP_303_SEE_OTHER) - - # 8) Authenticated HTML request ? proceed - response = await call_next(request) - - # 9) Apply sliding expiration only on successful responses (2xx) - if token and 200 <= response.status_code < 300: - apply_session(response, username=None, token=token) - - return response - -# ------------------------------------------------------------------------------ -# FRONTEND (FileResponse): pages and assets -# ------------------------------------------------------------------------------ -# Homepage -@app.get("/") -def home(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "hosts.html")) - -# CSS variables -@app.get("/css/variables.css") -def css_variables(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "css/variables.css")) - -# CSS Layout -@app.get("/css/layout.css") -def css_layout(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "css/layout.css")) - -# JS Common -@app.get("/js/common.js") -def js_common(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "js/common.js")) - -# JS Services -@app.get("/js/services.js") -def js_services(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "js/services.js")) - -# favicon -@app.get("/favicon.ico") -def favicon(request: Request): - return FileResponse(os.path.join(settings.FRONTEND_DIR, "favicon.ico")) - -# ------------------------------------------------------------------------------ -# Entry-point -# ------------------------------------------------------------------------------ -if __name__ == "__main__": - import uvicorn - - # Uvicorn config da settings con fallback - host = getattr(settings, "HTTP_HOST", "0.0.0.0") - port = int(getattr(settings, "HTTP_PORT", 8000)) - reload_flag = bool(getattr(settings, "DEV_RELOAD", False)) - - logger.info(f"Server running on http://{host}:{port} (reload={reload_flag})") - - uvicorn.run( - app, - host=host, - port=port, - reload=reload_flag, - proxy_headers=True, - forwarded_allow_ips="*", - log_level=(settings.LOG_LEVEL or "info").lower(), - #access_log=True, - log_config=None, - # workers=1, # GRGR in prod valuta gunicorn+uvicorn workers - ) diff --git a/backend/routes/aliases.py b/backend/routes/aliases.py index be7c2c5..cd0f686 100644 --- a/backend/routes/aliases.py +++ b/backend/routes/aliases.py @@ -14,10 +14,12 @@ from backend.db.aliases import ( update_alias, delete_alias ) -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -48,7 +50,6 @@ def api_get_aliases(request: Request): return aliases or [] except Exception as e: - logger = get_logger("aliases") logger.exception("Error getting list alias %s", str(e).strip()) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -84,7 +85,6 @@ def api_get_alias(request: Request, alias_id: int): return alias except Exception as e: - logger = get_logger("aliases") logger.exception("Error adding alias %s: %s", alias_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -141,7 +141,6 @@ def api_add_alias(request: Request, data: dict): raise httpe except Exception as e: - logger = get_logger("aliases") logger.exception("Error adding alias: %s", str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -196,7 +195,6 @@ def api_update_alias(request: Request, data: dict, alias_id: int): ) except Exception as e: - logger = get_logger("aliases") logger.exception("Error updating alias %s: %s", alias_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -251,7 +249,6 @@ def api_delete_alias(request: Request, alias_id: int): ) except Exception as e: - logger = get_logger("aliases") logger.exception("Error deleting alias %s: %s", alias_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( diff --git a/backend/routes/backup.py b/backend/routes/backup.py index 20df6b9..31d86e9 100644 --- a/backend/routes/backup.py +++ b/backend/routes/backup.py @@ -10,8 +10,12 @@ import ipaddress import time # Import local modules from backend.db.hosts import get_hosts -# Import Settings +# Import Settings & Logging from settings.settings import settings +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -54,7 +58,6 @@ async def api_dns_reload(request: Request): except Exception as err: took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 - logger = get_logger("hosts") logger.exception("Error executing backup: %s", str(e).strip()) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, diff --git a/backend/routes/dhcp.py b/backend/routes/dhcp.py index 14158bf..73fe0e8 100644 --- a/backend/routes/dhcp.py +++ b/backend/routes/dhcp.py @@ -12,10 +12,12 @@ from pathlib import Path import time # Import local modules from backend.db.hosts import get_hosts -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -80,7 +82,6 @@ async def api_dhcp_reload(request: Request): ) except Exception as err: - logger = get_logger("dhcp") logger.exception("Error reloading DHCP: %s", str(err).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -183,7 +184,6 @@ def api_dhcp_leases(request: Request): ) except Exception as err: - logger = get_logger("dhcp") logger.exception("Error reading DHCP leases: %s", str(err).strip()) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, diff --git a/backend/routes/dns.py b/backend/routes/dns.py index 6cd51f1..c260865 100644 --- a/backend/routes/dns.py +++ b/backend/routes/dns.py @@ -11,10 +11,12 @@ import time # Import local modules from backend.db.hosts import get_hosts from backend.db.aliases import get_aliases -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -74,7 +76,6 @@ async def api_dns_reload(request: Request): ) except Exception as err: - logger = get_logger("dns") logger.exception("Error reloading DNS: %s", str(err).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 diff --git a/backend/routes/health.py b/backend/routes/health.py index 574f7e6..bf9cc3f 100644 --- a/backend/routes/health.py +++ b/backend/routes/health.py @@ -5,10 +5,12 @@ from fastapi import APIRouter import sqlite3 import time import os -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -40,7 +42,7 @@ def health(): db_size = round(os.path.getsize(settings.DB_FILE) / (1024 * 1024), 2) except Exception as err: - get_logger("health").exception("Database health check failed: " + str(err).strip()) + logger.exception("Database health check failed: " + str(err).strip()) db_status = "error" db_version = None diff --git a/backend/routes/hosts.py b/backend/routes/hosts.py index 15c0368..bcb26d0 100644 --- a/backend/routes/hosts.py +++ b/backend/routes/hosts.py @@ -14,10 +14,12 @@ from backend.db.hosts import ( update_host, delete_host ) -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Logging -from log.log import setup_logging, get_logger +from log.log import get_logger + +# Logger initialization +logger = get_logger(__name__) # Create Router router = APIRouter() @@ -48,7 +50,6 @@ def api_get_hosts(request: Request): return hosts or [] except Exception as e: - logger = get_logger("hosts") logger.exception("Error getting list host %s", str(e).strip()) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -84,7 +85,6 @@ def api_get_host(request: Request, host_id: int): return host except Exception as e: - logger = get_logger("hosts") logger.exception("Error adding host %s: %s", host_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -141,7 +141,6 @@ def api_add_host(request: Request, data: dict): raise httpe except Exception as e: - logger = get_logger("hosts") logger.exception("Error adding host: %s", str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -196,7 +195,6 @@ def api_update_host(request: Request, data: dict, host_id: int): ) except Exception as e: - logger = get_logger("hosts") logger.exception("Error updating host %s: %s", host_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( @@ -251,7 +249,6 @@ def api_delete_host(request: Request, host_id: int): ) except Exception as e: - logger = get_logger("hosts") logger.exception("Error deleting host %s: %s", host_id, str(e).strip()) took_ms = (time.monotonic_ns() - start_ns) / 1_000_000 raise HTTPException( diff --git a/backend/security.py b/backend/security.py index 5974114..69b49ce 100644 --- a/backend/security.py +++ b/backend/security.py @@ -7,18 +7,20 @@ from fastapi import Request, HTTPException from itsdangerous import TimestampSigner # Import local modules from backend.db.users import get_user_by_username -# Import Settings +# Import Settings & Logging from settings.settings import settings -# Import Log from log.log import get_logger +# Logger initialization +logger = get_logger(__name__) + signer = TimestampSigner(settings.SECRET_KEY) # ----------------------------- # Verify Login # ----------------------------- def verify_login(username, password): - logger = get_logger(__name__) + user = get_user_by_username(username) if not user: logger.error("Login failed - user %s not found", username) @@ -39,7 +41,6 @@ def verify_login(username, password): # creates or renew the cookie # ---------------------------- def apply_session(response, username: str | None = None, token: str | None = None): - logger = get_logger(__name__) # First Login if username is not None and token is None: @@ -68,6 +69,7 @@ def apply_session(response, username: str | None = None, token: str | None = Non # check session cookie # ----------------------------- def is_logged_in(request: Request) -> bool: + token = request.cookies.get("session") if not token: return False @@ -81,7 +83,6 @@ def is_logged_in(request: Request) -> bool: # Close Session # ----------------------------- def close_session(response): - logger = get_logger(__name__) response.delete_cookie( key="session", diff --git a/log/log.py b/log/log.py index fa0b77a..899b179 100644 --- a/log/log.py +++ b/log/log.py @@ -151,11 +151,6 @@ def setup_logging(level: str = "INFO", to_file: bool = False, log_file: Optional config = build_log_config(level=level, to_file=to_file, log_file=log_file, log_access_file=log_access_file) logging.config.dictConfig(config) - logging.getLogger("main").info( - "Logging configured (level=%s, to_file=%s, log_file=%s, log_access_file=%s)", - level.upper(), to_file, log_file, log_access_file - ) - _INITIALIZED = True # ---------------------------------------------------------