Fix authentication log config

This commit is contained in:
Jet Li 2025-02-01 07:02:11 +00:00
parent 59e3c27b3f
commit 13171f16b7
8 changed files with 190 additions and 202 deletions

View File

@ -1,53 +1,54 @@
from loguru import logger as guru_logger from loguru import logger as guru_logger
from common.config.log_settings import log_settings from common.config.log_settings import log_settings
from typing import List from typing import Dict, Any
import socket import socket
import json
import logging
import threading import threading
class LoggerBase: class LoggerBase:
binded_loggers = {} binded_loggers = {} # Stores logger instances
loguru_sinks_added = set() # Tracks added log sinks
logger_lock = threading.Lock() logger_lock = threading.Lock()
def __init__( def __init__(self, logger_name: str, extra_fields: Dict[str, Any] = None) -> None:
self, logger_name: str, extra_fileds: dict[str, any]
) -> None:
self.__logger_name = logger_name self.__logger_name = logger_name
self.extra_fileds = extra_fileds self.extra_fields = extra_fields or {}
with LoggerBase.logger_lock: with LoggerBase.logger_lock:
# ✅ **If already created, reuse it** to prevent duplicates
if self.__logger_name in LoggerBase.binded_loggers: if self.__logger_name in LoggerBase.binded_loggers:
self.logger = LoggerBase.binded_loggers[self.__logger_name] self.logger = LoggerBase.binded_loggers[self.__logger_name]
return return
log_filename = ( log_filename = f"{log_settings.LOG_BASE_PATH}/{self.__logger_name}.log"
log_settings.LOG_PATH_BASE + "/" + self.__logger_name + ".log"
)
log_retention = log_settings.LOG_RETENTION
log_rotation = log_settings.LOG_ROTATION
log_level = "INFO"
log_message_format = "{message}"
guru_logger.add( # ✅ **Ensure Loguru sink is added only once**
sink=log_filename, if log_filename not in LoggerBase.loguru_sinks_added:
level=log_level, guru_logger.add(
retention=log_retention, sink=log_filename,
rotation=log_rotation, level="INFO",
format=log_message_format, retention=log_settings.LOG_RETENTION,
serialize=True, rotation=log_settings.LOG_ROTATION,
filter=lambda record: "extra" in record format="{message}",
and "topic" in record["extra"] serialize=True,
and record["extra"]["topic"] == self.__logger_name, filter=lambda record: "extra" in record
) and "topic" in record["extra"]
host_name = socket.gethostname() and record["extra"]["topic"] == self.__logger_name,
host_ip = socket.gethostbyname(host_name) )
self.logger = guru_logger.bind( LoggerBase.loguru_sinks_added.add(log_filename) # ✅ Mark as added
topic=self.__logger_name,
host_ip=host_ip, host_name = socket.gethostname()
host_name=host_name, host_ip = socket.gethostbyname(host_name)
)
with LoggerBase.logger_lock: # ✅ Bind the logger with topic and extra fields
self.logger = guru_logger.bind(
topic=self.__logger_name,
host_ip=host_ip,
host_name=host_name,
**self.extra_fields, # Include additional metadata
)
# ✅ Store reference to prevent duplicate instances
LoggerBase.binded_loggers[self.__logger_name] = self.logger LoggerBase.binded_loggers[self.__logger_name] = self.logger
async def log_event( async def log_event(
@ -56,15 +57,15 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
event: str, event: str,
properties: dict[str, any], properties: Dict[str, Any],
text: str = "" text: str = "",
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
receiver_id=receiver_id, receiver_id=receiver_id,
subject=subject, subject=subject,
event=event, event=event,
properties=properties properties=properties,
) )
local_logger.info(text) local_logger.info(text)
@ -75,7 +76,7 @@ class LoggerBase:
subject: str, subject: str,
exception: Exception, exception: Exception,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -83,7 +84,7 @@ class LoggerBase:
subject=subject, subject=subject,
event="exception", event="exception",
properties=properties, properties=properties,
exception=exception exception=exception,
) )
local_logger.exception(text) local_logger.exception(text)
@ -93,7 +94,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -110,7 +111,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -127,7 +128,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,

View File

@ -1,25 +0,0 @@
from .base_logger import LoggerBase
from common.config.app_settings import app_settings
import json
class BusinessMetricLogger(LoggerBase):
def __init__(self, business_metrics: dict[str, any] = {}) -> None:
extra_fileds = {}
if business_metrics:
extra_fileds.update(business_metrics)
super().__init__(
logger_name=app_settings.BUSINESS_METRIC_LOG,
extra_fileds=extra_fileds,
)
async def log_metrics(self, business_metrics: dict[str, any] = {}) -> None:
return await super().log_event(
sender_id="business_metric_manager",
receiver_id="business_metric_logger",
subject="metrics",
event="logging",
properties=business_metrics,
text="business metric logged"
)

View File

@ -1,14 +0,0 @@
from .base_logger import LoggerBase
from common.config.app_settings import app_settings
import json
class UserLogger(LoggerBase):
def __init__(self, user_activities: dict[str, any] = {}) -> None:
extra_fileds = {}
if user_activities:
extra_fileds.update(user_activities)
super().__init__(
logger_name=app_settings.USER_ACTIVITY_LOG, extra_fileds=extra_fileds
)

View File

@ -3,7 +3,7 @@ from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi from fastapi.openapi.utils import get_openapi
from webapi.providers import common from webapi.providers import common
from webapi.providers import logger from webapi.providers.logger import register_logger
from webapi.providers import router from webapi.providers import router
from webapi.providers import database from webapi.providers import database
@ -17,9 +17,9 @@ def create_app() -> FastAPI:
app = FreeleapsApp() app = FreeleapsApp()
register_logger()
register(app, exception_handler) register(app, exception_handler)
register(app, database) register(app, database)
register(app, logger)
register(app, router) register(app, router)
# register(app, scheduler) # register(app, scheduler)
register(app, common) register(app, common)

View File

@ -1,56 +1,47 @@
import logging import logging
import sys import sys
from loguru import logger from loguru import logger as guru_logger
from common.config.log_settings import log_settings
def register(app=None): def register_logger():
level = log_settings.LOG_LEVEL print("📢 Setting up logging interception...")
file_path = log_settings.LOG_PATH
retention = log_settings.LOG_RETENTION
rotation = log_settings.LOG_ROTATION
# intercept everything at the root logger # 🔴 **Ensure Uvicorn Logs Are Captured**
intercept_loggers = ["uvicorn", "uvicorn.access", "uvicorn.error", "fastapi"]
class InterceptHandler(logging.Handler):
def emit(self, record):
level = (
guru_logger.level(record.levelname).name
if guru_logger.level(record.levelname, None)
else record.levelno
)
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
guru_logger.opt(depth=depth, exception=record.exc_info).log(
level,
f"[{record.name}] {record.getMessage()}",
)
# 🔴 **Replace Existing Loggers with Interception**
logging.root.handlers.clear()
logging.root.setLevel(logging.INFO)
logging.root.handlers = [InterceptHandler()] logging.root.handlers = [InterceptHandler()]
logging.root.setLevel(level)
# remove every other logger's handlers for logger_name in intercept_loggers:
# and propagate to root logger logging_logger = logging.getLogger(logger_name)
for name in logging.root.manager.loggerDict.keys(): logging_logger.handlers.clear() # Remove Uvicorn default handlers
logging.getLogger(name).handlers = [] logging_logger.propagate = True # ✅ Ensure they propagate through Loguru
logging.getLogger(name).propagate = True
# configure loguru # 🔴 **Redirect stdout/stderr to Loguru (Keep Green Timestamps)**
logger.add(sink=sys.stdout) guru_logger.remove()
logger.add(sink=file_path, level=level, retention=retention, rotation=rotation) guru_logger.add(
sys.stdout,
level="INFO",
format="<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | {level} | {message}",
)
logger.disable("pika.adapters") print("✅ Logging interception complete. Logs are formatted and deduplicated!")
logger.disable("pika.connection")
logger.disable("pika.channel")
logger.disable("pika.callback")
logger.disable("pika.frame")
logger.disable("pika.spec")
logger.disable("aiormq.connection")
logger.disable("urllib3.connectionpool")
logging.getLogger("pymongo").setLevel(
logging.WARNING
) # Suppress pymongo DEBUG logs
class InterceptHandler(logging.Handler):
def emit(self, record):
# Get corresponding Loguru level if it exists
try:
level = logger.level(record.levelname).name
except ValueError:
level = record.levelno
# Find caller from where originated the logged message
frame, depth = logging.currentframe(), 2
while frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(
level, record.getMessage()
)

25
apps/content/.env Normal file
View File

@ -0,0 +1,25 @@
APP_NAME=content
export SERVICE_API_ACCESS_HOST=0.0.0.0
export SERVICE_API_ACCESS_PORT=8013
export MONGODB_NAME=freeleaps2
export MONGODB_PORT=27017
export CONTAINER_APP_ROOT=/app
export FREELEAPS_WWW_AS_AZURE_CLIENT_SECRET=3gK8Q~PJbyWmiNqaGgho2ZqCY~OXzABSyN8wWasK
export LOG_BASE_PATH=$CONTAINER_APP_ROOT/log/$APP_NAME
export BACKEND_LOG_FILE_NAME=$APP_NAME
export APPLICATION_ACTIVITY_LOG=$APP_NAME-activity
GIT_REPO_ROOT=/mnt/freeleaps/freeleaps-service-hub
CODEBASE_ROOT=/mnt/freeleaps/freeleaps-service-hub/apps/content
SITE_DEPLOY_FOLDER=/mnt/freeleaps/freeleaps-service-hub/sites/content/deploy
#!/bin/bash
export VENV_DIR=venv_t
export VENV_ACTIVATE=venv_t/bin/activate
export DOCKER_HOME=/var/lib/docker
export DOCKER_APP_HOME=$DOCKER_HOME/app
export DOCKER_BACKEND_HOME=$DOCKER_APP_HOME/$APP_NAME
export DOCKER_BACKEND_LOG_HOME=$DOCKER_BACKEND_HOME/log
export MONGODB_URI=mongodb://localhost:27017/
export CENTRAL_STORAGE_WEBAPI_URL_BASE="http://localhost:8005/api/central_storage"
export FREELEAPS_ENV=local
export LOG_BASE_PATH=${CODEBASE_ROOT}/log

View File

@ -1,49 +1,54 @@
from loguru import logger as guru_logger from loguru import logger as guru_logger
from common.config.log_settings import log_settings from common.config.log_settings import log_settings
from typing import List from typing import Dict, Any
import socket import socket
import json
import logging
import threading import threading
class LoggerBase: class LoggerBase:
binded_loggers = {} binded_loggers = {} # Stores logger instances
loguru_sinks_added = set() # Tracks added log sinks
logger_lock = threading.Lock() logger_lock = threading.Lock()
def __init__(self, logger_name: str, extra_fields: dict[str, any]) -> None: def __init__(self, logger_name: str, extra_fields: Dict[str, Any] = None) -> None:
self.__logger_name = logger_name self.__logger_name = logger_name
self.extra_fields = extra_fields self.extra_fields = extra_fields or {}
with LoggerBase.logger_lock: with LoggerBase.logger_lock:
# ✅ **If already created, reuse it** to prevent duplicates
if self.__logger_name in LoggerBase.binded_loggers: if self.__logger_name in LoggerBase.binded_loggers:
self.logger = LoggerBase.binded_loggers[self.__logger_name] self.logger = LoggerBase.binded_loggers[self.__logger_name]
return return
log_filename = log_settings.LOG_BASE_PATH + "/" + self.__logger_name + ".log" log_filename = f"{log_settings.LOG_BASE_PATH}/{self.__logger_name}.log"
log_retention = log_settings.LOG_RETENTION
log_rotation = log_settings.LOG_ROTATION
log_level = "INFO"
log_message_format = "{message}"
guru_logger.add( # ✅ **Ensure Loguru sink is added only once**
sink=log_filename, if log_filename not in LoggerBase.loguru_sinks_added:
level=log_level, guru_logger.add(
retention=log_retention, sink=log_filename,
rotation=log_rotation, level="INFO",
format=log_message_format, retention=log_settings.LOG_RETENTION,
serialize=True, rotation=log_settings.LOG_ROTATION,
filter=lambda record: "extra" in record format="{message}",
and "topic" in record["extra"] serialize=True,
and record["extra"]["topic"] == self.__logger_name, filter=lambda record: "extra" in record
) and "topic" in record["extra"]
host_name = socket.gethostname() and record["extra"]["topic"] == self.__logger_name,
host_ip = socket.gethostbyname(host_name) )
self.logger = guru_logger.bind( LoggerBase.loguru_sinks_added.add(log_filename) # ✅ Mark as added
topic=self.__logger_name,
host_ip=host_ip, host_name = socket.gethostname()
host_name=host_name, host_ip = socket.gethostbyname(host_name)
)
with LoggerBase.logger_lock: # ✅ Bind the logger with topic and extra fields
self.logger = guru_logger.bind(
topic=self.__logger_name,
host_ip=host_ip,
host_name=host_name,
**self.extra_fields, # Include additional metadata
)
# ✅ Store reference to prevent duplicate instances
LoggerBase.binded_loggers[self.__logger_name] = self.logger LoggerBase.binded_loggers[self.__logger_name] = self.logger
async def log_event( async def log_event(
@ -52,7 +57,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
event: str, event: str,
properties: dict[str, any], properties: Dict[str, Any],
text: str = "", text: str = "",
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
@ -71,7 +76,7 @@ class LoggerBase:
subject: str, subject: str,
exception: Exception, exception: Exception,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -89,7 +94,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -106,7 +111,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -123,7 +128,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,

View File

@ -1,49 +1,54 @@
from loguru import logger as guru_logger from loguru import logger as guru_logger
from common.config.log_settings import log_settings from common.config.log_settings import log_settings
from typing import List from typing import Dict, Any
import socket import socket
import json
import logging
import threading import threading
class LoggerBase: class LoggerBase:
binded_loggers = {} binded_loggers = {} # Stores logger instances
loguru_sinks_added = set() # Tracks added log sinks
logger_lock = threading.Lock() logger_lock = threading.Lock()
def __init__(self, logger_name: str, extra_fields: dict[str, any]) -> None: def __init__(self, logger_name: str, extra_fields: Dict[str, Any] = None) -> None:
self.__logger_name = logger_name self.__logger_name = logger_name
self.extra_fields = extra_fields self.extra_fields = extra_fields or {}
with LoggerBase.logger_lock: with LoggerBase.logger_lock:
# ✅ **If already created, reuse it** to prevent duplicates
if self.__logger_name in LoggerBase.binded_loggers: if self.__logger_name in LoggerBase.binded_loggers:
self.logger = LoggerBase.binded_loggers[self.__logger_name] self.logger = LoggerBase.binded_loggers[self.__logger_name]
return return
log_filename = log_settings.LOG_BASE_PATH + "/" + self.__logger_name + ".log" log_filename = f"{log_settings.LOG_BASE_PATH}/{self.__logger_name}.log"
log_retention = log_settings.LOG_RETENTION
log_rotation = log_settings.LOG_ROTATION
log_level = "INFO"
log_message_format = "{message}"
guru_logger.add( # ✅ **Ensure Loguru sink is added only once**
sink=log_filename, if log_filename not in LoggerBase.loguru_sinks_added:
level=log_level, guru_logger.add(
retention=log_retention, sink=log_filename,
rotation=log_rotation, level="INFO",
format=log_message_format, retention=log_settings.LOG_RETENTION,
serialize=True, rotation=log_settings.LOG_ROTATION,
filter=lambda record: "extra" in record format="{message}",
and "topic" in record["extra"] serialize=True,
and record["extra"]["topic"] == self.__logger_name, filter=lambda record: "extra" in record
) and "topic" in record["extra"]
host_name = socket.gethostname() and record["extra"]["topic"] == self.__logger_name,
host_ip = socket.gethostbyname(host_name) )
self.logger = guru_logger.bind( LoggerBase.loguru_sinks_added.add(log_filename) # ✅ Mark as added
topic=self.__logger_name,
host_ip=host_ip, host_name = socket.gethostname()
host_name=host_name, host_ip = socket.gethostbyname(host_name)
)
with LoggerBase.logger_lock: # ✅ Bind the logger with topic and extra fields
self.logger = guru_logger.bind(
topic=self.__logger_name,
host_ip=host_ip,
host_name=host_name,
**self.extra_fields, # Include additional metadata
)
# ✅ Store reference to prevent duplicate instances
LoggerBase.binded_loggers[self.__logger_name] = self.logger LoggerBase.binded_loggers[self.__logger_name] = self.logger
async def log_event( async def log_event(
@ -52,7 +57,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
event: str, event: str,
properties: dict[str, any], properties: Dict[str, Any],
text: str = "", text: str = "",
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
@ -71,7 +76,7 @@ class LoggerBase:
subject: str, subject: str,
exception: Exception, exception: Exception,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -89,7 +94,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -106,7 +111,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,
@ -123,7 +128,7 @@ class LoggerBase:
receiver_id: str, receiver_id: str,
subject: str, subject: str,
text: str = "", text: str = "",
properties: dict[str, any] = None, properties: Dict[str, Any] = None,
) -> None: ) -> None:
local_logger = self.logger.bind( local_logger = self.logger.bind(
sender_id=sender_id, sender_id=sender_id,