Spaces:
Sleeping
Sleeping
# 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: | |
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 |