| """ |
| Logging configuration: console (colored) + rotating file handler. |
| """ |
| import logging |
| import sys |
| from pathlib import Path |
| from logging.handlers import RotatingFileHandler |
|
|
| _LOG_FORMAT = "%(asctime)s | %(levelname)-8s | %(name)-30s | %(message)s" |
| _DATE_FORMAT = "%Y-%m-%d %H:%M:%S" |
|
|
|
|
| def setup_logger( |
| name: str = "sen2sr", |
| level: int = logging.INFO, |
| log_file: str | None = "sen2sr.log", |
| max_bytes: int = 10 * 1024 * 1024, |
| backup_count: int = 3, |
| ) -> logging.Logger: |
| """ |
| Create (or retrieve) a logger with a stream handler and optional file handler. |
| |
| Parameters |
| ---------- |
| name : Logger name (hierarchical, e.g. "sen2sr.pipeline"). |
| level : Logging level (default INFO). |
| log_file : Path to log file; None disables file logging. |
| max_bytes : Max file size before rotation. |
| backup_count: Number of rotated files to keep. |
| |
| Returns |
| ------- |
| Configured logging.Logger instance. |
| """ |
| logger = logging.getLogger(name) |
| if logger.handlers: |
| |
| return logger |
|
|
| logger.setLevel(level) |
| formatter = logging.Formatter(_LOG_FORMAT, datefmt=_DATE_FORMAT) |
|
|
| |
| console_handler = logging.StreamHandler(sys.stdout) |
| console_handler.setFormatter(formatter) |
| console_handler.setLevel(level) |
| logger.addHandler(console_handler) |
|
|
| |
| if log_file: |
| log_path = Path(log_file) |
| log_path.parent.mkdir(parents=True, exist_ok=True) |
| file_handler = RotatingFileHandler( |
| log_path, |
| maxBytes=max_bytes, |
| backupCount=backup_count, |
| encoding="utf-8", |
| ) |
| file_handler.setFormatter(formatter) |
| file_handler.setLevel(level) |
| logger.addHandler(file_handler) |
|
|
| return logger |
|
|
|
|
| def get_logger(name: str) -> logging.Logger: |
| """Convenience: return a child logger under the 'sen2sr' hierarchy.""" |
| return logging.getLogger(f"s2sr_pipe.{name}") |
|
|