SuperExpert / utils /logging.py
JarvisChan630's picture
first commit
75309ed
raw
history blame
3.7 kB
# File: logging_utils.py
import logging
import colorlog
from functools import wraps
import time
from typing import Callable, Any, Union
import json
def setup_logging(level=logging.INFO, log_file=None):
"""
Set up logging configuration with colored output and improved formatting.
Args:
level (int): The logging level (e.g., logging.DEBUG, logging.INFO)
log_file (str, optional): Path to a log file. If None, log to console only.
"""
formatter = colorlog.ColoredFormatter(
"%(log_color)s%(levelname)-8s%(reset)s %(blue)s%(asctime)s%(reset)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
reset=True,
log_colors={
'DEBUG': 'cyan',
'INFO': 'green',
'WARNING': 'yellow',
'ERROR': 'red',
'CRITICAL': 'red,bg_white',
},
secondary_log_colors={},
style='%'
)
console_handler = colorlog.StreamHandler()
console_handler.setFormatter(formatter)
logger = colorlog.getLogger()
logger.setLevel(level)
logger.addHandler(console_handler)
if log_file:
file_formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
file_handler = logging.FileHandler(log_file)
file_handler.setFormatter(file_formatter)
logger.addHandler(file_handler)
def format_dict(d, indent=0):
"""Format a dictionary for pretty printing."""
return '\n'.join(f"{' ' * indent}{k}: {format_dict(v, indent+1) if isinstance(v, dict) else v}" for k, v in d.items())
def log_function(logger: logging.Logger):
"""
A decorator that logs function entry, exit, arguments, and execution time with improved formatting.
Args:
logger (logging.Logger): The logger to use for logging.
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
func_name = func.__name__
logger.info(f"{'=' * 40}")
logger.info(f"Starting: {func_name}")
# Log arguments in a more readable format
if args or kwargs:
logger.debug("Arguments:")
if args:
for i, arg in enumerate(args):
if isinstance(arg, dict):
logger.debug(f" arg{i}:\n{format_dict(arg, 2)}")
else:
logger.debug(f" arg{i}: {arg}")
if kwargs:
for key, value in kwargs.items():
if isinstance(value, dict):
logger.debug(f" {key}:\n{format_dict(value, 2)}")
else:
logger.debug(f" {key}: {value}")
start_time = time.time()
try:
result = func(*args, **kwargs)
logger.info(f"Completed: {func_name}")
# Log the result
if result:
if isinstance(result, dict):
logger.info(f"Output:\n{format_dict(result, 1)}")
else:
logger.info(f"Output: {result}")
return result
except Exception as e:
logger.exception(f"Exception in {func_name}:")
logger.exception(f" {str(e)}")
raise
finally:
duration = time.time() - start_time
logger.debug(f"Execution time: {duration:.2f} seconds")
logger.info(f"{'=' * 40}\n")
return wrapper
return decorator