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')