Skip to content

Commit 50d434a

Browse files
committed
feat: logs system in telegram
1 parent a5c0d85 commit 50d434a

File tree

5 files changed

+161
-100
lines changed

5 files changed

+161
-100
lines changed

userbot/__main__.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from userbot import (
1212
db_setup, manage_clients
1313
)
14-
from userbot.src.config import GC_INTERVAL_SECONDS, LOG_QUEUE_INTERVAL_SECONDS, TIMEZONE
14+
from userbot.src.config import GC_INTERVAL_SECONDS, LOG_QUEUE_INTERVAL_SECONDS, TIMEZONE, LOG_ROTATION_ENABLED, LOG_RETENTION_DAYS
1515
from userbot.src.db.session import get_db
1616
import userbot.src.db_manager as db_manager
1717
from userbot.src.log_handler import log_queue
@@ -41,6 +41,19 @@ async def process_log_queue():
4141
except Exception as e:
4242
logger.error(f"Failed to process log queue batch: {e}", exc_info=True)
4343

44+
async def run_log_rotation():
45+
"""Periodically deletes old logs from the database if rotation is enabled."""
46+
if not LOG_ROTATION_ENABLED:
47+
return
48+
49+
logger.info(f"Running scheduled log rotation. Deleting logs older than {LOG_RETENTION_DAYS} days.")
50+
try:
51+
async with get_db() as db_session:
52+
deleted_count = await db_manager.delete_old_logs(db_session, LOG_RETENTION_DAYS)
53+
logger.info(f"Log rotation complete. Deleted {deleted_count} old log entries.")
54+
except Exception as e:
55+
logger.error(f"An error occurred during scheduled log rotation: {e}", exc_info=True)
56+
4457

4558
async def main():
4659
"""The main entry point for the userbot."""
@@ -52,10 +65,13 @@ async def main():
5265
scheduler = AsyncIOScheduler(timezone=TIMEZONE)
5366
scheduler.add_job(gc.collect, 'interval', seconds=GC_INTERVAL_SECONDS, id='gc_job')
5467
scheduler.add_job(process_log_queue, 'interval', seconds=LOG_QUEUE_INTERVAL_SECONDS, id='log_queue_job')
68+
scheduler.add_job(run_log_rotation, 'interval', hours=24, id='log_rotation_job')
5569
scheduler.start()
5670

5771
console.print(f"-> [system] - GC scheduled every {GC_INTERVAL_SECONDS} seconds.", style="blue")
5872
console.print(f"-> [system] - Log queue processing scheduled every {LOG_QUEUE_INTERVAL_SECONDS} seconds.", style="blue")
73+
if LOG_ROTATION_ENABLED:
74+
console.print(f"-> [system] - Log rotation scheduled every 24 hours (retention: {LOG_RETENTION_DAYS} days).", style="blue")
5975

6076
await manage_clients()
6177

userbot/locales/core/en.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
"lang_download_fail": "❌ Failed to download language pack: {error}",
3636
"restarting_now": "🔄 **Restarting...**",
3737
"ping_response": "🏓 <b>Pong!</b>\n\n<b>User → Server:</b> <code>{user_server} ms</code>\n<b>Server → Telegram:</b> <code>{server_api} ms</code>\n<b>Total Round-trip:</b> <code>{total} ms</code>",
38+
"logs_processing": "⏳ Processing logs request...",
39+
"logs_err_args": "❌ Error in command arguments.",
40+
"help_logs_usage": "<b>Usage:</b> <code>.logs [head|tail] [count] [level=LEVEL] [source=SOURCE]</code>\n<b>Example:</b> <code>.logs tail 200 level=error source=my_module</code>\n<b>Purge:</b> <code>.logs purge</code>",
41+
"logs_confirm_purge": "️⚠️ Are you sure you want to **PERMANENTLY** delete all logs from the database?\n\nSend `yes` to confirm.",
42+
"logs_purge_success": "✅ All {count} log entries have been deleted.",
43+
"logs_purge_cancelled": "Log purge cancelled.",
44+
"logs_not_found": "❌ No logs matching your query were found.",
45+
"logs_caption": "📄 <b>Logs Report</b>\n\n<b>Mode:</b> <code>{mode}</code>\n<b>Line Limit:</b> <code>{lines}</code>\n<b>Level:</b> <code>{level}</code>\n<b>Source:</b> <code>{source}</code>\n\n<b>Entries Found:</b> <code>{found}</code>",
3846
"help_header_management": "<b>➖ Management</b>",
3947
"help_header_modules": "<b>➖ Modules</b>",
4048
"help_header_utils": "<b>➖ Utilities</b>",
@@ -50,7 +58,8 @@
5058
"help_ping": "Check latency",
5159
"help_restart": "Restart the userbot",
5260
"help_updatemodules": "Update all modules",
53-
"help_logs": "Show bot logs",
61+
"help_logs": "Show logs with filters",
62+
"help_logs_purge": "Purge all logs",
5463
"help_about": "About the userbot",
5564
"about_text": "<b>DeBot Userbot on SQLAlchemy</b>"
5665
}

userbot/locales/core/ru.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@
3535
"lang_download_fail": "❌ Не удалось загрузить языковой пакет: {error}",
3636
"restarting_now": "🔄 **Перезагрузка...**",
3737
"ping_response": "🏓 <b>Pong!</b>\n\n<b>Пользователь → Сервер:</b> <code>{user_server} ms</code>\n<b>Сервер → Telegram:</b> <code>{server_api} ms</code>\n<b>Общая задержка:</b> <code>{total} ms</code>",
38+
"logs_processing": "⏳ Обрабатываю запрос логов...",
39+
"logs_err_args": "❌ Ошибка в аргументах команды.",
40+
"help_logs_usage": "<b>Использование:</b> <code>.logs [head|tail] [кол-во] [level=УРОВЕНЬ] [source=ИСТОЧНИК]</code>\n<b>Пример:</b> <code>.logs tail 200 level=error source=my_module</code>\n<b>Очистка:</b> <code>.logs purge</code>",
41+
"logs_confirm_purge": "️⚠️ Вы уверены, что хотите **НАВСЕГДА** удалить все логи из базы данных?\n\nОтправьте `да` для подтверждения.",
42+
"logs_purge_success": "✅ Все {count} записей логов были удалены.",
43+
"logs_purge_cancelled": "Очистка логов отменена.",
44+
"logs_not_found": "❌ Логи, соответствующие вашему запросу, не найдены.",
45+
"logs_caption": "📄 <b>Отчет по логам</b>\n\n<b>Режим:</b> <code>{mode}</code>\n<b>Лимит строк:</b> <code>{lines}</code>\n<b>Уровень:</b> <code>{level}</code>\n<b>Источник:</b> <code>{source}</code>\n\n<b>Найдено записей:</b> <code>{found}</code>",
3846
"help_header_management": "<b>➖ Управление</b>",
3947
"help_header_modules": "<b>➖ Модули</b>",
4048
"help_header_utils": "<b>➖ Утилиты</b>",
@@ -50,7 +58,8 @@
5058
"help_ping": "Проверить задержку",
5159
"help_restart": "Перезагрузить юзербот",
5260
"help_updatemodules": "Обновить все модули",
53-
"help_logs": "Показать логи бота",
61+
"help_logs": "Показать логи с фильтрами",
62+
"help_logs_purge": "Очистить все логи",
5463
"help_about": "О юзерботе",
5564
"about_text": "<b>DeBot Userbot на SQLAlchemy</b>"
5665
}

userbot/src/core_handlers.py

Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
import asyncio
2+
import io
23
import logging
34
import os
5+
import shlex
46
import sys
57
import time
68
from datetime import datetime
7-
from typing import Dict, Any, List, Set, Optional
9+
from typing import Dict, Any, List, Optional
810

911
from telethon import events
1012
from telethon.errors import SessionPasswordNeededError
1113
from telethon.sessions import SQLiteSession
1214
from telethon.tl.functions.updates import GetStateRequest
15+
from telethon.tl.types import DocumentAttributeFilename
1316

14-
from userbot import TelegramClient, FAKE, GLOBAL_HELP_INFO, _generate_random_device, ACTIVE_CLIENTS
17+
from userbot import TelegramClient, FAKE, GLOBAL_HELP_INFO, _generate_random_device
1518
from userbot.src.db.session import get_db
1619
import userbot.src.db_manager as db_manager
1720
from userbot.src.locales import translator
@@ -52,7 +55,90 @@ async def update_modules_handler(event: events.NewMessage.Event):
5255
await event.edit("Команда `.updatemodules` в разработке.")
5356

5457
async def logs_handler(event: events.NewMessage.Event):
55-
await event.edit("Команда `.logs` в разработке.")
58+
"""Handles the .logs command for fetching and managing logs."""
59+
await event.edit(await event.client.get_string("logs_processing"))
60+
61+
try:
62+
args: List[str] = shlex.split(event.raw_text)[1:]
63+
except ValueError:
64+
await event.edit(await event.client.get_string("logs_err_args"))
65+
return
66+
67+
if not args:
68+
await event.edit(await event.client.get_string("help_logs_usage"))
69+
return
70+
71+
command: str = args[0].lower()
72+
73+
if command == "purge":
74+
try:
75+
async with event.client.conversation(event.chat_id, timeout=60) as conv:
76+
await conv.send_message(await event.client.get_string("logs_confirm_purge"))
77+
response = await conv.get_response()
78+
if response.text.lower() in ("yes", "да"):
79+
async with get_db() as db:
80+
deleted_count = await db_manager.purge_logs(db)
81+
await conv.send_message(await event.client.get_string("logs_purge_success", count=deleted_count))
82+
else:
83+
await conv.send_message(await event.client.get_string("logs_purge_cancelled"))
84+
except asyncio.TimeoutError:
85+
await event.respond(await event.client.get_string("delete_timeout"))
86+
return
87+
88+
# --- Log Fetching Logic ---
89+
mode: str = "tail"
90+
limit: int = 100
91+
level: Optional[str] = None
92+
source: Optional[str] = None
93+
94+
# Parse arguments
95+
if args[0].lower() in ["head", "tail"]:
96+
mode = args.pop(0).lower()
97+
98+
if args and args[0].isdigit():
99+
limit = int(args.pop(0))
100+
101+
for arg in args:
102+
if "=" in arg:
103+
key, value = arg.split("=", 1)
104+
if key.lower() == "level":
105+
level = value.upper()
106+
elif key.lower() == "source":
107+
source = value
108+
109+
async with get_db() as db:
110+
logs_list = await db_manager.get_logs_advanced(db, mode, limit, level, source)
111+
112+
if not logs_list:
113+
await event.edit(await event.client.get_string("logs_not_found"))
114+
return
115+
116+
# Prepare file and caption
117+
log_content: str = "\n".join(
118+
f"[{log.timestamp.strftime('%Y-%m-%d %H:%M:%S')}] [{log.level}] [{log.module_name or 'System'}] {log.message}"
119+
for log in logs_list
120+
)
121+
122+
log_file = io.BytesIO(log_content.encode('utf-8'))
123+
filename = f"debot_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
124+
125+
caption: str = await event.client.get_string(
126+
"logs_caption",
127+
mode=mode,
128+
lines=limit,
129+
level=level or "ANY",
130+
source=source or "ANY",
131+
found=len(logs_list)
132+
)
133+
134+
await event.delete()
135+
await event.client.send_file(
136+
event.chat_id,
137+
file=log_file,
138+
caption=caption,
139+
attributes=[DocumentAttributeFilename(filename)],
140+
parse_mode="HTML"
141+
)
56142

57143
# --- Account Management Handlers ---
58144
async def list_accounts_handler(event: events.NewMessage.Event):
@@ -233,8 +319,9 @@ async def help_commands_handler(event: events.NewMessage.Event):
233319
help_utils = "\n".join([
234320
f"<code>.ping</code> - {await event.client.get_string('help_ping')}",
235321
f"<code>.restart</code> - {await event.client.get_string('help_restart')}",
236-
f"<code>.updatemodules</code> - {await event.client.get_string('help_updatemodules')}",
237322
f"<code>.logs</code> - {await event.client.get_string('help_logs')}",
323+
f"<code>.logs purge</code> - {await event.client.get_string('help_logs_purge')}",
324+
f"<code>.updatemodules</code> - {await event.client.get_string('help_updatemodules')}",
238325
f"<code>.about</code> - {await event.client.get_string('help_about')}"
239326
])
240327

@@ -259,12 +346,10 @@ async def ping_handler(event: events.NewMessage.Event):
259346
start_time: float = time.time()
260347
await event.edit("Pinging...")
261348

262-
# Measure API latency
263349
api_start_time: float = time.time()
264350
await event.client(GetStateRequest())
265351
api_end_time: float = time.time()
266352

267-
# Measure total round-trip latency
268353
end_time: float = time.time()
269354

270355
total_latency: float = (end_time - start_time) * 1000

0 commit comments

Comments
 (0)