feat: implement timezone-aware logging system

- Fix inconsistent timestamp formats in logs for easier troubleshooting
- All logging systems now respect Docker TZ environment variable (e.g., TZ=America/New_York)
- Add TimezoneAwareFormatter for Python's standard logging module
- Enhance _log function with robust timezone support and fallbacks
- Replace placeholder logging functions with centralized core.logging._log
- Support both zoneinfo (Python 3.9+) and pytz (older versions)
- Users now see consistent timezone formatting across all log outputs
This commit is contained in:
2025-09-14 09:45:32 -04:00
parent f4c56f6cbe
commit 17ef94ec4f
5 changed files with 100 additions and 14 deletions
+34 -3
View File
@@ -12,6 +12,7 @@ import logging
import logging.handlers
from pathlib import Path
from datetime import datetime, timezone, timedelta
from zoneinfo import ZoneInfo
from fastapi import FastAPI, HTTPException, BackgroundTasks, Request
from pydantic import BaseModel
from typing import Optional, Dict, Any, List, Set, Tuple
@@ -31,6 +32,37 @@ from clients.external_clients import ExternalClientManager
# Configuration & Logging
# ---------------------------
class TimezoneAwareFormatter(logging.Formatter):
"""Formatter that respects the container timezone"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.timezone = self._get_local_timezone()
def _get_local_timezone(self):
"""Get the local timezone, respecting TZ environment variable"""
tz_name = os.environ.get('TZ', 'UTC')
try:
# Try zoneinfo first (Python 3.9+)
return ZoneInfo(tz_name)
except ImportError:
# Fallback for older Python versions
try:
import pytz
return pytz.timezone(tz_name)
except:
# Final fallback to UTC
return timezone.utc
except:
# If zone name is invalid, fallback to UTC
return timezone.utc
def formatTime(self, record, datefmt=None):
dt = datetime.fromtimestamp(record.created, tz=self.timezone)
if datefmt:
return dt.strftime(datefmt)
return dt.isoformat(timespec='seconds')
def _setup_file_logging():
"""Setup file logging for NFOGuard"""
log_dir = Path("/app/data/logs")
@@ -43,9 +75,8 @@ def _setup_file_logging():
log_dir / "nfoguard.log", maxBytes=50*1024*1024, backupCount=3
)
formatter = logging.Formatter(
'[%(asctime)s] %(levelname)s: %(message)s',
datefmt='%Y-%m-%dT%H:%M:%S+00:00'
formatter = TimezoneAwareFormatter(
'[%(asctime)s] %(levelname)s: %(message)s'
)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)