Implement configuration management, drag-and-drop functionality, and logging utilities for WebDrop Bridge
This commit is contained in:
parent
04ef84cf9a
commit
6bef2f6119
9 changed files with 1154 additions and 0 deletions
100
src/webdrop_bridge/utils/logging.py
Normal file
100
src/webdrop_bridge/utils/logging.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
"""Logging configuration and utilities for WebDrop Bridge."""
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
|
||||
def setup_logging(
|
||||
name: str = "webdrop_bridge",
|
||||
level: str = "INFO",
|
||||
log_file: Optional[Path] = None,
|
||||
fmt: Optional[str] = None,
|
||||
) -> logging.Logger:
|
||||
"""Configure application-wide logging.
|
||||
|
||||
Sets up both console and file logging (if enabled). All loggers in the
|
||||
application should use this configured root logger.
|
||||
|
||||
Args:
|
||||
name: Logger name (typically module name or app name)
|
||||
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
||||
log_file: Optional path to log file. If provided, logs will be written
|
||||
to this file in addition to console
|
||||
fmt: Optional custom format string. If None, uses default format.
|
||||
Default: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
|
||||
Returns:
|
||||
logging.Logger: Configured logger instance
|
||||
|
||||
Raises:
|
||||
ValueError: If log_file path is invalid or can't be created
|
||||
KeyError: If level is not a valid logging level
|
||||
"""
|
||||
# Validate logging level
|
||||
try:
|
||||
numeric_level = getattr(logging, level.upper())
|
||||
except AttributeError as e:
|
||||
raise KeyError(f"Invalid logging level: {level}") from e
|
||||
|
||||
# Use default format if not provided
|
||||
if fmt is None:
|
||||
fmt = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
|
||||
# Create formatter
|
||||
formatter = logging.Formatter(fmt)
|
||||
|
||||
# Get or create logger
|
||||
logger = logging.getLogger(name)
|
||||
logger.setLevel(numeric_level)
|
||||
|
||||
# Remove existing handlers to avoid duplicates
|
||||
logger.handlers.clear()
|
||||
|
||||
# Add console handler
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(numeric_level)
|
||||
console_handler.setFormatter(formatter)
|
||||
logger.addHandler(console_handler)
|
||||
|
||||
# Add file handler if log file specified
|
||||
if log_file:
|
||||
try:
|
||||
# Create parent directories if needed
|
||||
log_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Use rotating file handler to manage log file size
|
||||
# Max 10 MB per file, keep 5 backups
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
log_file,
|
||||
maxBytes=10 * 1024 * 1024, # 10 MB
|
||||
backupCount=5,
|
||||
encoding="utf-8",
|
||||
)
|
||||
file_handler.setLevel(numeric_level)
|
||||
file_handler.setFormatter(formatter)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
except (OSError, IOError) as e:
|
||||
raise ValueError(f"Cannot write to log file {log_file}: {e}") from e
|
||||
|
||||
return logger
|
||||
|
||||
|
||||
def get_logger(name: str = __name__) -> logging.Logger:
|
||||
"""Get a logger instance for a module.
|
||||
|
||||
Convenience function to get a logger for a specific module.
|
||||
Use this in your modules to get properly named loggers.
|
||||
|
||||
Example:
|
||||
logger = get_logger(__name__)
|
||||
|
||||
Args:
|
||||
name: Logger name, typically __name__ of the calling module
|
||||
|
||||
Returns:
|
||||
logging.Logger: Logger instance for the given name
|
||||
"""
|
||||
return logging.getLogger(name)
|
||||
Loading…
Add table
Add a link
Reference in a new issue