Files
syncio/app/logging_utils.py
2026-04-16 17:57:58 +09:00

148 lines
6.0 KiB
Python

import json
import logging
import os
import traceback
from datetime import datetime
from typing import Any, Dict, Optional
from .config import Config
class MigrationLogger:
"""Класс для логирования процесса миграции"""
def __init__(self, config: Config):
self.config = config
self.start_time = datetime.now()
self.timestamp = self.start_time.strftime("%Y%m%d_%H%M%S")
self.log_file = os.path.join(
config.LOG_DIR,
config.LOG_FILE.format(timestamp=self.timestamp)
)
self.stats = {
'total_tables': len(config.TABLES_TO_COPY),
'copied_tables': [],
'failed_tables': [],
'total_rows': 0,
'start_time': self.start_time,
'end_time': None,
'errors': []
}
# Создаем директорию для логов
os.makedirs(config.LOG_DIR, exist_ok=True)
# Настраиваем logging
self.setup_logging()
def setup_logging(self):
"""Настройка системы логирования"""
logging.basicConfig(
level=self.config.LOG_LEVEL,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(self.log_file, encoding='utf-8'),
logging.StreamHandler() # Вывод в консоль
]
)
self.logger = logging.getLogger(__name__)
def log_info(self, message: str):
"""Логирование информационного сообщения"""
self.logger.info(message)
def log_error(self, message: str, exception: Optional[Exception] = None):
"""Логирование ошибки"""
error_details = {
'message': message,
'exception': str(exception) if exception else None,
'traceback': traceback.format_exc() if exception else None,
'timestamp': datetime.now().isoformat()
}
self.stats['errors'].append(error_details)
self.logger.error(f"{message}. Ошибка: {exception}")
def log_warning(self, message: str):
"""Логирование предупреждения"""
self.logger.warning(message)
def log_table_start(self, table_name: str):
"""Логирование начала обработки таблицы"""
self.logger.info(f"{'='*60}")
self.logger.info(f"Начало обработки таблицы: {table_name}")
self.logger.info(f"{'='*60}")
def log_table_success(self, table_name: str, row_count: int):
"""Логирование успешного копирования таблицы"""
self.stats['copied_tables'].append({
'name': table_name,
'row_count': row_count,
'timestamp': datetime.now().isoformat()
})
self.stats['total_rows'] += row_count
self.logger.info(f"Таблица {table_name} успешно скопирована ({row_count} строк)")
def log_table_failure(self, table_name: str, error: str):
"""Логирование ошибки при копировании таблицы"""
self.stats['failed_tables'].append({
'name': table_name,
'error': error,
'timestamp': datetime.now().isoformat()
})
self.logger.error(f"Ошибка при копировании таблицы {table_name}: {error}")
def log_progress(self, table_name: str, chunk_num: int, total_rows: int):
"""Логирование прогресса загрузки"""
self.logger.info(f"Таблица {table_name}: загружено чанков {chunk_num}, строк {total_rows}")
def generate_report(self) -> Dict[str, Any]:
"""Генерация итогового отчета"""
self.stats['end_time'] = datetime.now()
duration = self.stats['end_time'] - self.stats['start_time']
self.stats['duration_seconds'] = duration.total_seconds()
self.stats['duration_human'] = str(duration)
report = {
'summary': {
'total_tables': self.stats['total_tables'],
'successful_tables': len(self.stats['copied_tables']),
'failed_tables': len(self.stats['failed_tables']),
'success_rate': (len(self.stats['copied_tables']) / self.stats['total_tables'] * 100)
if self.stats['total_tables'] > 0 else 0,
'total_rows': self.stats['total_rows'],
'start_time': self.stats['start_time'].isoformat(),
'end_time': self.stats['end_time'].isoformat(),
'duration': self.stats['duration_human']
},
'successful_tables': [
{'name': t['name'], 'rows': t['row_count']}
for t in self.stats['copied_tables']
],
'failed_tables': [
{'name': t['name'], 'error': t['error']}
for t in self.stats['failed_tables']
],
'errors': self.stats['errors']
}
# Сохраняем отчет в JSON
report_file = os.path.join(
self.config.LOG_DIR,
f"migration_report_{self.timestamp}.json"
)
with open(report_file, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2, default=str)
return report
def get_log_content(self) -> str:
"""Получение содержимого лог-файла"""
try:
with open(self.log_file, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
return f"Ошибка при чтении лог-файла: {e}"
# ============================================================================