refactor(logging): add detailed debug logs

This commit is contained in:
2026-08-02 00:44:16 +05:00
parent a74e2eb328
commit 60d67b613a
4 changed files with 172 additions and 83 deletions
+7 -2
View File
@@ -7,14 +7,17 @@ logger = logging.getLogger(__name__)
async def main():
logger.debug("Инициализация Worker")
async with Worker() as worker:
logger.debug("Worker успешно инициализирован")
await worker.check_all()
logger.debug("Worker завершил работу")
if __name__ == "__main__":
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)-7s | %(message)s",
level=logging.DEBUG,
format="%(asctime)s | %(levelname)-7s | %(name)-20s | %(message)s",
datefmt="%H:%M:%S",
handlers=[logging.StreamHandler()],
)
@@ -23,7 +26,9 @@ if __name__ == "__main__":
logging.getLogger("opentele2").setLevel(logging.WARNING)
try:
logger.info("Запуск приложения TDATA-Checker")
asyncio.run(main())
logger.info("Приложение завершено")
except KeyboardInterrupt:
logger.info("Прервано пользователем")
+59 -26
View File
@@ -1,6 +1,7 @@
import logging
from dataclasses import dataclass
from pathlib import Path
from phonenumbers import parse, geocoder
from typing import List, Optional
@@ -32,112 +33,144 @@ class Result:
class Checker:
def __init__(self, path: str):
def __init__(self, path: Path, temp_path: Path):
self.path = path
self.temp_path = temp_path
self.client = None
logger.info(f"Инициализация проверки для пути: {path}")
logger.debug(f"Создание экземпляра Checker для пути: {path}")
try:
self.desktop = TDATA(path=self.path)
self.desktop = TDATA(path=self.path, temp_path=self.temp_path)
logger.debug("TDATA успешно инициализирована")
except Exception as e:
logger.error(f"Ошибка инициализации TDATA: {e}")
self.desktop = None
async def __aenter__(self):
self.__ensure_client()
logger.debug("Вход в контекстный менеджер Checker")
await self.__ensure_client()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
logger.debug("Выход из контекстного менеджера Checker")
if self.client:
logger.debug("Отключение клиента Telethon")
try:
await self.client.disconnect()
logger.debug("Telethon клиент отключен")
except Exception as e:
logger.error(f"Ошибка отключения клиента Telethon: {e}")
logger.warning(f"Ошибка при отключении клиента: {e}")
async def __ensure_client(self):
if self.client is None:
if self.desktop is None:
logger.error("Попытка инициализации клиента с неинициализированной TDATA")
raise Exception("TDATA не инициализирована")
logger.debug("Инициализация клиента Telethon из TDATA")
logger.debug("Конвертация TDATA в Telethon клиент")
self.client = await self.desktop.convert()
logger.debug("Telethon клиент успешно создан")
async def check_stars(self, me: User) -> int:
logger.debug("Запрос баланса звезд")
try:
stars_status = await self.client(GetStarsStatusRequest(peer=me))
return stars_status.balance.amount
stars = stars_status.balance.amount
logger.debug(f"Баланс звезд: {stars}")
return stars
except Exception as e:
logger.warning(f"Не удалось получить баланс звезд: {e}")
return 0
async def check_country(self, me: User) -> str:
logger.debug(f"Определение страны для номера +{me.phone}")
try:
phone_parse = parse(str(f"+{me.phone}"))
return geocoder.description_for_number(phone_parse, "en")
country = geocoder.description_for_number(phone_parse, "ru")
logger.debug(f"Страна определена: {country}")
return country
except Exception as e:
logger.warning(f"Не удалось определить страну: {e}")
return "N/A"
async def check_contacts(self) -> List[User]:
logger.debug("Запрос списка контактов")
try:
logger.debug("Получение контактов")
result = await self.client(GetContactsRequest(hash=0))
return result.users
contacts = result.users
logger.debug(f"Получено контактов: {len(contacts)}")
return contacts
except Exception as e:
logger.warning(f"Не удалось получить контакты: {e}")
return []
async def check_chats(self) -> List[Chat]:
logger.debug("Запрос всех диалогов")
try:
logger.debug("Получение всех диалогов")
chats = []
async for dialog in self.client.iter_dialogs():
chats.append(dialog.entity)
logger.debug(f"Получено диалогов: {len(chats)}")
return chats
except Exception as e:
logger.warning(f"Не удалось получить чаты: {e}")
return []
async def check_channels(self, chats: List[Chat]) -> List[Channel]:
logger.debug(f"Фильтрация каналов из {len(chats)} чатов")
try:
channels = [chat for chat in chats if isinstance(chat, Channel)]
logger.debug(f"Найдено каналов: {len(channels)}")
return channels
except Exception as e:
logger.warning(f"Не удалось отфильтровать каналы: {e}")
return []
async def check_admin_channels(self, channels: List[Channel]) -> List[Channel]:
logger.debug("Проверка прав администратора в каналах")
try:
logger.debug("Проверка прав администратора")
admin_channels = []
checked = 0
for channel in channels:
permissions = await self.client.get_permissions(channel, "me")
if permissions.is_admin or permissions.is_creator:
admin_channels.append(channel)
checked += 1
try:
permissions = await self.client.get_permissions(channel, "me")
if permissions.is_admin or permissions.is_creator:
admin_channels.append(channel)
logger.debug(f"Найден админ канал: {channel.title}")
except Exception as e:
logger.debug(f"Не удалось проверить права для канала: {e}")
logger.debug(f"Проверено каналов: {checked}, найдено админских: {len(admin_channels)}")
return admin_channels
except Exception as e:
logger.warning(f"Не удалось проверить админские права: {e}")
return []
async def check_all(self) -> Result:
logger.debug("Начало полной проверки аккаунта")
try:
me = await self.client.get_me()
if not me:
logger.error("Не удалось получить информацию о пользователе")
raise SessionInvalid()
# Собираем данные с обработкой ошибок
stars = self.check_stars(me=me)
country = self.check_country(me=me)
logger.debug(f"Получен пользователь: {me.first_name} (+{me.phone})")
contacts = self.check_contacts()
chats = self.check_chats()
channels = [] if chats == [] else self.check_channels(chats=chats)
admin_channels = (
[] if channels == [] else self.check_admin_channels(channels=channels)
)
stars = await self.check_stars(me=me)
country = await self.check_country(me=me)
contacts = await self.check_contacts()
chats = await self.check_chats()
channels = await self.check_channels(chats=chats) if chats else []
admin_channels = await self.check_admin_channels(channels=channels) if channels else []
logger.debug("Полная проверка завершена успешно")
return Result(
me=me,
stars=stars,
+32 -16
View File
@@ -17,6 +17,7 @@ logger = logging.getLogger(__name__)
class TDATA:
def __init__(self, path: Path, temp_path: Path):
logger.debug(f"Инициализация TDATA с путем: {path}")
try:
self.path = path
self.temp_path = temp_path
@@ -27,21 +28,26 @@ class TDATA:
self.desktop = None
self.telethon = None
self.api = API.TelegramDesktop
logger.debug("Загрузка TDesktop")
self.desktop = self.__get_telegram_desktop()
logger.debug(f"TDATA инициализирована с путем: {self.path}")
if self.desktop:
logger.debug("TDesktop успешно загружен")
except Exception as e:
logger.error(f"Не удалось инициализировать TDATA: {e}")
raise
def __get_telegram_desktop(self) -> TDesktop | None:
logger.debug("Попытка загрузки TDesktop")
try:
if self.desktop:
return self.desktop
return TDesktop(self.path.absolute(), api=self.api)
desktop = TDesktop(self.path.absolute(), api=self.api)
logger.debug("TDesktop создан успешно")
return desktop
except TFileNotFound as e:
logger.warning(f"Файлы TDATA не найдены или неполные: {e}")
@@ -52,27 +58,35 @@ class TDATA:
raise
def __gen_session_path(self) -> str:
logger.debug("Генерация пути сессии")
logger.debug("Генерация уникального пути для сессии")
tempPath = f"temp/{uuid4()}.session"
while Path(tempPath).exists():
logger.debug(f"Путь сессии '{tempPath}' существует, генерация нового")
logger.debug(f"Путь сессии '{tempPath}' уже существует, генерация нового")
tempPath = f"temp/{uuid4()}.session"
logger.debug(f"Сгенерирован путь сессии: {tempPath}")
return tempPath
async def validate(self) -> bool:
logger.debug("Валидация TDATA")
if self.desktop is None:
logger.warning("TDesktop не инициализирован, TDATA невалидна")
logger.warning("TDesktop не инициализирован")
return False
return self.desktop.isLoaded()
is_loaded = self.desktop.isLoaded()
if is_loaded:
logger.debug("TDATA содержит загруженные аккаунты")
else:
logger.warning("TDATA не содержит загруженных аккаунтов")
async def valid(self, client: TelegramClient, disconnect: bool = True) -> bool:
return is_loaded
async def is_valid(self, client: TelegramClient, disconnect: bool = True) -> bool:
logger.debug("Проверка авторизации Telethon клиента")
try:
logger.debug("Проверка авторизации клиента Telethon")
await client.connect()
logger.debug("Подключение к Telegram установлено")
authorized = await client.is_user_authorized()
@@ -84,8 +98,8 @@ class TDATA:
self.telethon = client
return True
except:
logger.exception("Не удалось валидировать клиент")
except Exception as e:
logger.error(f"Не удалось валидировать клиент: {e}")
return False
finally:
@@ -94,26 +108,28 @@ class TDATA:
await client.disconnect()
async def convert(self) -> TelegramClient:
logger.debug("Конвертация TDATA в сессию Telethon")
logger.debug("Начало конвертации TDATA в Telethon сессию")
if not await self.validate():
logger.error("TDATA невалидна, конвертация невозможна")
raise TDesktopNotLoaded("TDATA невалидна или не авторизована")
tempPath = self.__gen_session_path()
try:
logger.debug(f"Создание сессии Telethon по пути '{tempPath}'")
logger.debug(f"Создание Telethon сессии по пути '{tempPath}'")
client = await self.desktop.ToTelethon(
session=tempPath, flag=UseCurrentSession, api=self.api
)
valid_status = await self.valid(client, disconnect=False)
logger.debug("Валидация созданной сессии")
valid_status = await self.is_valid(client, disconnect=False)
if not valid_status:
logger.error("Созданная сессия невалидна")
raise TDesktopUnauthorized("TDATA невалидна или не авторизована")
logger.debug(f"Успешно конвертировано в сессию: {tempPath}")
logger.debug(f"Конвертация успешна: {tempPath}")
return self.telethon
except Exception as e:
logger.exception(f"Не удалось конвертировать TDATA: {e}")
logger.error(f"Не удалось конвертировать TDATA: {e}")
raise
+74 -39
View File
@@ -5,7 +5,7 @@ from shutil import move
from pathlib import Path
from countryflag import getflag
from checker import Result, Checker, SessionInvalid
from modules.checker import Result, Checker, SessionInvalid
logger = logging.getLogger(__name__)
@@ -17,6 +17,7 @@ class Worker:
output_path: str = "data",
temp_path: str = "temp",
):
logger.debug(f"Инициализация Worker с путями: input={input_path}, output={output_path}, temp={temp_path}")
self.input_path = Path(input_path).absolute()
self.output_path = Path(output_path).absolute()
self.temp_path = Path(temp_path).absolute()
@@ -25,52 +26,65 @@ class Worker:
self.invalid_path = self.output_path.joinpath("invalid")
self.all_path = self.valid_path.joinpath("all.txt")
logger.debug(f"Пути настроены: valid={self.valid_path}, invalid={self.invalid_path}")
async def __aenter__(self):
logger.debug("Вход в контекстный менеджер Worker")
logger.debug("Создание необходимых директорий")
if not self.input_path.exists():
self.input_path.mkdir()
logger.debug(f"Создана директория: {self.input_path}")
if not self.output_path.exists():
self.output_path.mkdir()
logger.debug(f"Создана директория: {self.output_path}")
if not self.temp_path.exists():
self.temp_path.mkdir()
logger.debug(f"Создана директория: {self.temp_path}")
else:
logger.debug("Очистка существующей временной директории")
self.__cleanup()
if not self.valid_path.exists():
self.valid_path.mkdir()
logger.debug(f"Создана директория: {self.valid_path}")
if not self.invalid_path.exists():
self.invalid_path.mkdir()
logger.debug(f"Создана директория: {self.invalid_path}")
logger.debug("Все директории готовы")
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
logger.debug("Выход из контекстного менеджера Worker")
self.__cleanup()
if self.client:
logger.debug("Отключение клиента Telethon")
try:
await self.client.disconnect()
except:
pass
def __cleanup(self):
logger.debug("Начало очистки временных файлов")
if self.temp_path.exists():
deleted_count = 0
for file in os.listdir(path=self.temp_path):
file_path = self.temp_path.joinpath(str(file))
try:
if file_path.isfile() and ".gitinclude" not in file_path:
if file_path.is_file() and ".gitinclude" not in str(file_path):
file_path.unlink(missing_ok=True)
elif file_path.isdir():
deleted_count += 1
elif file_path.is_dir():
file_path.rmdir()
deleted_count += 1
deleted_count += 1
except Exception as e:
logger.warning(f"Не удалось удалить {file_path}: {e}")
logger.debug(f"Не удалось удалить {file_path}: {e}")
if deleted_count > 0:
logger.debug(f"Удалено {deleted_count} временных файлов")
logger.debug(f"Удалено временных файлов: {deleted_count}")
else:
logger.debug("Нет временных файлов для удаления")
def __list_tdata(self):
logger.debug(f"Поиск TDATA папок в {self.input_path}")
tdatas = []
if self.input_path.exists():
@@ -78,10 +92,13 @@ class Worker:
joined = self.input_path.joinpath(content)
if joined.is_dir():
tdatas.append(joined.absolute())
logger.debug(f"Найдена TDATA папка: {joined}")
logger.debug(f"Всего найдено TDATA папок: {len(tdatas)}")
return tdatas
def __template(self, result: Result):
logger.debug(f"Создание шаблона для пользователя {result.me.id}")
return (
f"👤 [{getflag(countries=result.country)} {result.country}] {result.me.phone}{result.me.id}\n"
f"⭐️ {result.stars}\n"
@@ -91,62 +108,80 @@ class Worker:
)
def __append(self, content: str, path: Path):
with open(file=path, mode="+a", encoding="utf-8") as file:
file.write(content)
logger.debug(f"Добавление данных в файл: {path}")
with open(file=path, mode="a", encoding="utf-8") as file:
file.write(content + "\n\n")
def __write(self, content: str, path: Path):
with open(file=path, mode="+w", encoding="utf-8") as file:
logger.debug(f"Запись данных в файл: {path}")
with open(file=path, mode="w", encoding="utf-8") as file:
file.write(content)
def __save_valid(self, user_id: int, result: Result, tdata: Path):
id_path = self.output_path.joinpath(str(user_id))
logger.debug(f"Сохранение валидной TDATA для пользователя {user_id}")
id_path = self.valid_path.joinpath(str(user_id))
if not id_path.absolute().exists():
id_path.mkdir()
logger.debug(f"Создана директория для пользователя: {id_path}")
content = self.__template(result=result)
id_txt_path = id_path.joinpath(f"{user_id}.txt")
# Append to all.txt
logger.debug("Добавление в общий файл all.txt")
self.__append(content=content, path=self.all_path)
# Write to id.txt
logger.debug("Запись в индивидуальный файл")
self.__write(content=content, path=id_txt_path)
tdata_old_path = self.input_path.joinpath(tdata).absolute()
tdata_old_path = tdata
tdata_relative = tdata.relative_to(self.input_path)
tdata_new_path = id_path.joinpath(tdata_relative.name)
tdata_relative_id_path = id_path.joinpath(tdata)
tdata_new_path = self.valid_path.joinpath(tdata_relative_id_path).absolute()
# Move tdata
move(src=tdata_old_path, dst=tdata_new_path)
logger.debug(f"Перемещение TDATA: {tdata_old_path} -> {tdata_new_path}")
move(src=str(tdata_old_path), dst=str(tdata_new_path))
logger.info(f"Валидная TDATA сохранена для пользователя {user_id}")
def __save_invalid(self, tdata: Path):
tdata_old_path = self.input_path.joinpath(tdata).absolute()
tdata_new_path = self.invalid_path.joinpath(tdata).absolute()
logger.debug(f"Сохранение невалидной TDATA: {tdata}")
tdata_old_path = tdata
tdata_relative = tdata.relative_to(self.input_path)
tdata_new_path = self.invalid_path.joinpath(tdata_relative.name)
# Move tdata
move(src=tdata_old_path, dst=tdata_new_path)
logger.debug(f"Перемещение TDATA: {tdata_old_path} -> {tdata_new_path}")
move(src=str(tdata_old_path), dst=str(tdata_new_path))
logger.info(f"Невалидная TDATA перемещена: {tdata_relative.name}")
async def check_one(self, tdata: str):
tdata_absolute = Path(tdata).absolute()
tdata_relative = Path(tdata).relative_to(self.input_path)
async def check_one(self, tdata: Path):
tdata_absolute = tdata.absolute()
logger.info(f"Проверка TDATA: {tdata.name}")
logger.info(f"Начало проверки TDATA: {tdata_absolute}")
try:
async with Checker(path=tdata_absolute) as checker:
async with Checker(path=tdata_absolute, temp_path=self.temp_path) as checker:
result = await checker.check_all()
return
self.__save_valid(user_id=result.me.id, tdata=tdata_relative)
logger.info(f"Проверка завершена: {result.me.first_name} (+{result.me.phone})")
self.__save_valid(user_id=result.me.id, result=result, tdata=tdata_absolute)
except SessionInvalid:
self.__save_invalid(tdata=tdata_relative)
logger.warning(f"TDATA невалидна: {tdata.name}")
self.__save_invalid(tdata=tdata_absolute)
except:
pass
except Exception as e:
logger.error(f"Ошибка при проверке TDATA {tdata.name}: {e}")
self.__save_invalid(tdata=tdata_absolute)
async def check_all(self):
logger.info("Начало массовой проверки TDATA")
tdatas = self.__list_tdata()
for tdata in tdatas:
if not tdatas:
logger.warning("TDATA папки не найдены")
return
logger.info(f"Найдено TDATA для проверки: {len(tdatas)}")
for index, tdata in enumerate(tdatas, 1):
logger.info(f"[{index}/{len(tdatas)}] Проверка: {tdata.name}")
await self.check_one(tdata=tdata)
logger.info("Массовая проверка завершена")