chore: apply pending code updates
This commit is contained in:
@@ -724,9 +724,9 @@ async def add_series(
|
||||
if series_app and hasattr(series_app, 'loader'):
|
||||
try:
|
||||
year = series_app.loader.get_year(key)
|
||||
logger.info(f"Fetched year for {key}: {year}")
|
||||
logger.info("Fetched year for %s: %s", key, year)
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not fetch year for {key}: {e}")
|
||||
logger.warning("Could not fetch year for %s: %s", key, e)
|
||||
|
||||
# Create folder name with year if available
|
||||
if year:
|
||||
|
||||
@@ -91,7 +91,7 @@ async def check_database_health(db: AsyncSession) -> DatabaseHealth:
|
||||
message="Database connection successful",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Database health check failed: {e}")
|
||||
logger.error("Database health check failed: %s", e)
|
||||
return DatabaseHealth(
|
||||
status="unhealthy",
|
||||
connection_time_ms=0,
|
||||
@@ -121,7 +121,7 @@ async def check_filesystem_health() -> Dict[str, Any]:
|
||||
"message": "Filesystem check completed",
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Filesystem health check failed: {e}")
|
||||
logger.error("Filesystem health check failed: %s", e)
|
||||
return {
|
||||
"status": "unhealthy",
|
||||
"message": f"Filesystem check failed: {str(e)}",
|
||||
@@ -164,7 +164,7 @@ def get_system_metrics() -> SystemMetrics:
|
||||
uptime_seconds=uptime_seconds,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"System metrics collection failed: {e}")
|
||||
logger.error("System metrics collection failed: %s", e)
|
||||
raise HTTPException(
|
||||
status_code=500, detail=f"Failed to collect system metrics: {str(e)}"
|
||||
)
|
||||
@@ -236,7 +236,7 @@ async def detailed_health_check(
|
||||
startup_time=startup_time,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Detailed health check failed: {e}")
|
||||
logger.error("Detailed health check failed: %s", e)
|
||||
raise HTTPException(status_code=500, detail="Health check failed")
|
||||
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ async def get_missing_nfo(
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting missing NFOs: {e}", exc_info=True)
|
||||
logger.exception("Error getting missing NFOs: %s", e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to get missing NFOs: {str(e)}"
|
||||
@@ -334,7 +334,7 @@ async def check_nfo(
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking NFO for {serie_id}: {e}", exc_info=True)
|
||||
logger.exception("Error checking NFO for %s: %s", serie_id, e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Failed to check NFO: {str(e)}"
|
||||
@@ -429,7 +429,7 @@ async def create_nfo(
|
||||
except HTTPException:
|
||||
raise
|
||||
except TMDBAPIError as e:
|
||||
logger.warning(f"TMDB API error creating NFO for {serie_id}: {e}")
|
||||
logger.warning("TMDB API error creating NFO for %s: %s", serie_id, e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail=f"TMDB API error: {str(e)}"
|
||||
@@ -524,7 +524,7 @@ async def update_nfo(
|
||||
except HTTPException:
|
||||
raise
|
||||
except TMDBAPIError as e:
|
||||
logger.warning(f"TMDB API error updating NFO for {serie_id}: {e}")
|
||||
logger.warning("TMDB API error updating NFO for %s: %s", serie_id, e)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
||||
detail=f"TMDB API error: {str(e)}"
|
||||
|
||||
@@ -95,10 +95,10 @@ def setup_logging() -> Dict[str, logging.Logger]:
|
||||
# Log initial setup
|
||||
root_logger.info("=" * 80)
|
||||
root_logger.info("FastAPI Server Logging Initialized")
|
||||
root_logger.info(f"Log Level: {settings.log_level.upper()}")
|
||||
root_logger.info(f"Server Log: {server_log_file.absolute()}")
|
||||
root_logger.info(f"Error Log: {error_log_file.absolute()}")
|
||||
root_logger.info(f"Access Log: {access_log_file.absolute()}")
|
||||
root_logger.info("Log Level: %s", settings.log_level.upper())
|
||||
root_logger.info("Server Log: %s", server_log_file.absolute())
|
||||
root_logger.info("Error Log: %s", error_log_file.absolute())
|
||||
root_logger.info("Access Log: %s", access_log_file.absolute())
|
||||
root_logger.info("=" * 80)
|
||||
|
||||
return {
|
||||
|
||||
@@ -88,7 +88,7 @@ async def init_db() -> None:
|
||||
try:
|
||||
# Get database URL
|
||||
db_url = _get_database_url()
|
||||
logger.info(f"Initializing database: {db_url}")
|
||||
logger.info("Initializing database: %s", db_url)
|
||||
|
||||
# Build engine kwargs based on database type
|
||||
is_sqlite = "sqlite" in db_url
|
||||
@@ -143,7 +143,7 @@ async def init_db() -> None:
|
||||
logger.info("Database initialization complete")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize database: {e}")
|
||||
logger.error("Failed to initialize database: %s", e)
|
||||
raise
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ async def close_db() -> None:
|
||||
conn.commit()
|
||||
logger.info("SQLite WAL checkpoint completed")
|
||||
except Exception as e:
|
||||
logger.warning(f"WAL checkpoint failed (non-critical): {e}")
|
||||
logger.warning("WAL checkpoint failed (non-critical): %s", e)
|
||||
|
||||
if _engine:
|
||||
logger.info("Closing async database engine...")
|
||||
@@ -188,7 +188,7 @@ async def close_db() -> None:
|
||||
logger.info("Database connections closed")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error closing database: {e}")
|
||||
logger.error("Error closing database: %s", e)
|
||||
|
||||
|
||||
def get_engine() -> AsyncEngine:
|
||||
|
||||
@@ -98,7 +98,7 @@ async def initialize_database(
|
||||
seed_data=True
|
||||
)
|
||||
if result["success"]:
|
||||
logger.info(f"Database initialized: {result['schema_version']}")
|
||||
logger.info("Database initialized: %s", result['schema_version'])
|
||||
"""
|
||||
if engine is None:
|
||||
engine = get_engine()
|
||||
@@ -117,7 +117,7 @@ async def initialize_database(
|
||||
if create_schema:
|
||||
tables = await create_database_schema(engine)
|
||||
result["tables_created"] = tables
|
||||
logger.info(f"Created {len(tables)} tables")
|
||||
logger.info("Created %s tables", len(tables))
|
||||
|
||||
# Validate schema if requested
|
||||
if validate_schema:
|
||||
@@ -148,7 +148,7 @@ async def initialize_database(
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Database initialization failed: {e}", exc_info=True)
|
||||
logger.exception("Database initialization failed: %s", e)
|
||||
raise RuntimeError(f"Failed to initialize database: {e}") from e
|
||||
|
||||
|
||||
@@ -194,14 +194,14 @@ async def create_database_schema(
|
||||
created_tables = [t for t in new_tables if t not in existing_tables]
|
||||
|
||||
if created_tables:
|
||||
logger.info(f"Created tables: {', '.join(created_tables)}")
|
||||
logger.info("Created tables: %s", ', '.join(created_tables))
|
||||
else:
|
||||
logger.info("All tables already exist")
|
||||
|
||||
return new_tables
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create schema: {e}", exc_info=True)
|
||||
logger.exception("Failed to create schema: %s", e)
|
||||
raise RuntimeError(f"Schema creation failed: {e}") from e
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ async def validate_database_schema(
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Schema validation failed: {e}", exc_info=True)
|
||||
logger.exception("Schema validation failed: %s", e)
|
||||
return {
|
||||
"valid": False,
|
||||
"missing_tables": [],
|
||||
@@ -342,7 +342,7 @@ async def get_schema_version(engine: Optional[AsyncEngine] = None) -> str:
|
||||
return "unknown"
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get schema version: {e}")
|
||||
logger.error("Failed to get schema version: %s", e)
|
||||
return "error"
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ async def seed_initial_data(engine: Optional[AsyncEngine] = None) -> None:
|
||||
logger.info("Data will be populated via normal application usage")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to seed initial data: {e}", exc_info=True)
|
||||
logger.exception("Failed to seed initial data: %s", e)
|
||||
raise
|
||||
|
||||
|
||||
@@ -484,12 +484,12 @@ async def check_database_health(
|
||||
f"(connectivity: {result['connectivity_ms']}ms)"
|
||||
)
|
||||
else:
|
||||
logger.warning(f"Database health issues: {result['issues']}")
|
||||
logger.warning("Database health issues: %s", result['issues'])
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Database health check failed: {e}")
|
||||
logger.error("Database health check failed: %s", e)
|
||||
return {
|
||||
"healthy": False,
|
||||
"accessible": False,
|
||||
@@ -547,13 +547,13 @@ async def create_database_backup(
|
||||
backup_path = backup_dir / f"aniworld_{timestamp}.db"
|
||||
|
||||
try:
|
||||
logger.info(f"Creating database backup: {backup_path}")
|
||||
logger.info("Creating database backup: %s", backup_path)
|
||||
shutil.copy2(db_path, backup_path)
|
||||
logger.info(f"Backup created successfully: {backup_path}")
|
||||
logger.info("Backup created successfully: %s", backup_path)
|
||||
return backup_path
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create backup: {e}", exc_info=True)
|
||||
logger.exception("Failed to create backup: %s", e)
|
||||
raise RuntimeError(f"Backup creation failed: {e}") from e
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class AnimeSeriesService:
|
||||
db.add(series)
|
||||
await db.flush()
|
||||
await db.refresh(series)
|
||||
logger.info(f"Created anime series: {series.name} (key={series.key}, year={year})")
|
||||
logger.info("Created anime series: %s (key=%s, year=%s)", series.name, series.key, year)
|
||||
return series
|
||||
|
||||
@staticmethod
|
||||
@@ -205,7 +205,7 @@ class AnimeSeriesService:
|
||||
|
||||
await db.flush()
|
||||
await db.refresh(series)
|
||||
logger.info(f"Updated anime series: {series.name} (id={series_id})")
|
||||
logger.info("Updated anime series: %s (id=%s)", series.name, series_id)
|
||||
return series
|
||||
|
||||
@staticmethod
|
||||
@@ -226,7 +226,7 @@ class AnimeSeriesService:
|
||||
)
|
||||
deleted = result.rowcount > 0
|
||||
if deleted:
|
||||
logger.info(f"Deleted anime series with id={series_id}")
|
||||
logger.info("Deleted anime series with id=%s", series_id)
|
||||
return deleted
|
||||
|
||||
@staticmethod
|
||||
@@ -701,7 +701,7 @@ class EpisodeService:
|
||||
updated_count += 1
|
||||
|
||||
await db.flush()
|
||||
logger.info(f"Bulk marked {updated_count} episodes as downloaded")
|
||||
logger.info("Bulk marked %s episodes as downloaded", updated_count)
|
||||
|
||||
return updated_count
|
||||
|
||||
@@ -850,7 +850,7 @@ class DownloadQueueService:
|
||||
|
||||
await db.flush()
|
||||
await db.refresh(item)
|
||||
logger.debug(f"Set error on download queue item {item_id}")
|
||||
logger.debug("Set error on download queue item %s", item_id)
|
||||
return item
|
||||
|
||||
@staticmethod
|
||||
@@ -869,7 +869,7 @@ class DownloadQueueService:
|
||||
)
|
||||
deleted = result.rowcount > 0
|
||||
if deleted:
|
||||
logger.info(f"Deleted download queue item with id={item_id}")
|
||||
logger.info("Deleted download queue item with id=%s", item_id)
|
||||
return deleted
|
||||
|
||||
@staticmethod
|
||||
@@ -931,7 +931,7 @@ class DownloadQueueService:
|
||||
)
|
||||
|
||||
count = result.rowcount
|
||||
logger.info(f"Bulk deleted {count} download queue items")
|
||||
logger.info("Bulk deleted %s download queue items", count)
|
||||
|
||||
return count
|
||||
|
||||
@@ -952,7 +952,7 @@ class DownloadQueueService:
|
||||
"""
|
||||
result = await db.execute(delete(DownloadQueueItem))
|
||||
count = result.rowcount
|
||||
logger.info(f"Cleared all {count} download queue items")
|
||||
logger.info("Cleared all %s download queue items", count)
|
||||
return count
|
||||
|
||||
|
||||
@@ -1006,7 +1006,7 @@ class UserSessionService:
|
||||
db.add(session)
|
||||
await db.flush()
|
||||
await db.refresh(session)
|
||||
logger.info(f"Created user session: {session_id}")
|
||||
logger.info("Created user session: %s", session_id)
|
||||
return session
|
||||
|
||||
@staticmethod
|
||||
@@ -1093,7 +1093,7 @@ class UserSessionService:
|
||||
|
||||
session.revoke()
|
||||
await db.flush()
|
||||
logger.info(f"Revoked user session: {session_id}")
|
||||
logger.info("Revoked user session: %s", session_id)
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
@@ -1115,7 +1115,7 @@ class UserSessionService:
|
||||
)
|
||||
)
|
||||
count = result.rowcount
|
||||
logger.info(f"Cleaned up {count} expired sessions")
|
||||
logger.info("Cleaned up %s expired sessions", count)
|
||||
return count
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -97,10 +97,10 @@ async def _check_incomplete_series_on_startup(background_loader) -> None:
|
||||
logger.info("All series data is complete. No background loading needed.")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking incomplete series: {e}", exc_info=True)
|
||||
logger.exception("Error checking incomplete series: %s", e)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to check incomplete series on startup: {e}", exc_info=True)
|
||||
logger.exception("Failed to check incomplete series on startup: %s", e)
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
|
||||
@@ -74,7 +74,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle authentication errors (401)."""
|
||||
logger.warning(
|
||||
f"Authentication error: {exc.message}",
|
||||
"Authentication error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -94,7 +95,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle authorization errors (403)."""
|
||||
logger.warning(
|
||||
f"Authorization error: {exc.message}",
|
||||
"Authorization error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -114,7 +116,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle validation errors (422)."""
|
||||
logger.info(
|
||||
f"Validation error: {exc.message}",
|
||||
"Validation error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -134,7 +137,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle bad request errors (400)."""
|
||||
logger.info(
|
||||
f"Bad request error: {exc.message}",
|
||||
"Bad request error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -154,7 +158,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle not found errors (404)."""
|
||||
logger.info(
|
||||
f"Not found error: {exc.message}",
|
||||
"Not found error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -174,7 +179,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle conflict errors (409)."""
|
||||
logger.info(
|
||||
f"Conflict error: {exc.message}",
|
||||
"Conflict error: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -194,7 +200,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle rate limit errors (429)."""
|
||||
logger.warning(
|
||||
f"Rate limit exceeded: {exc.message}",
|
||||
"Rate limit exceeded: %s",
|
||||
exc.message,
|
||||
extra={"details": exc.details, "path": str(request.url.path)},
|
||||
)
|
||||
return JSONResponse(
|
||||
@@ -214,7 +221,8 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle generic API exceptions."""
|
||||
logger.error(
|
||||
f"API error: {exc.message}",
|
||||
"API error: %s",
|
||||
exc.message,
|
||||
extra={
|
||||
"error_code": exc.error_code,
|
||||
"details": exc.details,
|
||||
@@ -238,12 +246,13 @@ def register_exception_handlers(app: FastAPI) -> None:
|
||||
) -> JSONResponse:
|
||||
"""Handle unexpected exceptions."""
|
||||
logger.exception(
|
||||
f"Unexpected error: {str(exc)}",
|
||||
"Unexpected error: %s",
|
||||
str(exc),
|
||||
extra={"path": str(request.url.path)},
|
||||
)
|
||||
|
||||
# Log full traceback for debugging
|
||||
logger.debug(f"Traceback: {traceback.format_exc()}")
|
||||
logger.debug("Traceback: %s", traceback.format_exc())
|
||||
|
||||
# Return generic error response for security
|
||||
return JSONResponse(
|
||||
|
||||
@@ -315,11 +315,11 @@ class RequestSanitizationMiddleware(BaseHTTPMiddleware):
|
||||
None if malicious content detected, sanitized value otherwise
|
||||
"""
|
||||
if self.check_sql_injection and self._check_sql_injection(value):
|
||||
logger.warning(f"Potential SQL injection detected: {value[:100]}")
|
||||
logger.warning("Potential SQL injection detected: %s", value[:100])
|
||||
return None
|
||||
|
||||
if self.check_xss and self._check_xss(value):
|
||||
logger.warning(f"Potential XSS detected: {value[:100]}")
|
||||
logger.warning("Potential XSS detected: %s", value[:100])
|
||||
return None
|
||||
|
||||
return value
|
||||
@@ -341,7 +341,7 @@ class RequestSanitizationMiddleware(BaseHTTPMiddleware):
|
||||
content_type
|
||||
and not any(ct in content_type for ct in self.allowed_content_types)
|
||||
):
|
||||
logger.warning(f"Unsupported content type: {content_type}")
|
||||
logger.warning("Unsupported content type: %s", content_type)
|
||||
return JSONResponse(
|
||||
status_code=415,
|
||||
content={"detail": "Unsupported Media Type"},
|
||||
@@ -350,7 +350,7 @@ class RequestSanitizationMiddleware(BaseHTTPMiddleware):
|
||||
# Check request size
|
||||
content_length = request.headers.get("content-length")
|
||||
if content_length and int(content_length) > self.max_request_size:
|
||||
logger.warning(f"Request too large: {content_length} bytes")
|
||||
logger.warning("Request too large: %s bytes", content_length)
|
||||
return JSONResponse(
|
||||
status_code=413,
|
||||
content={"detail": "Request Entity Too Large"},
|
||||
@@ -361,7 +361,7 @@ class RequestSanitizationMiddleware(BaseHTTPMiddleware):
|
||||
if isinstance(value, str):
|
||||
sanitized = self._sanitize_value(value)
|
||||
if sanitized is None:
|
||||
logger.warning(f"Malicious query parameter detected: {key}")
|
||||
logger.warning("Malicious query parameter detected: %s", key)
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
content={"detail": "Malicious request detected"},
|
||||
@@ -372,7 +372,7 @@ class RequestSanitizationMiddleware(BaseHTTPMiddleware):
|
||||
if isinstance(value, str):
|
||||
sanitized = self._sanitize_value(value)
|
||||
if sanitized is None:
|
||||
logger.warning(f"Malicious path parameter detected: {key}")
|
||||
logger.warning("Malicious path parameter detected: %s", key)
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
content={"detail": "Malicious request detected"},
|
||||
|
||||
@@ -945,12 +945,12 @@ class AnimeService:
|
||||
|
||||
# Get the serie from in-memory cache
|
||||
if not hasattr(self._app, 'list') or not hasattr(self._app.list, 'keyDict'):
|
||||
logger.warning(f"Series list not available for episode sync: {series_key}")
|
||||
logger.warning("Series list not available for episode sync: %s", series_key)
|
||||
return 0
|
||||
|
||||
serie = self._app.list.keyDict.get(series_key)
|
||||
if not serie:
|
||||
logger.warning(f"Series not found in memory for episode sync: {series_key}")
|
||||
logger.warning("Series not found in memory for episode sync: %s", series_key)
|
||||
return 0
|
||||
|
||||
episodes_added = 0
|
||||
@@ -959,7 +959,7 @@ class AnimeService:
|
||||
# Get series from database
|
||||
series_db = await AnimeSeriesService.get_by_key(db, series_key)
|
||||
if not series_db:
|
||||
logger.warning(f"Series not found in database: {series_key}")
|
||||
logger.warning("Series not found in database: %s", series_key)
|
||||
return 0
|
||||
|
||||
# Get existing episodes from database
|
||||
@@ -1000,7 +1000,7 @@ class AnimeService:
|
||||
try:
|
||||
await self._broadcast_series_updated(series_key)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to broadcast series update: {e}")
|
||||
logger.warning("Failed to broadcast series update: %s", e)
|
||||
|
||||
return episodes_added
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ class BackgroundLoaderService:
|
||||
"""
|
||||
# Check if task already exists
|
||||
if key in self.active_tasks:
|
||||
logger.debug(f"Task for series {key} already exists, skipping")
|
||||
logger.debug("Task for series %s already exists, skipping", key)
|
||||
return
|
||||
|
||||
task = SeriesLoadingTask(
|
||||
@@ -202,7 +202,7 @@ class BackgroundLoaderService:
|
||||
self.active_tasks[key] = task
|
||||
await self.task_queue.put(task)
|
||||
|
||||
logger.info(f"Added loading task for series: {key}")
|
||||
logger.info("Added loading task for series: %s", key)
|
||||
|
||||
# Broadcast initial status
|
||||
await self._broadcast_status(task)
|
||||
@@ -277,7 +277,7 @@ class BackgroundLoaderService:
|
||||
Args:
|
||||
worker_id: Unique identifier for this worker instance
|
||||
"""
|
||||
logger.info(f"Background worker {worker_id} started processing tasks")
|
||||
logger.info("Background worker %s started processing tasks", worker_id)
|
||||
|
||||
while not self._shutdown:
|
||||
try:
|
||||
@@ -301,14 +301,14 @@ class BackgroundLoaderService:
|
||||
# No task available, continue loop
|
||||
continue
|
||||
except asyncio.CancelledError:
|
||||
logger.info(f"Worker {worker_id} task cancelled")
|
||||
logger.info("Worker %s task cancelled", worker_id)
|
||||
break
|
||||
except Exception as e:
|
||||
logger.exception(f"Error in background worker {worker_id}: {e}")
|
||||
logger.exception("Error in background worker %s: %s", worker_id, e)
|
||||
# Continue processing other tasks
|
||||
continue
|
||||
|
||||
logger.info(f"Background worker {worker_id} stopped")
|
||||
logger.info("Background worker %s stopped", worker_id)
|
||||
|
||||
async def _load_series_data(self, task: SeriesLoadingTask) -> None:
|
||||
"""Load all missing data for a series.
|
||||
@@ -362,10 +362,10 @@ class BackgroundLoaderService:
|
||||
# Broadcast completion
|
||||
await self._broadcast_status(task)
|
||||
|
||||
logger.info(f"Successfully loaded all data for series: {task.key}")
|
||||
logger.info("Successfully loaded all data for series: %s", task.key)
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Error loading series data: {e}")
|
||||
logger.exception("Error loading series data: %s", e)
|
||||
task.status = LoadingStatus.FAILED
|
||||
task.error = str(e)
|
||||
task.completed_at = datetime.now(timezone.utc)
|
||||
@@ -400,14 +400,14 @@ class BackgroundLoaderService:
|
||||
|
||||
# Check if directory exists
|
||||
if series_dir.exists() and series_dir.is_dir():
|
||||
logger.debug(f"Found series directory: {series_dir}")
|
||||
logger.debug("Found series directory: %s", series_dir)
|
||||
return series_dir
|
||||
else:
|
||||
logger.warning(f"Series directory not found: {series_dir}")
|
||||
logger.warning("Series directory not found: %s", series_dir)
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error finding series directory for {task.key}: {e}")
|
||||
logger.error("Error finding series directory for %s: %s", task.key, e)
|
||||
return None
|
||||
|
||||
async def _scan_series_episodes(self, series_dir: Path, task: SeriesLoadingTask) -> Dict[str, List[str]]:
|
||||
@@ -440,13 +440,13 @@ class BackgroundLoaderService:
|
||||
|
||||
if episodes:
|
||||
episodes_by_season[season_name] = episodes
|
||||
logger.debug(f"Found {len(episodes)} episodes in {season_name}")
|
||||
logger.debug("Found %s episodes in %s", len(episodes), season_name)
|
||||
|
||||
logger.info(f"Scanned {len(episodes_by_season)} seasons for {task.key}")
|
||||
logger.info("Scanned %s seasons for %s", len(episodes_by_season), task.key)
|
||||
return episodes_by_season
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error scanning episodes for {task.key}: {e}")
|
||||
logger.error("Error scanning episodes for %s: %s", task.key, e)
|
||||
return {}
|
||||
|
||||
async def _load_episodes(self, task: SeriesLoadingTask, db: Any) -> None:
|
||||
@@ -466,7 +466,7 @@ class BackgroundLoaderService:
|
||||
# Find series directory without full rescan
|
||||
series_dir = await self._find_series_directory(task)
|
||||
if not series_dir:
|
||||
logger.error(f"Cannot load episodes - directory not found for {task.key}")
|
||||
logger.error("Cannot load episodes - directory not found for %s", task.key)
|
||||
task.progress["episodes"] = False
|
||||
return
|
||||
|
||||
@@ -474,7 +474,7 @@ class BackgroundLoaderService:
|
||||
episodes_by_season = await self._scan_series_episodes(series_dir, task)
|
||||
|
||||
if not episodes_by_season:
|
||||
logger.warning(f"No episodes found for {task.key}")
|
||||
logger.warning("No episodes found for %s", task.key)
|
||||
task.progress["episodes"] = False
|
||||
return
|
||||
|
||||
@@ -489,10 +489,10 @@ class BackgroundLoaderService:
|
||||
series_db.loading_status = "loading_episodes"
|
||||
await db.commit()
|
||||
|
||||
logger.info(f"Episodes loaded for series: {task.key} ({len(episodes_by_season)} seasons)")
|
||||
logger.info("Episodes loaded for series: %s (%s seasons)", task.key, len(episodes_by_season))
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to load episodes for {task.key}: {e}")
|
||||
logger.exception("Failed to load episodes for %s: %s", task.key, e)
|
||||
raise
|
||||
|
||||
async def _load_nfo_and_images(self, task: SeriesLoadingTask, db: Any) -> bool:
|
||||
@@ -521,7 +521,7 @@ class BackgroundLoaderService:
|
||||
|
||||
# Check if NFO already exists
|
||||
if self.series_app.nfo_service.has_nfo(task.folder):
|
||||
logger.info(f"NFO already exists for {task.key}, skipping creation")
|
||||
logger.info("NFO already exists for %s, skipping creation", task.key)
|
||||
|
||||
# Update task progress
|
||||
task.progress["nfo"] = True
|
||||
@@ -536,19 +536,19 @@ class BackgroundLoaderService:
|
||||
if not series_db.has_nfo:
|
||||
series_db.has_nfo = True
|
||||
series_db.nfo_created_at = datetime.now(timezone.utc)
|
||||
logger.info(f"Updated database with existing NFO for {task.key}")
|
||||
logger.info("Updated database with existing NFO for %s", task.key)
|
||||
if not series_db.logo_loaded:
|
||||
series_db.logo_loaded = True
|
||||
if not series_db.images_loaded:
|
||||
series_db.images_loaded = True
|
||||
await db.commit()
|
||||
|
||||
logger.info(f"Existing NFO found and database updated for series: {task.key}")
|
||||
logger.info("Existing NFO found and database updated for series: %s", task.key)
|
||||
return False
|
||||
|
||||
# NFO doesn't exist, create it
|
||||
await self._broadcast_status(task, "Generating NFO file...")
|
||||
logger.info(f"Creating new NFO for {task.key}")
|
||||
logger.info("Creating new NFO for %s", task.key)
|
||||
|
||||
# Use existing NFOService to create NFO with all images
|
||||
# This reuses all existing TMDB API logic and image downloading
|
||||
@@ -577,11 +577,11 @@ class BackgroundLoaderService:
|
||||
series_db.loading_status = "loading_nfo"
|
||||
await db.commit()
|
||||
|
||||
logger.info(f"NFO and images created and loaded for series: {task.key}")
|
||||
logger.info("NFO and images created and loaded for series: %s", task.key)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to load NFO/images for {task.key}: {e}")
|
||||
logger.exception("Failed to load NFO/images for %s: %s", task.key, e)
|
||||
# Don't fail the entire task if NFO fails
|
||||
task.progress["nfo"] = False
|
||||
task.progress["logo"] = False
|
||||
@@ -611,7 +611,7 @@ class BackgroundLoaderService:
|
||||
|
||||
# Scan for missing episodes using the targeted scan method
|
||||
# This populates the episodeDict without triggering a full rescan
|
||||
logger.info(f"Scanning missing episodes for {task.key}")
|
||||
logger.info("Scanning missing episodes for %s", task.key)
|
||||
missing_episodes = self.series_app.serie_scanner.scan_single_series(
|
||||
key=task.key,
|
||||
folder=task.folder
|
||||
@@ -628,12 +628,12 @@ class BackgroundLoaderService:
|
||||
# Notify anime_service to sync episodes to database
|
||||
# Use sync_single_series_after_scan which gets data from serie_scanner.keyDict
|
||||
if self.anime_service:
|
||||
logger.debug(f"Calling anime_service.sync_single_series_after_scan for {task.key}")
|
||||
logger.debug("Calling anime_service.sync_single_series_after_scan for %s", task.key)
|
||||
await self.anime_service.sync_single_series_after_scan(task.key)
|
||||
else:
|
||||
logger.warning(f"anime_service not available, episodes will not be synced to DB for {task.key}")
|
||||
logger.warning("anime_service not available, episodes will not be synced to DB for %s", task.key)
|
||||
else:
|
||||
logger.info(f"No missing episodes found for {task.key}")
|
||||
logger.info("No missing episodes found for %s", task.key)
|
||||
|
||||
# Update series status in database
|
||||
from src.server.database.service import AnimeSeriesService
|
||||
@@ -648,7 +648,7 @@ class BackgroundLoaderService:
|
||||
task.progress["episodes"] = True
|
||||
|
||||
except Exception as e:
|
||||
logger.exception(f"Failed to scan missing episodes for {task.key}: {e}")
|
||||
logger.exception("Failed to scan missing episodes for %s: %s", task.key, e)
|
||||
task.progress["episodes"] = False
|
||||
|
||||
async def _broadcast_status(
|
||||
|
||||
@@ -170,14 +170,17 @@ class InMemoryCacheBackend(CacheBackend):
|
||||
"""Get value from cache."""
|
||||
async with self._lock:
|
||||
if key not in self.cache:
|
||||
logger.debug("Cache miss for key: %s", key)
|
||||
return None
|
||||
|
||||
item = self.cache[key]
|
||||
|
||||
if self._is_expired(item):
|
||||
logger.debug("Cache expired for key: %s", key)
|
||||
del self.cache[key]
|
||||
return None
|
||||
|
||||
logger.debug("Cache hit for key: %s", key)
|
||||
return item["value"]
|
||||
|
||||
async def set(
|
||||
@@ -196,6 +199,7 @@ class InMemoryCacheBackend(CacheBackend):
|
||||
"expiry": expiry,
|
||||
"created": datetime.utcnow(),
|
||||
}
|
||||
logger.debug("Cached key: %s (ttl=%s)", key, ttl)
|
||||
return True
|
||||
|
||||
async def delete(self, key: str) -> bool:
|
||||
@@ -203,7 +207,9 @@ class InMemoryCacheBackend(CacheBackend):
|
||||
async with self._lock:
|
||||
if key in self.cache:
|
||||
del self.cache[key]
|
||||
logger.debug("Deleted cache key: %s", key)
|
||||
return True
|
||||
logger.debug("Cache delete skipped; key not found: %s", key)
|
||||
return False
|
||||
|
||||
async def exists(self, key: str) -> bool:
|
||||
@@ -223,6 +229,7 @@ class InMemoryCacheBackend(CacheBackend):
|
||||
"""Clear all cached values."""
|
||||
async with self._lock:
|
||||
self.cache.clear()
|
||||
logger.debug("Cleared in-memory cache")
|
||||
return True
|
||||
|
||||
async def get_many(self, keys: List[str]) -> Dict[str, Any]:
|
||||
@@ -281,13 +288,14 @@ class RedisCacheBackend(CacheBackend):
|
||||
import aioredis
|
||||
|
||||
self._redis = await aioredis.create_redis_pool(self.redis_url)
|
||||
logger.debug("Connected to Redis at %s", self.redis_url)
|
||||
except ImportError:
|
||||
logger.error(
|
||||
"aioredis not installed. Install with: pip install aioredis"
|
||||
)
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to connect to Redis: {e}")
|
||||
logger.error("Failed to connect to Redis: %s", e)
|
||||
raise
|
||||
|
||||
return self._redis
|
||||
@@ -308,7 +316,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return pickle.loads(data)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis get error: {e}")
|
||||
logger.error("Redis get error: %s", e)
|
||||
return None
|
||||
|
||||
async def set(
|
||||
@@ -327,7 +335,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis set error: {e}")
|
||||
logger.error("Redis set error: %s", e)
|
||||
return False
|
||||
|
||||
async def delete(self, key: str) -> bool:
|
||||
@@ -338,7 +346,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return result > 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis delete error: {e}")
|
||||
logger.error("Redis delete error: %s", e)
|
||||
return False
|
||||
|
||||
async def exists(self, key: str) -> bool:
|
||||
@@ -348,7 +356,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return await redis.exists(self._make_key(key))
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis exists error: {e}")
|
||||
logger.error("Redis exists error: %s", e)
|
||||
return False
|
||||
|
||||
async def clear(self) -> bool:
|
||||
@@ -361,7 +369,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis clear error: {e}")
|
||||
logger.error("Redis clear error: %s", e)
|
||||
return False
|
||||
|
||||
async def get_many(self, keys: List[str]) -> Dict[str, Any]:
|
||||
@@ -379,7 +387,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis get_many error: {e}")
|
||||
logger.error("Redis get_many error: %s", e)
|
||||
return {}
|
||||
|
||||
async def set_many(
|
||||
@@ -392,7 +400,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis set_many error: {e}")
|
||||
logger.error("Redis set_many error: %s", e)
|
||||
return False
|
||||
|
||||
async def delete_pattern(self, pattern: str) -> int:
|
||||
@@ -409,7 +417,7 @@ class RedisCacheBackend(CacheBackend):
|
||||
return 0
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Redis delete_pattern error: {e}")
|
||||
logger.error("Redis delete_pattern error: %s", e)
|
||||
return 0
|
||||
|
||||
async def close(self) -> None:
|
||||
|
||||
@@ -8,6 +8,7 @@ This service handles:
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import shutil
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -15,6 +16,8 @@ from typing import Dict, List, Optional
|
||||
|
||||
from src.server.models.config import AppConfig, ConfigUpdate, ValidationResult
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConfigServiceError(Exception):
|
||||
"""Base exception for configuration service errors."""
|
||||
@@ -136,7 +139,7 @@ class ConfigService:
|
||||
self.create_backup()
|
||||
except ConfigBackupError as e:
|
||||
# Log but don't fail save operation
|
||||
print(f"Warning: Failed to create backup: {e}")
|
||||
logger.warning("Failed to create backup: %s", e)
|
||||
|
||||
# Save configuration with version
|
||||
data = config.model_dump()
|
||||
|
||||
@@ -342,7 +342,7 @@ async def perform_nfo_scan_if_needed(progress_service=None):
|
||||
if not settings.tmdb_api_key
|
||||
else "Skipped - NFO features disabled"
|
||||
)
|
||||
logger.info(f"NFO scan skipped: {message}")
|
||||
logger.info("NFO scan skipped: %s", message)
|
||||
|
||||
if progress_service:
|
||||
await progress_service.complete_progress(
|
||||
|
||||
@@ -151,7 +151,7 @@ class EmailNotificationService:
|
||||
start_tls=True,
|
||||
)
|
||||
|
||||
logger.info(f"Email notification sent to {to_address}")
|
||||
logger.info("Email notification sent to %s", to_address)
|
||||
return True
|
||||
|
||||
except ImportError:
|
||||
@@ -160,7 +160,7 @@ class EmailNotificationService:
|
||||
)
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send email notification: {e}")
|
||||
logger.error("Failed to send email notification: %s", e)
|
||||
return False
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ class WebhookNotificationService:
|
||||
timeout=aiohttp.ClientTimeout(total=self.timeout),
|
||||
) as response:
|
||||
if response.status < 400:
|
||||
logger.info(f"Webhook notification sent to {url}")
|
||||
logger.info("Webhook notification sent to %s", url)
|
||||
return True
|
||||
else:
|
||||
logger.warning(
|
||||
@@ -213,9 +213,9 @@ class WebhookNotificationService:
|
||||
)
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
logger.warning(f"Webhook timeout (attempt {attempt + 1}/{self.max_retries}): {url}")
|
||||
logger.warning("Webhook timeout (attempt %s/%s): %s", attempt + 1, self.max_retries, url)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send webhook (attempt {attempt + 1}/{self.max_retries}): {e}")
|
||||
logger.error("Failed to send webhook (attempt %s/%s): %s", attempt + 1, self.max_retries, e)
|
||||
|
||||
if attempt < self.max_retries - 1:
|
||||
await asyncio.sleep(2 ** attempt) # Exponential backoff
|
||||
@@ -436,7 +436,7 @@ class NotificationService:
|
||||
await self.in_app_service.add_notification(notification)
|
||||
results["in_app"] = True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send in-app notification: {e}")
|
||||
logger.error("Failed to send in-app notification: %s", e)
|
||||
results["in_app"] = False
|
||||
|
||||
# Send email notification
|
||||
@@ -452,7 +452,7 @@ class NotificationService:
|
||||
)
|
||||
results["email"] = success
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send email notification: {e}")
|
||||
logger.error("Failed to send email notification: %s", e)
|
||||
results["email"] = False
|
||||
|
||||
# Send webhook notifications
|
||||
@@ -476,7 +476,7 @@ class NotificationService:
|
||||
success = await self.webhook_service.send_webhook(str(url), payload)
|
||||
webhook_results.append(success)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send webhook notification to {url}: {e}")
|
||||
logger.error("Failed to send webhook notification to %s: %s", url, e)
|
||||
webhook_results.append(False)
|
||||
|
||||
results["webhook"] = all(webhook_results) if webhook_results else False
|
||||
|
||||
@@ -82,7 +82,7 @@ class LogManager:
|
||||
log_path = self.log_dir / log_file
|
||||
|
||||
if not log_path.exists():
|
||||
logger.warning(f"Log file not found: {log_file}")
|
||||
logger.warning("Log file not found: %s", log_file)
|
||||
return False
|
||||
|
||||
stat = log_path.stat()
|
||||
@@ -99,10 +99,10 @@ class LogManager:
|
||||
# Compress the rotated file
|
||||
self._compress_log(rotated_path)
|
||||
|
||||
logger.info(f"Rotated log file: {log_file} -> {rotated_name}")
|
||||
logger.info("Rotated log file: %s -> %s", log_file, rotated_name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to rotate log file {log_file}: {e}")
|
||||
logger.error("Failed to rotate log file %s: %s", log_file, e)
|
||||
return False
|
||||
|
||||
def _compress_log(self, log_path: Path) -> bool:
|
||||
@@ -122,10 +122,10 @@ class LogManager:
|
||||
shutil.copyfileobj(f_in, f_out)
|
||||
|
||||
log_path.unlink()
|
||||
logger.debug(f"Compressed log file: {log_path.name}")
|
||||
logger.debug("Compressed log file: %s", log_path.name)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to compress log {log_path}: {e}")
|
||||
logger.error("Failed to compress log %s: %s", log_path, e)
|
||||
return False
|
||||
|
||||
def archive_old_logs(
|
||||
@@ -160,10 +160,10 @@ class LogManager:
|
||||
f"Failed to archive {log_file.filename}: {e}"
|
||||
)
|
||||
|
||||
logger.info(f"Archived {archived_count} old log files")
|
||||
logger.info("Archived %s old log files", archived_count)
|
||||
return archived_count
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to archive logs: {e}")
|
||||
logger.error("Failed to archive logs: %s", e)
|
||||
return 0
|
||||
|
||||
def search_logs(
|
||||
@@ -209,7 +209,7 @@ class LogManager:
|
||||
)
|
||||
return results
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to search logs: {e}")
|
||||
logger.error("Failed to search logs: %s", e)
|
||||
return {}
|
||||
|
||||
def export_logs(
|
||||
@@ -243,7 +243,7 @@ class LogManager:
|
||||
arcname=log_file.filename,
|
||||
)
|
||||
|
||||
logger.info(f"Exported logs to: {tar_path}")
|
||||
logger.info("Exported logs to: %s", tar_path)
|
||||
return True
|
||||
else:
|
||||
# Concatenate all logs
|
||||
@@ -253,10 +253,10 @@ class LogManager:
|
||||
with open(log_file.path, "r") as in_f:
|
||||
out_f.write(in_f.read())
|
||||
|
||||
logger.info(f"Exported logs to: {output_path}")
|
||||
logger.info("Exported logs to: %s", output_path)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to export logs: {e}")
|
||||
logger.error("Failed to export logs: %s", e)
|
||||
return False
|
||||
|
||||
def get_log_stats(self) -> Dict[str, Any]:
|
||||
@@ -294,7 +294,7 @@ class LogManager:
|
||||
"newest_file": log_files[0].filename,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get log stats: {e}")
|
||||
logger.error("Failed to get log stats: %s", e)
|
||||
return {}
|
||||
|
||||
def cleanup_logs(
|
||||
@@ -330,16 +330,16 @@ class LogManager:
|
||||
log_file.path.unlink()
|
||||
total_size -= log_file.size_bytes
|
||||
deleted_count += 1
|
||||
logger.debug(f"Deleted log file: {log_file.filename}")
|
||||
logger.debug("Deleted log file: %s", log_file.filename)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Failed to delete {log_file.filename}: {e}"
|
||||
)
|
||||
|
||||
logger.info(f"Cleaned up {deleted_count} log files")
|
||||
logger.info("Cleaned up %s log files", deleted_count)
|
||||
return deleted_count
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to cleanup logs: {e}")
|
||||
logger.error("Failed to cleanup logs: %s", e)
|
||||
return 0
|
||||
|
||||
def set_log_level(self, logger_name: str, level: str) -> bool:
|
||||
@@ -357,10 +357,10 @@ class LogManager:
|
||||
target_logger = logging.getLogger(logger_name)
|
||||
target_logger.setLevel(log_level)
|
||||
|
||||
logger.info(f"Set {logger_name} log level to {level}")
|
||||
logger.info("Set %s log level to %s", logger_name, level)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to set log level: {e}")
|
||||
logger.error("Failed to set log level: %s", e)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -416,9 +416,9 @@ def cleanup_old_logs(log_dir: Union[str, Path],
|
||||
try:
|
||||
if log_file.stat().st_mtime < cutoff_time:
|
||||
log_file.unlink()
|
||||
logger.info(f"Deleted old log file: {log_file}")
|
||||
logger.info("Deleted old log file: %s", log_file)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to delete log file {log_file}: {e}")
|
||||
logger.error("Failed to delete log file %s: %s", log_file, e)
|
||||
|
||||
|
||||
# Initialize default logging configuration
|
||||
|
||||
@@ -161,7 +161,7 @@ class MetricsCollector:
|
||||
Duration in seconds.
|
||||
"""
|
||||
if timer_name not in self._timers:
|
||||
logger.warning(f"Timer {timer_name} not started")
|
||||
logger.warning("Timer %s not started", timer_name)
|
||||
return 0.0
|
||||
|
||||
duration = time.time() - self._timers[timer_name]
|
||||
|
||||
@@ -60,7 +60,7 @@ class SystemUtilities:
|
||||
path=path,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get disk usage for {path}: {e}")
|
||||
logger.error("Failed to get disk usage for %s: %s", path, e)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -93,7 +93,7 @@ class SystemUtilities:
|
||||
|
||||
return disk_infos
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get all disk usage: {e}")
|
||||
logger.error("Failed to get all disk usage: %s", e)
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
@@ -115,7 +115,7 @@ class SystemUtilities:
|
||||
|
||||
path = Path(directory)
|
||||
if not path.exists():
|
||||
logger.warning(f"Directory not found: {directory}")
|
||||
logger.warning("Directory not found: %s", directory)
|
||||
return 0
|
||||
|
||||
deleted_count = 0
|
||||
@@ -130,16 +130,16 @@ class SystemUtilities:
|
||||
try:
|
||||
file_path.unlink()
|
||||
deleted_count += 1
|
||||
logger.debug(f"Deleted file: {file_path}")
|
||||
logger.debug("Deleted file: %s", file_path)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"Failed to delete {file_path}: {e}"
|
||||
)
|
||||
|
||||
logger.info(f"Cleaned up {deleted_count} files from {directory}")
|
||||
logger.info("Cleaned up %s files from %s", deleted_count, directory)
|
||||
return deleted_count
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to cleanup directory {directory}: {e}")
|
||||
logger.error("Failed to cleanup directory %s: %s", directory, e)
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
@@ -171,12 +171,12 @@ class SystemUtilities:
|
||||
f"Deleted empty directory: {dir_path}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug(f"Cannot delete {dir_path}: {e}")
|
||||
logger.debug("Cannot delete %s: %s", dir_path, e)
|
||||
|
||||
logger.info(f"Cleaned up {deleted_count} empty directories")
|
||||
logger.info("Cleaned up %s empty directories", deleted_count)
|
||||
return deleted_count
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to cleanup empty directories: {e}")
|
||||
logger.error("Failed to cleanup empty directories: %s", e)
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
@@ -201,7 +201,7 @@ class SystemUtilities:
|
||||
|
||||
return total_size
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get directory size for {directory}: {e}")
|
||||
logger.error("Failed to get directory size for %s: %s", directory, e)
|
||||
return 0
|
||||
|
||||
@staticmethod
|
||||
@@ -232,7 +232,7 @@ class SystemUtilities:
|
||||
),
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get process info for {pid}: {e}")
|
||||
logger.error("Failed to get process info for %s: %s", pid, e)
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
@@ -260,7 +260,7 @@ class SystemUtilities:
|
||||
|
||||
return processes
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get all processes: {e}")
|
||||
logger.error("Failed to get all processes: %s", e)
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
@@ -285,7 +285,7 @@ class SystemUtilities:
|
||||
"python_version": platform.python_version(),
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get system info: {e}")
|
||||
logger.error("Failed to get system info: %s", e)
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
@@ -308,7 +308,7 @@ class SystemUtilities:
|
||||
"dropped_out": net_io.dropout,
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get network info: {e}")
|
||||
logger.error("Failed to get network info: %s", e)
|
||||
return {}
|
||||
|
||||
@staticmethod
|
||||
@@ -330,7 +330,7 @@ class SystemUtilities:
|
||||
dest_path = Path(dest)
|
||||
|
||||
if not src_path.exists():
|
||||
logger.error(f"Source file not found: {src}")
|
||||
logger.error("Source file not found: %s", src)
|
||||
return False
|
||||
|
||||
# Create temporary file
|
||||
@@ -342,10 +342,10 @@ class SystemUtilities:
|
||||
# Atomic rename
|
||||
temp_path.replace(dest_path)
|
||||
|
||||
logger.debug(f"Atomically copied {src} to {dest}")
|
||||
logger.debug("Atomically copied %s to %s", src, dest)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to copy file {src} to {dest}: {e}")
|
||||
logger.error("Failed to copy file %s to %s: %s", src, dest, e)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user