Spaces:
Runtime error
Runtime error
invincible-jha
commited on
Commit
·
f83b968
1
Parent(s):
76166e3
Add comprehensive logging system and analytics with log rotation
Browse files- .gitignore +2 -0
- README.md +105 -1
- requirements.txt +3 -1
- utils/analytics_logger.py +170 -0
- utils/log_manager.py +169 -0
.gitignore
CHANGED
|
@@ -32,7 +32,9 @@ ENV/
|
|
| 32 |
*.swo
|
| 33 |
|
| 34 |
# Logs
|
|
|
|
| 35 |
*.log
|
|
|
|
| 36 |
|
| 37 |
# Local configuration
|
| 38 |
.env
|
|
|
|
| 32 |
*.swo
|
| 33 |
|
| 34 |
# Logs
|
| 35 |
+
logs/
|
| 36 |
*.log
|
| 37 |
+
*.log.*
|
| 38 |
|
| 39 |
# Local configuration
|
| 40 |
.env
|
README.md
CHANGED
|
@@ -9,4 +9,108 @@ app_file: app.py
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Mental Wellness Platform
|
| 13 |
+
|
| 14 |
+
A comprehensive mental wellness support system powered by AI, deployed on Hugging Face Spaces.
|
| 15 |
+
|
| 16 |
+
## Features
|
| 17 |
+
- 🤖 Multi-agent AI support system
|
| 18 |
+
- 💬 Natural therapeutic conversations
|
| 19 |
+
- 📊 Mental health assessments
|
| 20 |
+
- 🧘♀️ Guided meditation and mindfulness
|
| 21 |
+
- 🚨 Crisis intervention support
|
| 22 |
+
- 📱 Multi-modal interaction (text, voice, image)
|
| 23 |
+
- 📈 Comprehensive logging and analytics
|
| 24 |
+
- 🔄 Automatic log rotation and management
|
| 25 |
+
|
| 26 |
+
## System Components
|
| 27 |
+
- Therapeutic Conversation Agent
|
| 28 |
+
- Assessment Agent
|
| 29 |
+
- Mindfulness Agent
|
| 30 |
+
- Crisis Intervention Agent
|
| 31 |
+
- Analytics and Logging System
|
| 32 |
+
|
| 33 |
+
## Logging System
|
| 34 |
+
The platform includes a comprehensive logging system with:
|
| 35 |
+
- Agent-specific logs
|
| 36 |
+
- System health monitoring
|
| 37 |
+
- Analytics tracking
|
| 38 |
+
- Performance metrics
|
| 39 |
+
- Security event logging
|
| 40 |
+
- Automatic log rotation
|
| 41 |
+
- Log cleanup for older files
|
| 42 |
+
|
| 43 |
+
### Log Categories
|
| 44 |
+
1. Agent Logs (`logs/agents/`)
|
| 45 |
+
- Individual agent activities
|
| 46 |
+
- Performance metrics
|
| 47 |
+
- Error tracking
|
| 48 |
+
|
| 49 |
+
2. System Logs (`logs/system/`)
|
| 50 |
+
- System health
|
| 51 |
+
- Resource usage
|
| 52 |
+
- General operations
|
| 53 |
+
|
| 54 |
+
3. Analytics Logs (`logs/analytics/`)
|
| 55 |
+
- User interactions
|
| 56 |
+
- Session metrics
|
| 57 |
+
- Model performance
|
| 58 |
+
- Usage statistics
|
| 59 |
+
|
| 60 |
+
## Usage
|
| 61 |
+
1. Open the chat interface
|
| 62 |
+
2. Type your message or use voice/image input
|
| 63 |
+
3. Choose from available tools:
|
| 64 |
+
- Mental Health Check
|
| 65 |
+
- Start Meditation
|
| 66 |
+
- View Resources
|
| 67 |
+
|
| 68 |
+
## Important Note
|
| 69 |
+
This is an AI-powered support tool and not a substitute for professional mental health care. In case of emergency:
|
| 70 |
+
- Call emergency services: 911 (US)
|
| 71 |
+
- National Crisis Hotline: 988
|
| 72 |
+
- Crisis Text Line: Text HOME to 741741
|
| 73 |
+
|
| 74 |
+
## Technical Details
|
| 75 |
+
Built with:
|
| 76 |
+
- Gradio for interface
|
| 77 |
+
- Hugging Face Transformers for AI models
|
| 78 |
+
- CrewAI for multi-agent orchestration
|
| 79 |
+
- Advanced voice and image processing
|
| 80 |
+
- Comprehensive logging system
|
| 81 |
+
|
| 82 |
+
## Development
|
| 83 |
+
To run locally:
|
| 84 |
+
1. Clone the repository
|
| 85 |
+
2. Install dependencies:
|
| 86 |
+
```bash
|
| 87 |
+
pip install -r requirements.txt
|
| 88 |
+
```
|
| 89 |
+
3. Run the application:
|
| 90 |
+
```bash
|
| 91 |
+
python app.py
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
## Monitoring
|
| 95 |
+
The system includes:
|
| 96 |
+
- Real-time performance monitoring
|
| 97 |
+
- Error tracking and alerts
|
| 98 |
+
- Usage analytics
|
| 99 |
+
- System health metrics
|
| 100 |
+
|
| 101 |
+
## Security
|
| 102 |
+
- All conversations are encrypted
|
| 103 |
+
- Comprehensive security logging
|
| 104 |
+
- Access control and monitoring
|
| 105 |
+
- Data retention policies
|
| 106 |
+
|
| 107 |
+
## License
|
| 108 |
+
MIT License
|
| 109 |
+
|
| 110 |
+
## Authors
|
| 111 |
+
Created by Invincible Jha
|
| 112 |
+
|
| 113 |
+
## Acknowledgments
|
| 114 |
+
- CrewAI for the multi-agent framework
|
| 115 |
+
- Hugging Face for AI models and hosting
|
| 116 |
+
- Gradio for the interface framework
|
requirements.txt
CHANGED
|
@@ -15,4 +15,6 @@ pillow>=10.1.0
|
|
| 15 |
redis>=5.0.1
|
| 16 |
pytest>=7.4.3
|
| 17 |
crewai>=0.11.0
|
| 18 |
-
huggingface_hub>=0.26.5
|
|
|
|
|
|
|
|
|
| 15 |
redis>=5.0.1
|
| 16 |
pytest>=7.4.3
|
| 17 |
crewai>=0.11.0
|
| 18 |
+
huggingface_hub>=0.26.5
|
| 19 |
+
psutil>=5.9.0
|
| 20 |
+
python-json-logger>=2.0.7
|
utils/analytics_logger.py
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Dict, Any, Optional
|
| 2 |
+
import json
|
| 3 |
+
import time
|
| 4 |
+
from datetime import datetime
|
| 5 |
+
from utils.log_manager import LogManager
|
| 6 |
+
|
| 7 |
+
class AnalyticsLogger:
|
| 8 |
+
"""Handles logging of analytics events and metrics"""
|
| 9 |
+
|
| 10 |
+
def __init__(self):
|
| 11 |
+
self.log_manager = LogManager()
|
| 12 |
+
self.logger = self.log_manager.get_analytics_logger("events")
|
| 13 |
+
self.metrics_logger = self.log_manager.get_analytics_logger("metrics")
|
| 14 |
+
|
| 15 |
+
def log_user_interaction(self,
|
| 16 |
+
user_id: str,
|
| 17 |
+
interaction_type: str,
|
| 18 |
+
agent_type: str,
|
| 19 |
+
duration: float,
|
| 20 |
+
success: bool,
|
| 21 |
+
details: Optional[Dict] = None):
|
| 22 |
+
"""Log user interaction events"""
|
| 23 |
+
event = {
|
| 24 |
+
"event_type": "user_interaction",
|
| 25 |
+
"user_id": user_id,
|
| 26 |
+
"interaction_type": interaction_type,
|
| 27 |
+
"agent_type": agent_type,
|
| 28 |
+
"duration": duration,
|
| 29 |
+
"success": success,
|
| 30 |
+
"timestamp": datetime.now().isoformat(),
|
| 31 |
+
"details": details or {}
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
self.logger.info(f"User Interaction: {json.dumps(event, indent=2)}")
|
| 35 |
+
|
| 36 |
+
def log_agent_performance(self,
|
| 37 |
+
agent_type: str,
|
| 38 |
+
operation: str,
|
| 39 |
+
response_time: float,
|
| 40 |
+
success: bool,
|
| 41 |
+
error: Optional[str] = None):
|
| 42 |
+
"""Log agent performance metrics"""
|
| 43 |
+
metric = {
|
| 44 |
+
"metric_type": "agent_performance",
|
| 45 |
+
"agent_type": agent_type,
|
| 46 |
+
"operation": operation,
|
| 47 |
+
"response_time": response_time,
|
| 48 |
+
"success": success,
|
| 49 |
+
"error": error,
|
| 50 |
+
"timestamp": datetime.now().isoformat()
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
self.metrics_logger.info(f"Agent Performance: {json.dumps(metric, indent=2)}")
|
| 54 |
+
|
| 55 |
+
def log_system_health(self,
|
| 56 |
+
cpu_usage: float,
|
| 57 |
+
memory_usage: float,
|
| 58 |
+
active_users: int,
|
| 59 |
+
active_sessions: int):
|
| 60 |
+
"""Log system health metrics"""
|
| 61 |
+
metric = {
|
| 62 |
+
"metric_type": "system_health",
|
| 63 |
+
"cpu_usage": cpu_usage,
|
| 64 |
+
"memory_usage": memory_usage,
|
| 65 |
+
"active_users": active_users,
|
| 66 |
+
"active_sessions": active_sessions,
|
| 67 |
+
"timestamp": datetime.now().isoformat()
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
self.metrics_logger.info(f"System Health: {json.dumps(metric, indent=2)}")
|
| 71 |
+
|
| 72 |
+
def log_error(self,
|
| 73 |
+
error_type: str,
|
| 74 |
+
error_message: str,
|
| 75 |
+
severity: str,
|
| 76 |
+
context: Optional[Dict] = None):
|
| 77 |
+
"""Log error events"""
|
| 78 |
+
event = {
|
| 79 |
+
"event_type": "error",
|
| 80 |
+
"error_type": error_type,
|
| 81 |
+
"error_message": error_message,
|
| 82 |
+
"severity": severity,
|
| 83 |
+
"context": context or {},
|
| 84 |
+
"timestamp": datetime.now().isoformat()
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
self.logger.error(f"Error Event: {json.dumps(event, indent=2)}")
|
| 88 |
+
|
| 89 |
+
def log_security_event(self,
|
| 90 |
+
event_type: str,
|
| 91 |
+
user_id: str,
|
| 92 |
+
success: bool,
|
| 93 |
+
details: Optional[Dict] = None):
|
| 94 |
+
"""Log security-related events"""
|
| 95 |
+
event = {
|
| 96 |
+
"event_type": "security",
|
| 97 |
+
"security_event_type": event_type,
|
| 98 |
+
"user_id": user_id,
|
| 99 |
+
"success": success,
|
| 100 |
+
"details": details or {},
|
| 101 |
+
"timestamp": datetime.now().isoformat()
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
self.logger.info(f"Security Event: {json.dumps(event, indent=2)}")
|
| 105 |
+
|
| 106 |
+
def log_model_performance(self,
|
| 107 |
+
model_name: str,
|
| 108 |
+
operation: str,
|
| 109 |
+
input_tokens: int,
|
| 110 |
+
output_tokens: int,
|
| 111 |
+
response_time: float,
|
| 112 |
+
success: bool):
|
| 113 |
+
"""Log AI model performance metrics"""
|
| 114 |
+
metric = {
|
| 115 |
+
"metric_type": "model_performance",
|
| 116 |
+
"model_name": model_name,
|
| 117 |
+
"operation": operation,
|
| 118 |
+
"input_tokens": input_tokens,
|
| 119 |
+
"output_tokens": output_tokens,
|
| 120 |
+
"response_time": response_time,
|
| 121 |
+
"success": success,
|
| 122 |
+
"timestamp": datetime.now().isoformat()
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
self.metrics_logger.info(f"Model Performance: {json.dumps(metric, indent=2)}")
|
| 126 |
+
|
| 127 |
+
def log_user_feedback(self,
|
| 128 |
+
user_id: str,
|
| 129 |
+
interaction_id: str,
|
| 130 |
+
rating: int,
|
| 131 |
+
feedback_text: Optional[str] = None):
|
| 132 |
+
"""Log user feedback"""
|
| 133 |
+
event = {
|
| 134 |
+
"event_type": "user_feedback",
|
| 135 |
+
"user_id": user_id,
|
| 136 |
+
"interaction_id": interaction_id,
|
| 137 |
+
"rating": rating,
|
| 138 |
+
"feedback_text": feedback_text,
|
| 139 |
+
"timestamp": datetime.now().isoformat()
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
self.logger.info(f"User Feedback: {json.dumps(event, indent=2)}")
|
| 143 |
+
|
| 144 |
+
def log_session_metrics(self,
|
| 145 |
+
session_id: str,
|
| 146 |
+
user_id: str,
|
| 147 |
+
session_type: str,
|
| 148 |
+
start_time: str,
|
| 149 |
+
end_time: str,
|
| 150 |
+
metrics: Dict[str, Any]):
|
| 151 |
+
"""Log session-specific metrics"""
|
| 152 |
+
session_data = {
|
| 153 |
+
"metric_type": "session_metrics",
|
| 154 |
+
"session_id": session_id,
|
| 155 |
+
"user_id": user_id,
|
| 156 |
+
"session_type": session_type,
|
| 157 |
+
"start_time": start_time,
|
| 158 |
+
"end_time": end_time,
|
| 159 |
+
"duration": self._calculate_duration(start_time, end_time),
|
| 160 |
+
"metrics": metrics,
|
| 161 |
+
"timestamp": datetime.now().isoformat()
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
self.metrics_logger.info(f"Session Metrics: {json.dumps(session_data, indent=2)}")
|
| 165 |
+
|
| 166 |
+
def _calculate_duration(self, start_time: str, end_time: str) -> float:
|
| 167 |
+
"""Calculate duration between two ISO format timestamps"""
|
| 168 |
+
start = datetime.fromisoformat(start_time)
|
| 169 |
+
end = datetime.fromisoformat(end_time)
|
| 170 |
+
return (end - start).total_seconds()
|
utils/log_manager.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
from logging.handlers import RotatingFileHandler
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
class LogManager:
|
| 8 |
+
"""Manages logging configuration and rotation for all agents"""
|
| 9 |
+
|
| 10 |
+
def __init__(self, log_dir: str = "logs", max_bytes: int = 5_000_000, backup_count: int = 5):
|
| 11 |
+
"""Initialize log manager
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
log_dir: Directory to store log files
|
| 15 |
+
max_bytes: Maximum size of each log file before rotation
|
| 16 |
+
backup_count: Number of backup files to keep
|
| 17 |
+
"""
|
| 18 |
+
self.log_dir = Path(log_dir)
|
| 19 |
+
self.max_bytes = max_bytes
|
| 20 |
+
self.backup_count = backup_count
|
| 21 |
+
|
| 22 |
+
# Create log directories
|
| 23 |
+
self._create_log_dirs()
|
| 24 |
+
|
| 25 |
+
# Configure root logger
|
| 26 |
+
self._configure_root_logger()
|
| 27 |
+
|
| 28 |
+
def _create_log_dirs(self):
|
| 29 |
+
"""Create necessary log directories"""
|
| 30 |
+
dirs = [
|
| 31 |
+
self.log_dir,
|
| 32 |
+
self.log_dir / "agents",
|
| 33 |
+
self.log_dir / "system",
|
| 34 |
+
self.log_dir / "analytics"
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
for dir_path in dirs:
|
| 38 |
+
dir_path.mkdir(parents=True, exist_ok=True)
|
| 39 |
+
|
| 40 |
+
def _configure_root_logger(self):
|
| 41 |
+
"""Configure the root logger"""
|
| 42 |
+
root_logger = logging.getLogger()
|
| 43 |
+
root_logger.setLevel(logging.INFO)
|
| 44 |
+
|
| 45 |
+
# System log handler
|
| 46 |
+
system_handler = RotatingFileHandler(
|
| 47 |
+
self.log_dir / "system" / "system.log",
|
| 48 |
+
maxBytes=self.max_bytes,
|
| 49 |
+
backupCount=self.backup_count
|
| 50 |
+
)
|
| 51 |
+
system_handler.setLevel(logging.INFO)
|
| 52 |
+
formatter = logging.Formatter(
|
| 53 |
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| 54 |
+
)
|
| 55 |
+
system_handler.setFormatter(formatter)
|
| 56 |
+
root_logger.addHandler(system_handler)
|
| 57 |
+
|
| 58 |
+
def get_agent_logger(self, agent_name: str, log_level: int = logging.INFO) -> logging.Logger:
|
| 59 |
+
"""Get a configured logger for an agent
|
| 60 |
+
|
| 61 |
+
Args:
|
| 62 |
+
agent_name: Name of the agent (used in log file name)
|
| 63 |
+
log_level: Logging level for this logger
|
| 64 |
+
|
| 65 |
+
Returns:
|
| 66 |
+
Configured logger instance
|
| 67 |
+
"""
|
| 68 |
+
logger = logging.getLogger(f"agent.{agent_name}")
|
| 69 |
+
logger.setLevel(log_level)
|
| 70 |
+
|
| 71 |
+
# Remove any existing handlers
|
| 72 |
+
logger.handlers = []
|
| 73 |
+
|
| 74 |
+
# Add rotating file handler
|
| 75 |
+
handler = RotatingFileHandler(
|
| 76 |
+
self.log_dir / "agents" / f"{agent_name}.log",
|
| 77 |
+
maxBytes=self.max_bytes,
|
| 78 |
+
backupCount=self.backup_count
|
| 79 |
+
)
|
| 80 |
+
handler.setLevel(log_level)
|
| 81 |
+
formatter = logging.Formatter(
|
| 82 |
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| 83 |
+
)
|
| 84 |
+
handler.setFormatter(formatter)
|
| 85 |
+
logger.addHandler(handler)
|
| 86 |
+
|
| 87 |
+
return logger
|
| 88 |
+
|
| 89 |
+
def get_analytics_logger(self, name: str, log_level: int = logging.INFO) -> logging.Logger:
|
| 90 |
+
"""Get a configured logger for analytics
|
| 91 |
+
|
| 92 |
+
Args:
|
| 93 |
+
name: Analytics category name
|
| 94 |
+
log_level: Logging level for this logger
|
| 95 |
+
|
| 96 |
+
Returns:
|
| 97 |
+
Configured logger instance
|
| 98 |
+
"""
|
| 99 |
+
logger = logging.getLogger(f"analytics.{name}")
|
| 100 |
+
logger.setLevel(log_level)
|
| 101 |
+
|
| 102 |
+
# Remove any existing handlers
|
| 103 |
+
logger.handlers = []
|
| 104 |
+
|
| 105 |
+
# Add rotating file handler
|
| 106 |
+
handler = RotatingFileHandler(
|
| 107 |
+
self.log_dir / "analytics" / f"{name}.log",
|
| 108 |
+
maxBytes=self.max_bytes,
|
| 109 |
+
backupCount=self.backup_count
|
| 110 |
+
)
|
| 111 |
+
handler.setLevel(log_level)
|
| 112 |
+
formatter = logging.Formatter(
|
| 113 |
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
| 114 |
+
)
|
| 115 |
+
handler.setFormatter(formatter)
|
| 116 |
+
logger.addHandler(handler)
|
| 117 |
+
|
| 118 |
+
return logger
|
| 119 |
+
|
| 120 |
+
def cleanup_old_logs(self, max_age_days: int = 30):
|
| 121 |
+
"""Clean up log files older than specified days
|
| 122 |
+
|
| 123 |
+
Args:
|
| 124 |
+
max_age_days: Maximum age of log files in days
|
| 125 |
+
"""
|
| 126 |
+
import time
|
| 127 |
+
current_time = time.time()
|
| 128 |
+
max_age_seconds = max_age_days * 24 * 60 * 60
|
| 129 |
+
|
| 130 |
+
for root, _, files in os.walk(self.log_dir):
|
| 131 |
+
for file in files:
|
| 132 |
+
file_path = os.path.join(root, file)
|
| 133 |
+
if os.path.getmtime(file_path) < (current_time - max_age_seconds):
|
| 134 |
+
try:
|
| 135 |
+
os.remove(file_path)
|
| 136 |
+
logging.info(f"Removed old log file: {file_path}")
|
| 137 |
+
except Exception as e:
|
| 138 |
+
logging.error(f"Error removing old log file {file_path}: {str(e)}")
|
| 139 |
+
|
| 140 |
+
def get_log_stats(self) -> dict:
|
| 141 |
+
"""Get statistics about log files
|
| 142 |
+
|
| 143 |
+
Returns:
|
| 144 |
+
Dictionary containing log statistics
|
| 145 |
+
"""
|
| 146 |
+
stats = {
|
| 147 |
+
"total_size": 0,
|
| 148 |
+
"file_count": 0,
|
| 149 |
+
"categories": {}
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
for root, _, files in os.walk(self.log_dir):
|
| 153 |
+
category = os.path.basename(root)
|
| 154 |
+
if category not in stats["categories"]:
|
| 155 |
+
stats["categories"][category] = {
|
| 156 |
+
"size": 0,
|
| 157 |
+
"file_count": 0
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
for file in files:
|
| 161 |
+
file_path = os.path.join(root, file)
|
| 162 |
+
size = os.path.getsize(file_path)
|
| 163 |
+
|
| 164 |
+
stats["total_size"] += size
|
| 165 |
+
stats["file_count"] += 1
|
| 166 |
+
stats["categories"][category]["size"] += size
|
| 167 |
+
stats["categories"][category]["file_count"] += 1
|
| 168 |
+
|
| 169 |
+
return stats
|