""" Performance monitoring functionality for Issue #144. This module provides performance monitoring and optimization capabilities for asset management operations. """ import time from typing import Dict, Any, List, Optional from dataclasses import dataclass, field from contextlib import contextmanager from collections import defaultdict @dataclass class OperationMetrics: """Metrics for a specific operation.""" total_time: float = 0.0 call_count: int = 0 avg_time: float = 0.0 min_time: float = float('inf') max_time: float = 0.0 last_time: float = 0.0 def update(self, execution_time: float): """Update metrics with new execution time.""" self.total_time += execution_time self.call_count += 1 self.avg_time = self.total_time / self.call_count self.min_time = min(self.min_time, execution_time) self.max_time = max(self.max_time, execution_time) self.last_time = execution_time class PerformanceMonitor: """Performance monitoring system for asset operations.""" def __init__(self): """Initialize performance monitor.""" self._metrics: Dict[str, OperationMetrics] = defaultdict(OperationMetrics) self._operation_stack: List[str] = [] @contextmanager def track_operation(self, operation_name: str): """Context manager to track operation performance.""" start_time = time.time() self._operation_stack.append(operation_name) try: yield finally: end_time = time.time() execution_time = end_time - start_time self._metrics[operation_name].update(execution_time) self._operation_stack.pop() @contextmanager def track_query(self, query_name: str): """Context manager to track database query performance.""" start_time = time.time() try: yield finally: end_time = time.time() execution_time = end_time - start_time self._metrics[query_name].update(execution_time) def get_metrics(self) -> Dict[str, Dict[str, Any]]: """Get all performance metrics.""" result = {} for operation_name, metrics in self._metrics.items(): result[operation_name] = { 'total_time': metrics.total_time, 'call_count': metrics.call_count, 'avg_time': metrics.avg_time, 'min_time': metrics.min_time if metrics.min_time != float('inf') else 0.0, 'max_time': metrics.max_time, 'last_time': metrics.last_time } return result def get_slowest_operations(self, limit: int = 10) -> List[Dict[str, Any]]: """Get the slowest operations by average time.""" operations = [] for operation_name, metrics in self._metrics.items(): operations.append({ 'operation': operation_name, 'avg_time': metrics.avg_time, 'total_time': metrics.total_time, 'call_count': metrics.call_count }) # Sort by average time descending operations.sort(key=lambda x: x['avg_time'], reverse=True) return operations[:limit] def reset_metrics(self): """Reset all performance metrics.""" self._metrics.clear() def get_operation_summary(self) -> Dict[str, Any]: """Get summary of all operations.""" if not self._metrics: return { 'total_operations': 0, 'total_time': 0.0, 'avg_operation_time': 0.0 } total_time = sum(metrics.total_time for metrics in self._metrics.values()) total_calls = sum(metrics.call_count for metrics in self._metrics.values()) avg_time = total_time / total_calls if total_calls > 0 else 0.0 return { 'total_operations': len(self._metrics), 'total_calls': total_calls, 'total_time': total_time, 'avg_operation_time': avg_time } class QueryOptimizer: """Database query optimization utilities.""" def __init__(self): """Initialize query optimizer.""" self._query_plans: Dict[str, Dict[str, Any]] = {} def analyze_query_plan(self, query: str) -> Dict[str, Any]: """Analyze query execution plan.""" # Simplified query analysis plan = { 'query_type': self._get_query_type(query), 'estimated_cost': self._estimate_cost(query), 'optimization_suggestions': self._get_suggestions(query) } return plan def _get_query_type(self, query: str) -> str: """Determine query type.""" query_lower = query.lower().strip() if query_lower.startswith('select'): return 'SELECT' elif query_lower.startswith('insert'): return 'INSERT' elif query_lower.startswith('update'): return 'UPDATE' elif query_lower.startswith('delete'): return 'DELETE' else: return 'OTHER' def _estimate_cost(self, query: str) -> float: """Estimate query execution cost.""" # Simplified cost estimation base_cost = 1.0 # Add cost for complexity indicators if 'JOIN' in query.upper(): base_cost += 2.0 if 'GROUP BY' in query.upper(): base_cost += 1.5 if 'ORDER BY' in query.upper(): base_cost += 1.0 if 'LIKE' in query.upper(): base_cost += 0.5 return base_cost def _get_suggestions(self, query: str) -> List[str]: """Get optimization suggestions for query.""" suggestions = [] query_upper = query.upper() if 'SELECT *' in query_upper: suggestions.append("Consider selecting only needed columns instead of SELECT *") if 'WHERE' not in query_upper and 'SELECT' in query_upper: suggestions.append("Consider adding WHERE clause to limit results") if 'ORDER BY' in query_upper and 'LIMIT' not in query_upper: suggestions.append("Consider adding LIMIT when using ORDER BY") return suggestions