Server: PID-based logging - only master logs startup

- Only master PID logs blocklist loading, pack scanning, etc.
- Worker processes stay silent during startup
- Much cleaner logs
This commit is contained in:
SashegDev
2026-05-07 17:45:36 +00:00
parent d7a928cce4
commit f6fbb66cdc
+31 -13
View File
@@ -1,5 +1,6 @@
import re import re
import logging import logging
import os
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from datetime import datetime from datetime import datetime
from pathlib import Path from pathlib import Path
@@ -17,6 +18,12 @@ from uvicorn.protocols.http.httptools_impl import HttpToolsProtocol
logging.getLogger("httpx").setLevel(logging.WARNING) logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("httpcore").setLevel(logging.WARNING) logging.getLogger("httpcore").setLevel(logging.WARNING)
# PID for logging (only master logs startup)
MASTER_PID = os.getpid()
def is_master() -> bool:
return os.getpid() == MASTER_PID
from pack_manager import DATA_DIR, scan_pack, get_cached_manifest, PACKS_DIR from pack_manager import DATA_DIR, scan_pack, get_cached_manifest, PACKS_DIR
from models import PackMeta from models import PackMeta
from middleware import LoggingMiddleware from middleware import LoggingMiddleware
@@ -64,10 +71,11 @@ async def lifespan(app: FastAPI):
if BLOCKLIST_CACHE_FILE.exists(): if BLOCKLIST_CACHE_FILE.exists():
try: try:
cached_ips = set(BLOCKLIST_CACHE_FILE.read_text().strip().splitlines()) cached_ips = set(BLOCKLIST_CACHE_FILE.read_text().strip().splitlines())
if cached_ips: if cached_ips and is_master():
logger.info(f"Loaded {len(cached_ips)} IPs from blocklist cache") logger.info(f"Loaded {len(cached_ips)} IPs from blocklist cache")
except Exception as e: except Exception as e:
logger.warning(f"Failed to load blocklist cache: {e}") if is_master():
logger.warning(f"Failed to load blocklist cache: {e}")
# If no cache, download (only one worker will do this) # If no cache, download (only one worker will do this)
if not cached_ips: if not cached_ips:
@@ -84,20 +92,22 @@ async def lifespan(app: FastAPI):
cached_ips = mw.load_public_blocklists() cached_ips = mw.load_public_blocklists()
if cached_ips: if cached_ips:
BLOCKLIST_CACHE_FILE.write_text("\n".join(cached_ips)) BLOCKLIST_CACHE_FILE.write_text("\n".join(cached_ips))
logger.info(f"Downloaded and saved {len(cached_ips)} IPs to blocklist cache") if is_master():
logger.info(f"Downloaded and saved {len(cached_ips)} IPs to blocklist cache")
except BlockingIOError: except BlockingIOError:
# Another process is downloading - wait for cache # Another process is downloading - wait for cache
pass pass
finally: finally:
lock_fd.close() lock_fd.close()
except Exception as e: except Exception as e:
logger.warning(f"Lock error: {e}") if is_master():
logger.warning(f"Lock error: {e}")
# Re-read cache after download # Re-read cache after download
if BLOCKLIST_CACHE_FILE.exists() and not cached_ips: if BLOCKLIST_CACHE_FILE.exists() and not cached_ips:
try: try:
cached_ips = set(BLOCKLIST_CACHE_FILE.read_text().strip().splitlines()) cached_ips = set(BLOCKLIST_CACHE_FILE.read_text().strip().splitlines())
if cached_ips: if cached_ips and is_master():
logger.info(f"Loaded {len(cached_ips)} IPs from blocklist cache (after wait)") logger.info(f"Loaded {len(cached_ips)} IPs from blocklist cache (after wait)")
except Exception: except Exception:
pass pass
@@ -105,7 +115,8 @@ async def lifespan(app: FastAPI):
all_blocked.update(cached_ips) all_blocked.update(cached_ips)
mw.set_ip_config(blocked=all_blocked) mw.set_ip_config(blocked=all_blocked)
logger.info(f"IP blocklist loaded: {len(all_blocked)} IPs") if is_master():
logger.info(f"IP blocklist loaded: {len(all_blocked)} IPs")
# Determine environment # Determine environment
if args.test: if args.test:
@@ -115,7 +126,8 @@ async def lifespan(app: FastAPI):
else: else:
env = "production" env = "production"
logger.info(f"Starting ZernMC Launcher Server (environment: {env})") if is_master():
logger.info(f"Starting ZernMC Launcher Server (environment: {env})")
# Create directories if they don't exist # Create directories if they don't exist
BUILDS_DIR.mkdir(exist_ok=True) BUILDS_DIR.mkdir(exist_ok=True)
@@ -129,21 +141,26 @@ async def lifespan(app: FastAPI):
yield yield
return return
logger.info("Scanning packs on startup...") if is_master():
logger.info("Scanning packs on startup...")
pack_dirs = [p for p in PACKS_DIR.iterdir() if p.is_dir()] pack_dirs = [p for p in PACKS_DIR.iterdir() if p.is_dir()]
if not pack_dirs: if not pack_dirs:
logger.warning(f"No packs found in directory: {PACKS_DIR}") if is_master():
logger.warning(f"No packs found in directory: {PACKS_DIR}")
else: else:
for pack_dir in pack_dirs: for pack_dir in pack_dirs:
try: try:
meta = await scan_pack(pack_dir.name) meta = await scan_pack(pack_dir.name)
logger.info(f"Pack scanned successfully: {pack_dir.name} v{meta.version} ({len(meta.files)} files)") if is_master():
logger.info(f"Pack scanned successfully: {pack_dir.name} v{meta.version} ({len(meta.files)} files)")
except Exception as e: except Exception as e:
logger.error(f"Failed to scan pack: {pack_dir.name} - {e}", exc_info=True) if is_master():
logger.error(f"Failed to scan pack: {pack_dir.name} - {e}", exc_info=True)
logger.info("All packs ready. Server is running.") if is_master():
logger.info("All packs ready. Server is running.")
# Initialize proxy client # Initialize proxy client
global proxy_client global proxy_client
@@ -155,7 +172,8 @@ async def lifespan(app: FastAPI):
if proxy_client: if proxy_client:
await proxy_client.aclose() await proxy_client.aclose()
logger.info("Server shutting down...") if is_master():
logger.info("Server shutting down...")