streaming-digit-classifier / utils /logging_utils.py
Pranav Mishra
Initial backend deployment - Flask API with ML models
1772a46
Raw
History Blame Contribute Delete
7.41 kB
import logging
import time
from typing import Dict, List, Any
from collections import defaultdict, deque
import json
class PerformanceLogger:
"""
Performance logger for tracking audio processing metrics.
Provides detailed logging and statistics for each processing method.
"""
def __init__(self, max_history: int = 100):
self.max_history = max_history
self.method_stats = defaultdict(lambda: {
'predictions': deque(maxlen=max_history),
'inference_times': deque(maxlen=max_history),
'errors': deque(maxlen=max_history),
'total_calls': 0,
'total_errors': 0
})
# Setup structured logging
self.setup_logging()
def setup_logging(self):
"""Setup structured logging with proper formatting."""
# Create custom formatter
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
# Setup console handler
console_handler = logging.StreamHandler()
console_handler.setFormatter(formatter)
# Setup file handler
file_handler = logging.FileHandler('audio_digit_classifier.log')
file_handler.setFormatter(formatter)
# Configure root logger
logging.basicConfig(
level=logging.DEBUG,
handlers=[console_handler, file_handler]
)
self.logger = logging.getLogger(__name__)
def log_prediction(self, method: str, result: Dict[str, Any]):
"""
Log a prediction result with performance metrics.
Args:
method: Processing method name
result: Prediction result dictionary
"""
stats = self.method_stats[method]
stats['total_calls'] += 1
if result.get('success', True):
stats['predictions'].append({
'digit': result.get('predicted_digit'),
'timestamp': result.get('timestamp', time.time()),
'inference_time': result.get('inference_time', 0)
})
stats['inference_times'].append(result.get('inference_time', 0))
self.logger.info(json.dumps({
'event': 'prediction',
'method': method,
'digit': result.get('predicted_digit'),
'inference_time': result.get('inference_time'),
'timestamp': result.get('timestamp')
}))
else:
stats['total_errors'] += 1
stats['errors'].append({
'error': result.get('error'),
'timestamp': result.get('timestamp', time.time()),
'inference_time': result.get('inference_time', 0)
})
self.logger.error(json.dumps({
'event': 'error',
'method': method,
'error': result.get('error'),
'timestamp': result.get('timestamp')
}))
def get_method_stats(self, method: str) -> Dict[str, Any]:
"""
Get performance statistics for a specific method.
Args:
method: Processing method name
Returns:
Dictionary with performance statistics
"""
stats = self.method_stats[method]
inference_times = list(stats['inference_times'])
if not inference_times:
return {
'method': method,
'total_calls': stats['total_calls'],
'successful_predictions': 0,
'error_rate': 0.0,
'avg_inference_time': 0.0,
'min_inference_time': 0.0,
'max_inference_time': 0.0
}
successful_predictions = len(inference_times)
error_rate = stats['total_errors'] / stats['total_calls'] if stats['total_calls'] > 0 else 0
return {
'method': method,
'total_calls': stats['total_calls'],
'successful_predictions': successful_predictions,
'error_rate': round(error_rate * 100, 2),
'avg_inference_time': round(sum(inference_times) / len(inference_times), 3),
'min_inference_time': round(min(inference_times), 3),
'max_inference_time': round(max(inference_times), 3),
'recent_predictions': list(stats['predictions'])[-10:] # Last 10 predictions
}
def get_all_stats(self) -> Dict[str, Any]:
"""Get statistics for all processing methods."""
all_stats = {}
for method in self.method_stats.keys():
all_stats[method] = self.get_method_stats(method)
return all_stats
def get_comparison_report(self) -> str:
"""
Generate a comparison report of all processing methods.
Returns:
Formatted string with method comparison
"""
all_stats = self.get_all_stats()
if not all_stats:
return "No statistics available yet."
report = "\n=== Audio Processing Method Comparison ===\n\n"
for method, stats in all_stats.items():
report += f"Method: {method}\n"
report += f" Total Calls: {stats['total_calls']}\n"
report += f" Successful: {stats['successful_predictions']}\n"
report += f" Error Rate: {stats['error_rate']}%\n"
report += f" Avg Time: {stats['avg_inference_time']}s\n"
report += f" Min/Max: {stats['min_inference_time']}s / {stats['max_inference_time']}s\n"
report += "\n"
# Find best performing method
if len(all_stats) > 1:
best_speed = min(all_stats.items(), key=lambda x: x[1]['avg_inference_time'])
best_accuracy = min(all_stats.items(), key=lambda x: x[1]['error_rate'])
report += f"Fastest Method: {best_speed[0]} ({best_speed[1]['avg_inference_time']}s avg)\n"
report += f"Most Accurate: {best_accuracy[0]} ({best_accuracy[1]['error_rate']}% error rate)\n"
return report
def log_system_info(self, info: Dict[str, Any]):
"""Log system information for debugging."""
self.logger.info(json.dumps({
'event': 'system_info',
'timestamp': time.time(),
**info
}))
def log_audio_info(self, duration: float, format_info: Dict[str, Any]):
"""Log audio input information."""
self.logger.debug(json.dumps({
'event': 'audio_input',
'duration': duration,
'format': format_info,
'timestamp': time.time()
}))
# Global performance logger instance
performance_logger = PerformanceLogger()
def setup_flask_logging(app):
"""Setup logging configuration for Flask application."""
if not app.debug:
# Production logging
file_handler = logging.FileHandler('flask_app.log')
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s %(name)s %(message)s'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Audio Digit Classifier startup')