mrradix commited on
Commit
436bd7b
·
verified ·
1 Parent(s): a429c8d

Update utils/logging.py

Browse files
Files changed (1) hide show
  1. utils/logging.py +203 -134
utils/logging.py CHANGED
@@ -1,163 +1,232 @@
1
- """
2
- Logging module for the MONA application.
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 logging.config
 
10
  from datetime import datetime
 
 
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
- def get_logger(name=None):
22
  """
23
- Get a logger instance with the specified name.
24
 
25
- Args:
26
- name (str, optional): The name of the logger. If None, returns the root logger.
27
- For module-specific loggers, use __name__ as the name.
28
 
29
- Returns:
30
- logging.Logger: A logger instance.
31
- """
32
- if name:
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
- Args:
42
- func (callable): The function to decorate.
 
 
 
43
 
44
- Returns:
45
- callable: The decorated function.
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
- return wrapper
67
-
68
-
69
- def log_error(error_msg, exc_info=None):
70
- """
71
- Log an error message.
72
 
73
- Args:
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
- Args:
88
- warning_msg (str): The warning message to log.
89
- """
90
- logger.warning(warning_msg)
91
-
92
-
93
- def log_info(info_msg):
94
- """
95
- Log an info message.
96
 
97
- Args:
98
- info_msg (str): The info message to log.
99
- """
100
- logger.info(info_msg)
101
-
102
 
103
- def log_debug(debug_msg):
104
- """
105
- Log a debug message.
 
 
 
 
 
106
 
107
- Args:
108
- debug_msg (str): The debug message to log.
109
- """
110
- logger.debug(debug_msg)
111
-
112
 
113
- def log_user_activity(user_id, activity_type, details=None):
114
- """
115
- Log user activity for analytics purposes.
 
 
 
 
 
 
 
116
 
117
- Args:
118
- user_id (str): The user identifier.
119
- activity_type (str): The type of activity (e.g., 'page_view', 'task_create').
120
- details (dict, optional): Additional details about the activity.
121
- """
122
- activity_log = {
123
- "timestamp": datetime.now().isoformat(),
124
- "user_id": user_id,
125
- "activity_type": activity_type,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
128
  if details:
129
- activity_log["details"] = details
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
- logger.info(f"User activity: {activity_log}")
132
-
133
-
134
- def log_performance(operation, duration_ms):
135
- """
136
- Log performance metrics for monitoring.
137
 
138
- Args:
139
- operation (str): The operation being measured.
140
- duration_ms (float): The duration of the operation in milliseconds.
141
- """
142
- logger.info(f"Performance: {operation} took {duration_ms:.2f}ms")
143
-
144
 
145
- def log_ai_model_usage(model_name: str, operation: str, tokens_used: Optional[int] = None):
146
- """
147
- Log AI model usage for monitoring and quota management.
148
-
149
- Args:
150
- model_name (str): The name of the AI model used.
151
- operation (str): The operation performed with the model.
152
- tokens_used (int, optional): The number of tokens used in the operation.
153
- """
154
- usage_log = {
155
- "timestamp": datetime.now().isoformat(),
156
  "model": model_name,
157
  "operation": operation,
 
 
158
  }
159
 
160
- if tokens_used is not None:
161
- usage_log["tokens_used"] = tokens_used
 
 
 
 
 
 
 
 
 
162
 
163
- logger.info(f"AI model usage: {usage_log}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import logging
2
+ import os
3
+ import sys
4
  from datetime import datetime
5
+ from typing import Optional, Dict, Any
6
+ import json
7
 
8
+ # Configure logging
9
+ def setup_logger(name: str = "mona_app", level: str = "INFO") -> logging.Logger:
10
+ """
11
+ Set up a logger with both file and console handlers
 
 
 
 
 
 
12
  """
13
+ logger = logging.getLogger(name)
14
 
15
+ # Clear existing handlers to avoid duplicates
16
+ if logger.handlers:
17
+ logger.handlers.clear()
18
 
19
+ # Set log level
20
+ log_level = getattr(logging, level.upper(), logging.INFO)
21
+ logger.setLevel(log_level)
 
 
 
 
 
 
 
 
22
 
23
+ # Create formatters
24
+ detailed_formatter = logging.Formatter(
25
+ '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
26
+ )
27
+ simple_formatter = logging.Formatter('%(levelname)s - %(message)s')
28
 
29
+ # Console handler
30
+ console_handler = logging.StreamHandler(sys.stdout)
31
+ console_handler.setLevel(logging.INFO)
32
+ console_handler.setFormatter(simple_formatter)
33
+
34
+ # File handler (if in a writable environment)
35
+ try:
36
+ log_dir = "/tmp/logs" if os.path.exists("/tmp") else "./logs"
37
+ os.makedirs(log_dir, exist_ok=True)
 
 
 
38
 
39
+ log_file = os.path.join(log_dir, f"{name}.log")
40
+ file_handler = logging.FileHandler(log_file)
41
+ file_handler.setLevel(logging.DEBUG)
42
+ file_handler.setFormatter(detailed_formatter)
43
+ logger.addHandler(file_handler)
44
+ except Exception:
45
+ # If we can't create file handler, continue with just console
46
+ pass
47
 
48
+ logger.addHandler(console_handler)
 
 
 
 
 
49
 
50
+ return logger
 
 
 
 
 
 
 
 
51
 
52
+ # Global logger instance
53
+ _logger = None
54
+
55
+ def get_logger() -> logging.Logger:
56
+ """Get the global logger instance"""
57
+ global _logger
58
+ if _logger is None:
59
+ _logger = setup_logger()
60
+ return _logger
61
+
62
+ def log_error(message: str, error: Exception = None) -> None:
63
+ """Log error messages with optional exception details"""
64
+ logger = get_logger()
65
+ if error:
66
+ logger.error(f"{message}: {str(error)}", exc_info=True)
67
+ else:
68
+ logger.error(message)
69
+
70
+ def log_warning(message: str) -> None:
71
+ """Log warning messages"""
72
+ logger = get_logger()
73
+ logger.warning(message)
74
+
75
+ def log_info(message: str) -> None:
76
+ """Log info messages"""
77
+ logger = get_logger()
78
+ logger.info(message)
79
+
80
+ def log_debug(message: str) -> None:
81
+ """Log debug messages"""
82
+ logger = get_logger()
83
+ logger.debug(message)
84
+
85
+ def log_performance(operation: str, duration: float, additional_info: Dict[str, Any] = None) -> None:
86
+ """Log performance metrics"""
87
+ logger = get_logger()
88
+ perf_data = {
89
+ "operation": operation,
90
+ "duration_seconds": round(duration, 4),
91
+ "timestamp": datetime.now().isoformat()
92
+ }
93
 
94
+ if additional_info:
95
+ perf_data.update(additional_info)
 
 
 
 
 
 
 
96
 
97
+ logger.info(f"PERFORMANCE: {json.dumps(perf_data)}")
 
 
 
 
98
 
99
+ def log_user_action(action: str, user_id: str = None, details: Dict[str, Any] = None) -> None:
100
+ """Log user actions for analytics"""
101
+ logger = get_logger()
102
+ action_data = {
103
+ "action": action,
104
+ "user_id": user_id or "anonymous",
105
+ "timestamp": datetime.now().isoformat()
106
+ }
107
 
108
+ if details:
109
+ action_data.update(details)
110
+
111
+ logger.info(f"USER_ACTION: {json.dumps(action_data)}")
 
112
 
113
+ def log_data_operation(operation: str, table_name: str = None, record_count: int = None, success: bool = True) -> None:
114
+ """Log database/data operations"""
115
+ logger = get_logger()
116
+ data_op = {
117
+ "operation": operation,
118
+ "table": table_name,
119
+ "record_count": record_count,
120
+ "success": success,
121
+ "timestamp": datetime.now().isoformat()
122
+ }
123
 
124
+ level = logging.INFO if success else logging.ERROR
125
+ logger.log(level, f"DATA_OP: {json.dumps(data_op)}")
126
+
127
+ def log_api_call(endpoint: str, method: str = "GET", status_code: int = None, duration: float = None) -> None:
128
+ """Log API calls and responses"""
129
+ logger = get_logger()
130
+ api_data = {
131
+ "endpoint": endpoint,
132
+ "method": method,
133
+ "status_code": status_code,
134
+ "duration_seconds": round(duration, 4) if duration else None,
135
+ "timestamp": datetime.now().isoformat()
136
+ }
137
+
138
+ logger.info(f"API_CALL: {json.dumps(api_data)}")
139
+
140
+ def log_security_event(event_type: str, details: Dict[str, Any] = None, severity: str = "INFO") -> None:
141
+ """Log security-related events"""
142
+ logger = get_logger()
143
+ security_data = {
144
+ "event_type": event_type,
145
+ "severity": severity,
146
+ "timestamp": datetime.now().isoformat()
147
  }
148
 
149
  if details:
150
+ security_data.update(details)
151
+
152
+ level = getattr(logging, severity.upper(), logging.INFO)
153
+ logger.log(level, f"SECURITY: {json.dumps(security_data)}")
154
+
155
+ def log_system_health(component: str, status: str, metrics: Dict[str, Any] = None) -> None:
156
+ """Log system health checks"""
157
+ logger = get_logger()
158
+ health_data = {
159
+ "component": component,
160
+ "status": status,
161
+ "timestamp": datetime.now().isoformat()
162
+ }
163
 
164
+ if metrics:
165
+ health_data.update(metrics)
 
 
 
 
166
 
167
+ level = logging.INFO if status == "healthy" else logging.WARNING
168
+ logger.log(level, f"HEALTH: {json.dumps(health_data)}")
 
 
 
 
169
 
170
+ def log_ai_model_usage(model_name: str, operation: str, tokens_used: Optional[int] = None) -> None:
171
+ """Log AI model usage for monitoring and billing"""
172
+ logger = get_logger()
173
+ ai_data = {
 
 
 
 
 
 
 
174
  "model": model_name,
175
  "operation": operation,
176
+ "tokens_used": tokens_used,
177
+ "timestamp": datetime.now().isoformat()
178
  }
179
 
180
+ logger.info(f"AI_USAGE: {json.dumps(ai_data)}")
181
+
182
+ def log_business_metric(metric_name: str, value: float, unit: str = None, tags: Dict[str, str] = None) -> None:
183
+ """Log business metrics for analytics"""
184
+ logger = get_logger()
185
+ metric_data = {
186
+ "metric": metric_name,
187
+ "value": value,
188
+ "unit": unit,
189
+ "timestamp": datetime.now().isoformat()
190
+ }
191
 
192
+ if tags:
193
+ metric_data["tags"] = tags
194
+
195
+ logger.info(f"METRIC: {json.dumps(metric_data)}")
196
+
197
+ # Context manager for performance logging
198
+ class PerformanceLogger:
199
+ def __init__(self, operation: str, additional_info: Dict[str, Any] = None):
200
+ self.operation = operation
201
+ self.additional_info = additional_info or {}
202
+ self.start_time = None
203
+
204
+ def __enter__(self):
205
+ self.start_time = datetime.now()
206
+ return self
207
+
208
+ def __exit__(self, exc_type, exc_val, exc_tb):
209
+ if self.start_time:
210
+ duration = (datetime.now() - self.start_time).total_seconds()
211
+ success = exc_type is None
212
+
213
+ perf_info = self.additional_info.copy()
214
+ perf_info["success"] = success
215
+
216
+ if not success and exc_val:
217
+ perf_info["error"] = str(exc_val)
218
+
219
+ log_performance(self.operation, duration, perf_info)
220
+
221
+ # Decorator for automatic performance logging
222
+ def log_performance_decorator(operation_name: str = None):
223
+ def decorator(func):
224
+ def wrapper(*args, **kwargs):
225
+ op_name = operation_name or f"{func.__module__}.{func.__name__}"
226
+ with PerformanceLogger(op_name):
227
+ return func(*args, **kwargs)
228
+ return wrapper
229
+ return decorator
230
+
231
+ # Initialize logger on module import
232
+ get_logger().info("Logging system initialized")