Основа для логгера

This commit is contained in:
2025-09-04 17:13:39 +03:00
parent 0f3340c899
commit bbbfbbd508
2 changed files with 50 additions and 38 deletions

View File

@@ -6,10 +6,14 @@ import json
import zipfile import zipfile
import tempfile import tempfile
import shutil import shutil
import logging
from typing import Dict, Any, List, Optional from typing import Dict, Any, List, Optional
from core.ports import ParserPort from core.ports import ParserPort
from adapters.pconfig import SINGLE_OGS, replace_id_in_path, find_header_row, data_to_json from adapters.pconfig import SINGLE_OGS, replace_id_in_path, find_header_row, data_to_json
# Настройка логгера для модуля
logger = logging.getLogger(__name__)
class SvodkaPMParser(ParserPort): class SvodkaPMParser(ParserPort):
"""Парсер для сводок ПМ (план и факт)""" """Парсер для сводок ПМ (план и факт)"""
@@ -51,17 +55,17 @@ class SvodkaPMParser(ParserPort):
# Разархивируем файл # Разархивируем файл
with zipfile.ZipFile(file_path, 'r') as zip_ref: with zipfile.ZipFile(file_path, 'r') as zip_ref:
zip_ref.extractall(temp_dir) zip_ref.extractall(temp_dir)
print(f"📦 Архив разархивирован в: {temp_dir}") logger.info(f"📦 Архив разархивирован в: {temp_dir}")
# Посмотрим, что находится в архиве # Посмотрим, что находится в архиве
print(f"🔍 Содержимое архива:") logger.debug(f"🔍 Содержимое архива:")
for root, dirs, files in os.walk(temp_dir): for root, dirs, files in os.walk(temp_dir):
level = root.replace(temp_dir, '').count(os.sep) level = root.replace(temp_dir, '').count(os.sep)
indent = ' ' * 2 * level indent = ' ' * 2 * level
print(f"{indent}{os.path.basename(root)}/") logger.debug(f"{indent}{os.path.basename(root)}/")
subindent = ' ' * 2 * (level + 1) subindent = ' ' * 2 * (level + 1)
for file in files: for file in files:
print(f"{subindent}{file}") logger.debug(f"{subindent}{file}")
# Создаем словари для хранения данных как в оригинале # Создаем словари для хранения данных как в оригинале
df_pm_facts = {} # Словарь с данными факта, ключ - ID ОГ df_pm_facts = {} # Словарь с данными факта, ключ - ID ОГ
@@ -80,8 +84,8 @@ class SvodkaPMParser(ParserPort):
elif 'plan' in file.lower() or 'план' in file.lower(): elif 'plan' in file.lower() or 'план' in file.lower():
plan_files.append(full_path) plan_files.append(full_path)
print(f"📊 Найдено файлов факта: {len(fact_files)}") logger.info(f"📊 Найдено файлов факта: {len(fact_files)}")
print(f"📊 Найдено файлов плана: {len(plan_files)}") logger.info(f"📊 Найдено файлов плана: {len(plan_files)}")
# Обрабатываем найденные файлы # Обрабатываем найденные файлы
for fact_file in fact_files: for fact_file in fact_files:
@@ -91,9 +95,9 @@ class SvodkaPMParser(ParserPort):
if 'svodka_fact_pm_' in filename: if 'svodka_fact_pm_' in filename:
og_id = filename.replace('svodka_fact_pm_', '').replace('.xlsx', '').replace('.xlsm', '') og_id = filename.replace('svodka_fact_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
if og_id in SINGLE_OGS: if og_id in SINGLE_OGS:
print(f'📊 Загрузка факта: {fact_file} (ОГ: {og_id})') logger.info(f'📊 Загрузка факта: {fact_file} (ОГ: {og_id})')
df_pm_facts[og_id] = self._parse_svodka_pm(fact_file, 'Сводка Нефтепереработка') df_pm_facts[og_id] = self._parse_svodka_pm(fact_file, 'Сводка Нефтепереработка')
print(f"✅ Факт загружен для {og_id}") logger.info(f"✅ Факт загружен для {og_id}")
for plan_file in plan_files: for plan_file in plan_files:
# Извлекаем ID ОГ из имени файла # Извлекаем ID ОГ из имени файла
@@ -102,9 +106,9 @@ class SvodkaPMParser(ParserPort):
if 'svodka_plan_pm_' in filename: if 'svodka_plan_pm_' in filename:
og_id = filename.replace('svodka_plan_pm_', '').replace('.xlsx', '').replace('.xlsm', '') og_id = filename.replace('svodka_plan_pm_', '').replace('.xlsx', '').replace('.xlsm', '')
if og_id in SINGLE_OGS: if og_id in SINGLE_OGS:
print(f'📊 Загрузка плана: {plan_file} (ОГ: {og_id})') logger.info(f'📊 Загрузка плана: {plan_file} (ОГ: {og_id})')
df_pm_plans[og_id] = self._parse_svodka_pm(plan_file, 'Сводка Нефтепереработка') df_pm_plans[og_id] = self._parse_svodka_pm(plan_file, 'Сводка Нефтепереработка')
print(f"✅ План загружен для {og_id}") logger.info(f"✅ План загружен для {og_id}")
# Инициализируем None для ОГ, для которых файлы не найдены # Инициализируем None для ОГ, для которых файлы не найдены
for og_id in SINGLE_OGS: for og_id in SINGLE_OGS:
@@ -123,14 +127,14 @@ class SvodkaPMParser(ParserPort):
'df_pm_plans': df_pm_plans 'df_pm_plans': df_pm_plans
} }
print(f"🎯 Обработано ОГ: {len([k for k, v in df_pm_facts.items() if v is not None])} факт, {len([k for k, v in df_pm_plans.items() if v is not None])} план") logger.info(f"🎯 Обработано ОГ: {len([k for k, v in df_pm_facts.items() if v is not None])} факт, {len([k for k, v in df_pm_plans.items() if v is not None])} план")
return result return result
finally: finally:
# Удаляем временную директорию # Удаляем временную директорию
shutil.rmtree(temp_dir, ignore_errors=True) shutil.rmtree(temp_dir, ignore_errors=True)
print(f"🗑️ Временная директория удалена: {temp_dir}") logger.debug(f"🗑️ Временная директория удалена: {temp_dir}")
def _parse_svodka_pm(self, file_path: str, sheet_name: str, header_num: Optional[int] = None) -> pd.DataFrame: def _parse_svodka_pm(self, file_path: str, sheet_name: str, header_num: Optional[int] = None) -> pd.DataFrame:
"""Парсинг отчетов одного ОГ для БП, ПП и факта""" """Парсинг отчетов одного ОГ для БП, ПП и факта"""
@@ -226,19 +230,19 @@ class SvodkaPMParser(ParserPort):
def _get_svodka_value(self, df_svodka: pd.DataFrame, og_id: str, code: int, search_value: Optional[str] = None): def _get_svodka_value(self, df_svodka: pd.DataFrame, og_id: str, code: int, search_value: Optional[str] = None):
"""Служебная функция для простой выборке по сводке""" """Служебная функция для простой выборке по сводке"""
print(f"🔍 DEBUG: Ищем код '{code}' для ОГ '{og_id}' в DataFrame с {len(df_svodka)} строками") logger.debug(f"🔍 DEBUG: Ищем код '{code}' для ОГ '{og_id}' в DataFrame с {len(df_svodka)} строками")
print(f"🔍 DEBUG: Первая строка данных: {df_svodka.iloc[0].tolist()}") logger.debug(f"🔍 DEBUG: Первая строка данных: {df_svodka.iloc[0].tolist()}")
print(f"🔍 DEBUG: Доступные индексы: {list(df_svodka.index)}") logger.debug(f"🔍 DEBUG: Доступные индексы: {list(df_svodka.index)}")
print(f"🔍 DEBUG: Доступные столбцы: {list(df_svodka.columns)}") logger.debug(f"🔍 DEBUG: Доступные столбцы: {list(df_svodka.columns)}")
# Проверяем, есть ли код в индексе # Проверяем, есть ли код в индексе
if code not in df_svodka.index: if code not in df_svodka.index:
print(f"⚠️ Код '{code}' не найден в индексе") logger.warning(f"⚠️ Код '{code}' не найден в индексе")
return 0 return 0
# Получаем позицию строки с кодом # Получаем позицию строки с кодом
code_row_loc = df_svodka.index.get_loc(code) code_row_loc = df_svodka.index.get_loc(code)
print(f"🔍 DEBUG: Код '{code}' в позиции {code_row_loc}") logger.debug(f"🔍 DEBUG: Код '{code}' в позиции {code_row_loc}")
# Определяем позиции для поиска # Определяем позиции для поиска
if search_value is None: if search_value is None:
@@ -254,14 +258,14 @@ class SvodkaPMParser(ParserPort):
if col_name == search_value: if col_name == search_value:
target_positions.append(i) target_positions.append(i)
print(f"🔍 DEBUG: Найдены позиции для '{search_value}': {target_positions[:5]}...") logger.debug(f"🔍 DEBUG: Найдены позиции для '{search_value}': {target_positions[:5]}...")
print(f"🔍 DEBUG: Позиции в первой строке: {target_positions[:5]}...") logger.debug(f"🔍 DEBUG: Позиции в первой строке: {target_positions[:5]}...")
print(f"🔍 DEBUG: Ищем столбцы с названием '{search_value}'") logger.debug(f"🔍 DEBUG: Ищем столбцы с названием '{search_value}'")
print(f"🔍 DEBUG: Целевые позиции: {target_positions[:10]}...") logger.debug(f"🔍 DEBUG: Целевые позиции: {target_positions[:10]}...")
if not target_positions: if not target_positions:
print(f"⚠️ Позиции '{search_value}' не найдены") logger.warning(f"⚠️ Позиции '{search_value}' не найдены")
return 0 return 0
# Извлекаем значения из найденных позиций # Извлекаем значения из найденных позиций
@@ -285,7 +289,7 @@ class SvodkaPMParser(ParserPort):
# Преобразуем в числовой формат # Преобразуем в числовой формат
numeric_values = pd.to_numeric(values, errors='coerce') numeric_values = pd.to_numeric(values, errors='coerce')
print(f"🔍 DEBUG: Числовые значения (первые 5): {numeric_values.tolist()[:5]}") logger.debug(f"🔍 DEBUG: Числовые значения (первые 5): {numeric_values.tolist()[:5]}")
# Попробуем альтернативное преобразование # Попробуем альтернативное преобразование
try: try:
@@ -301,10 +305,10 @@ class SvodkaPMParser(ParserPort):
except (ValueError, TypeError): except (ValueError, TypeError):
manual_values.append(0) manual_values.append(0)
print(f"🔍 DEBUG: Ручное преобразование (первые 5): {manual_values[:5]}") logger.debug(f"🔍 DEBUG: Ручное преобразование (первые 5): {manual_values[:5]}")
numeric_values = pd.Series(manual_values) numeric_values = pd.Series(manual_values)
except Exception as e: except Exception as e:
print(f"⚠️ Ошибка при ручном преобразовании: {e}") logger.warning(f"⚠️ Ошибка при ручном преобразовании: {e}")
# Используем исходные значения # Используем исходные значения
numeric_values = pd.Series([0 if pd.isna(v) or v is None else v for v in values]) numeric_values = pd.Series([0 if pd.isna(v) or v is None else v for v in values])
@@ -338,7 +342,7 @@ class SvodkaPMParser(ParserPort):
# Получаем данные из сохраненных словарей (через self.df) # Получаем данные из сохраненных словарей (через self.df)
if not hasattr(self, 'df') or self.df is None: if not hasattr(self, 'df') or self.df is None:
print("❌ Данные не загружены. Сначала загрузите ZIP архив.") logger.error("❌ Данные не загружены. Сначала загрузите ZIP архив.")
return {col: {str(code): None for code in codes} for col in columns} return {col: {str(code): None for code in codes} for col in columns}
# Извлекаем словари из сохраненных данных # Извлекаем словари из сохраненных данных
@@ -349,10 +353,10 @@ class SvodkaPMParser(ParserPort):
fact_df = df_pm_facts.get(og_id) fact_df = df_pm_facts.get(og_id)
plan_df = df_pm_plans.get(og_id) plan_df = df_pm_plans.get(og_id)
print(f"🔍 ===== НАЧАЛО ОБРАБОТКИ ОГ {og_id} =====") logger.debug(f"🔍 ===== НАЧАЛО ОБРАБОТКИ ОГ {og_id} =====")
print(f"🔍 Коды: {codes}") logger.debug(f"🔍 Коды: {codes}")
print(f"🔍 Столбцы: {columns}") logger.debug(f"🔍 Столбцы: {columns}")
print(f"🔍 Получены данные для {og_id}: факт={'' if fact_df is not None else ''}, план={'' if plan_df is not None else ''}") logger.debug(f"🔍 Получены данные для {og_id}: факт={'' if fact_df is not None else ''}, план={'' if plan_df is not None else ''}")
# Определяем, какие столбцы из какого датафрейма брать # Определяем, какие столбцы из какого датафрейма брать
for col in columns: for col in columns:
@@ -360,24 +364,24 @@ class SvodkaPMParser(ParserPort):
if col in ['ПП', 'БП']: if col in ['ПП', 'БП']:
if plan_df is None: if plan_df is None:
print(f"❌ Невозможно обработать '{col}': нет данных плана для {og_id}") logger.warning(f"❌ Невозможно обработать '{col}': нет данных плана для {og_id}")
else: else:
print(f"🔍 DEBUG: ===== ОБРАБАТЫВАЕМ '{col}' ИЗ ДАННЫХ ПЛАНА =====") logger.debug(f"🔍 DEBUG: ===== ОБРАБАТЫВАЕМ '{col}' ИЗ ДАННЫХ ПЛАНА =====")
for code in codes: for code in codes:
print(f"🔍 DEBUG: --- Код {code} для {col} ---") logger.debug(f"🔍 DEBUG: --- Код {code} для {col} ---")
val = self._get_svodka_value(plan_df, og_id, code, col) val = self._get_svodka_value(plan_df, og_id, code, col)
col_result[str(code)] = val col_result[str(code)] = val
print(f"🔍 DEBUG: ===== ЗАВЕРШИЛИ ОБРАБОТКУ '{col}' =====") logger.debug(f"🔍 DEBUG: ===== ЗАВЕРШИЛИ ОБРАБОТКУ '{col}' =====")
elif col in ['ТБ', 'СЭБ', 'НЭБ']: elif col in ['ТБ', 'СЭБ', 'НЭБ']:
if fact_df is None: if fact_df is None:
print(f"❌ Невозможно обработать '{col}': нет данных факта для {og_id}") logger.warning(f"❌ Невозможно обработать '{col}': нет данных факта для {og_id}")
else: else:
for code in codes: for code in codes:
val = self._get_svodka_value(fact_df, og_id, code, col) val = self._get_svodka_value(fact_df, og_id, code, col)
col_result[str(code)] = val col_result[str(code)] = val
else: else:
print(f"⚠️ Неизвестный столбец: '{col}'. Пропускаем.") logger.warning(f"⚠️ Неизвестный столбец: '{col}'. Пропускаем.")
col_result = {str(code): None for code in codes} col_result = {str(code): None for code in codes}
result[col] = col_result result[col] = col_result
@@ -443,7 +447,7 @@ class SvodkaPMParser(ParserPort):
data = self._get_svodka_og(og_id, codes, columns, search) data = self._get_svodka_og(og_id, codes, columns, search)
total_result[og_id] = data total_result[og_id] = data
except Exception as e: except Exception as e:
print(f"❌ Ошибка при обработке {og_id}: {e}") logger.error(f"❌ Ошибка при обработке {og_id}: {e}")
total_result[og_id] = None total_result[og_id] = None
json_result = data_to_json(total_result) json_result = data_to_json(total_result)

View File

@@ -1,10 +1,18 @@
import os import os
import multiprocessing import multiprocessing
import uvicorn import uvicorn
import logging
from typing import Dict, List from typing import Dict, List
from fastapi import FastAPI, File, UploadFile, HTTPException, status from fastapi import FastAPI, File, UploadFile, HTTPException, status
from fastapi.responses import JSONResponse from fastapi.responses import JSONResponse
# Настройка логирования
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(name)s - %(lineno)d - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
from adapters.storage import MinIOStorageAdapter from adapters.storage import MinIOStorageAdapter
from adapters.parsers import SvodkaPMParser, SvodkaCAParser, MonitoringFuelParser, MonitoringTarParser, SvodkaRepairCAParser, StatusesRepairCAParser, OperSpravkaTechPosParser from adapters.parsers import SvodkaPMParser, SvodkaCAParser, MonitoringFuelParser, MonitoringTarParser, SvodkaRepairCAParser, StatusesRepairCAParser, OperSpravkaTechPosParser