Update utils/logging.py
Browse files- utils/logging.py +104 -128
utils/logging.py
CHANGED
@@ -1,163 +1,139 @@
|
|
1 |
"""
|
2 |
-
Logging
|
3 |
-
|
4 |
-
This module provides a centralized logging system for the application,
|
5 |
-
replacing print statements with proper logging for better debugging and monitoring.
|
6 |
"""
|
7 |
|
8 |
import logging
|
9 |
-
import
|
10 |
-
from
|
11 |
-
|
12 |
-
from utils.config import LOGGING_CONFIG
|
13 |
-
|
14 |
-
# Configure logging based on the configuration in config.py
|
15 |
-
logging.config.dictConfig(LOGGING_CONFIG)
|
16 |
-
|
17 |
-
# Create a logger for the application
|
18 |
-
logger = logging.getLogger("mona")
|
19 |
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
22 |
"""
|
23 |
-
|
24 |
|
25 |
Args:
|
26 |
-
name
|
27 |
-
|
|
|
|
|
28 |
|
29 |
Returns:
|
30 |
-
|
31 |
"""
|
32 |
-
|
33 |
-
return logging.getLogger(f"mona.{name}")
|
34 |
-
return logger
|
35 |
-
|
36 |
-
|
37 |
-
def log_function_call(func):
|
38 |
-
"""
|
39 |
-
Decorator to log function calls with parameters and return values.
|
40 |
|
41 |
-
|
42 |
-
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
"""
|
47 |
-
def wrapper(*args, **kwargs):
|
48 |
-
func_logger = get_logger(func.__module__)
|
49 |
-
func_name = func.__qualname__
|
50 |
-
|
51 |
-
# Log function call with arguments
|
52 |
-
args_repr = [repr(a) for a in args]
|
53 |
-
kwargs_repr = [f"{k}={v!r}" for k, v in kwargs.items()]
|
54 |
-
signature = ", ".join(args_repr + kwargs_repr)
|
55 |
-
func_logger.debug(f"Calling {func_name}({signature})")
|
56 |
-
|
57 |
-
# Call the function
|
58 |
-
try:
|
59 |
-
result = func(*args, **kwargs)
|
60 |
-
func_logger.debug(f"{func_name} returned {result!r}")
|
61 |
-
return result
|
62 |
-
except Exception as e:
|
63 |
-
func_logger.exception(f"Exception in {func_name}: {str(e)}")
|
64 |
-
raise
|
65 |
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
def log_error(error_msg, exc_info=None):
|
70 |
-
"""
|
71 |
-
Log an error message.
|
72 |
|
73 |
-
|
74 |
-
error_msg (str): The error message to log.
|
75 |
-
exc_info (Exception, optional): The exception information to include in the log.
|
76 |
-
"""
|
77 |
-
if exc_info:
|
78 |
-
logger.error(error_msg, exc_info=exc_info)
|
79 |
-
else:
|
80 |
-
logger.error(error_msg)
|
81 |
-
|
82 |
-
|
83 |
-
def log_warning(warning_msg):
|
84 |
-
"""
|
85 |
-
Log a warning message.
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
logger.
|
91 |
-
|
92 |
-
|
93 |
-
def log_info(info_msg):
|
94 |
-
"""
|
95 |
-
Log an info message.
|
96 |
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
|
|
|
|
|
|
106 |
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
logger
|
111 |
-
|
112 |
|
113 |
-
def
|
114 |
"""
|
115 |
-
|
116 |
|
117 |
Args:
|
118 |
-
|
119 |
-
|
120 |
-
|
|
|
121 |
"""
|
122 |
-
|
123 |
-
"timestamp": datetime.now().isoformat(),
|
124 |
-
"user_id": user_id,
|
125 |
-
"activity_type": activity_type,
|
126 |
-
}
|
127 |
|
128 |
-
|
129 |
-
|
|
|
130 |
|
131 |
-
logger
|
132 |
-
|
133 |
|
134 |
-
def
|
135 |
"""
|
136 |
-
|
137 |
|
138 |
Args:
|
139 |
-
|
140 |
-
|
141 |
"""
|
142 |
-
logger.
|
143 |
-
|
|
|
144 |
|
145 |
-
def
|
146 |
"""
|
147 |
-
|
148 |
|
149 |
Args:
|
150 |
-
|
151 |
-
|
152 |
-
tokens_used (int, optional): The number of tokens used in the operation.
|
153 |
"""
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
"""
|
2 |
+
Logging utilities for the application.
|
|
|
|
|
|
|
3 |
"""
|
4 |
|
5 |
import logging
|
6 |
+
import sys
|
7 |
+
from pathlib import Path
|
8 |
+
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
+
def setup_logger(
|
11 |
+
name: str = "app",
|
12 |
+
level: str = "INFO",
|
13 |
+
log_file: Optional[str] = None,
|
14 |
+
format_string: Optional[str] = None
|
15 |
+
) -> logging.Logger:
|
16 |
"""
|
17 |
+
Set up and configure a logger with console and optional file output.
|
18 |
|
19 |
Args:
|
20 |
+
name: Logger name
|
21 |
+
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
22 |
+
log_file: Optional file path for log output
|
23 |
+
format_string: Optional custom format string
|
24 |
|
25 |
Returns:
|
26 |
+
Configured logger instance
|
27 |
"""
|
28 |
+
logger = logging.getLogger(name)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
|
30 |
+
# Clear any existing handlers to avoid duplicates
|
31 |
+
logger.handlers.clear()
|
32 |
|
33 |
+
# Set logging level
|
34 |
+
logger.setLevel(getattr(logging, level.upper()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
+
# Create formatter
|
37 |
+
if format_string is None:
|
38 |
+
format_string = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
|
|
|
|
|
39 |
|
40 |
+
formatter = logging.Formatter(format_string)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
|
42 |
+
# Console handler
|
43 |
+
console_handler = logging.StreamHandler(sys.stdout)
|
44 |
+
console_handler.setFormatter(formatter)
|
45 |
+
logger.addHandler(console_handler)
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
# File handler (optional)
|
48 |
+
if log_file:
|
49 |
+
try:
|
50 |
+
# Create directory if it doesn't exist
|
51 |
+
log_path = Path(log_file)
|
52 |
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
53 |
+
|
54 |
+
file_handler = logging.FileHandler(log_file)
|
55 |
+
file_handler.setFormatter(formatter)
|
56 |
+
logger.addHandler(file_handler)
|
57 |
+
except Exception as e:
|
58 |
+
logger.warning(f"Could not create file handler for {log_file}: {e}")
|
59 |
|
60 |
+
# Prevent propagation to avoid duplicate logs
|
61 |
+
logger.propagate = False
|
62 |
+
|
63 |
+
return logger
|
|
|
64 |
|
65 |
+
def get_logger(name: str = "app") -> logging.Logger:
|
66 |
"""
|
67 |
+
Get an existing logger or create a basic one if it doesn't exist.
|
68 |
|
69 |
Args:
|
70 |
+
name: Logger name
|
71 |
+
|
72 |
+
Returns:
|
73 |
+
Logger instance
|
74 |
"""
|
75 |
+
logger = logging.getLogger(name)
|
|
|
|
|
|
|
|
|
76 |
|
77 |
+
# If logger has no handlers, set up a basic one
|
78 |
+
if not logger.handlers:
|
79 |
+
logger = setup_logger(name)
|
80 |
|
81 |
+
return logger
|
|
|
82 |
|
83 |
+
def set_log_level(logger: logging.Logger, level: str) -> None:
|
84 |
"""
|
85 |
+
Set the logging level for a logger and all its handlers.
|
86 |
|
87 |
Args:
|
88 |
+
logger: Logger instance
|
89 |
+
level: New logging level
|
90 |
"""
|
91 |
+
logger.setLevel(getattr(logging, level.upper()))
|
92 |
+
for handler in logger.handlers:
|
93 |
+
handler.setLevel(getattr(logging, level.upper()))
|
94 |
|
95 |
+
def add_file_handler(logger: logging.Logger, log_file: str) -> None:
|
96 |
"""
|
97 |
+
Add a file handler to an existing logger.
|
98 |
|
99 |
Args:
|
100 |
+
logger: Logger instance
|
101 |
+
log_file: Path to log file
|
|
|
102 |
"""
|
103 |
+
try:
|
104 |
+
# Create directory if it doesn't exist
|
105 |
+
log_path = Path(log_file)
|
106 |
+
log_path.parent.mkdir(parents=True, exist_ok=True)
|
107 |
+
|
108 |
+
file_handler = logging.FileHandler(log_file)
|
109 |
+
formatter = logging.Formatter(
|
110 |
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
111 |
+
)
|
112 |
+
file_handler.setFormatter(formatter)
|
113 |
+
logger.addHandler(file_handler)
|
114 |
+
except Exception as e:
|
115 |
+
logger.warning(f"Could not add file handler for {log_file}: {e}")
|
116 |
+
|
117 |
+
# Create a default logger instance
|
118 |
+
default_logger = setup_logger("app", "INFO")
|
119 |
+
|
120 |
+
# Convenience functions using the default logger
|
121 |
+
def debug(message: str) -> None:
|
122 |
+
"""Log a debug message."""
|
123 |
+
default_logger.debug(message)
|
124 |
+
|
125 |
+
def info(message: str) -> None:
|
126 |
+
"""Log an info message."""
|
127 |
+
default_logger.info(message)
|
128 |
+
|
129 |
+
def warning(message: str) -> None:
|
130 |
+
"""Log a warning message."""
|
131 |
+
default_logger.warning(message)
|
132 |
+
|
133 |
+
def error(message: str) -> None:
|
134 |
+
"""Log an error message."""
|
135 |
+
default_logger.error(message)
|
136 |
+
|
137 |
+
def critical(message: str) -> None:
|
138 |
+
"""Log a critical message."""
|
139 |
+
default_logger.critical(message)
|