From 88d526aa0069ff903e2708fb3ba7b474c0d976ed Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Mon, 9 Feb 2026 15:47:24 -0600 Subject: [PATCH] log rotate --- email-worker/logger.py | 78 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 10 deletions(-) diff --git a/email-worker/logger.py b/email-worker/logger.py index 89bfb19..7af1ee1 100644 --- a/email-worker/logger.py +++ b/email-worker/logger.py @@ -1,21 +1,79 @@ #!/usr/bin/env python3 """ -Structured logging for email worker +Structured logging for email worker with Daily Rotation """ +import os +import sys +import logging import threading +from logging.handlers import TimedRotatingFileHandler from datetime import datetime +# Konfiguration +LOG_DIR = "/var/log/email-worker" +LOG_FILE = os.path.join(LOG_DIR, "worker.log") + +# Logger initialisieren +logger = logging.getLogger("unified-worker") +logger.setLevel(logging.INFO) +logger.propagate = False + +# Formatierung definieren: [Timestamp] [Level] [Thread] Nachricht +# Hinweis: worker_name wird in der Funktion 'log' manuell eingefügt +formatter = logging.Formatter( + '[%(asctime)s] [%(levelname)s] [%(threadName)s] %(message)s', + datefmt='%Y-%m-%d %H:%M:%S' +) + +# 1. Console Handler (damit 'docker logs' weiterhin etwas anzeigt) +console_handler = logging.StreamHandler(sys.stdout) +console_handler.setFormatter(formatter) +logger.addHandler(console_handler) + +# 2. File Handler mit täglicher Rotation +# Prüfen, ob das Verzeichnis schreibbar ist (durch Docker Volume Mount) +if os.path.exists(LOG_DIR): + try: + # when="midnight": Rotiert jede Nacht um 00:00 Uhr + # backupCount=30: Behält Logs für 30 Tage + file_handler = TimedRotatingFileHandler( + LOG_FILE, + when="midnight", + interval=1, + backupCount=30, + encoding='utf-8' + ) + file_handler.setFormatter(formatter) + # Suffix für rotierte Dateien: worker.log.2023-10-27 + file_handler.suffix = "%Y-%m-%d" + logger.addHandler(file_handler) + except Exception as e: + print(f"⚠ Logging Setup Error: Could not create file handler: {e}") def log(message: str, level: str = 'INFO', worker_name: str = 'unified-worker'): """ - Structured logging with timestamp and thread info - - Args: - message: Log message - level: Log level (INFO, WARNING, ERROR, SUCCESS) - worker_name: Name of the worker component + Structured logging with timestamp and thread info. + Drop-In Replacement for original print-based logging. """ - timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S') - thread_name = threading.current_thread().name - print(f"[{timestamp}] [{level}] [{worker_name}] [{thread_name}] {message}", flush=True) + # Mapping von String-Levels zu logging Konstanten + lvl_map = { + 'DEBUG': logging.DEBUG, + 'INFO': logging.INFO, + 'WARNING': logging.WARNING, + 'ERROR': logging.ERROR, + 'CRITICAL': logging.CRITICAL, + 'SUCCESS': logging.INFO # 'SUCCESS' gibt es im Standard nicht, wir nutzen INFO + } + + log_level = lvl_map.get(level.upper(), logging.INFO) + + # Prefix für SUCCESS Level manuell hinzufügen, da es im Standard-Logging fehlt + prefix = "" + if level.upper() == 'SUCCESS': + prefix = "[SUCCESS] " + + # Den worker_name in die Nachricht integrieren + final_message = f"[{worker_name}] {prefix}{message}" + + logger.log(log_level, final_message) \ No newline at end of file