From 730de38cee02a46be7514cc0dffe409ebd6d78e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=20=D0=97=D0=B2=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B2?= Date: Fri, 2 Aug 2024 11:09:40 +0500 Subject: [PATCH] Add Log rotation Add logging for Telebot and Flask Add routing for Enable debugging for Flask and Telebot separately --- telezab.py | 360 +++++++++++++++++++++++++++++------------------------ 1 file changed, 195 insertions(+), 165 deletions(-) diff --git a/telezab.py b/telezab.py index abd89b6..083fa80 100644 --- a/telezab.py +++ b/telezab.py @@ -1,8 +1,10 @@ import os from flask import Flask, request, jsonify -import telebot +import schedule from dotenv import load_dotenv import hashlib +import telebot +from telebot import logger import logging from logging.config import dictConfig import zipfile @@ -23,21 +25,6 @@ import re # Load environment variables load_dotenv() -# Read environment variables for logging configuration -ENABLE_CONSOLE_LOGGING = os.getenv('ENABLE_CONSOLE_LOGGING', 'true').lower() in ['true', '1', 'yes'] -ENABLE_FILE_LOGGING = os.getenv('ENABLE_FILE_LOGGING', 'true').lower() in ['true', '1', 'yes'] - -# Define log paths -LOG_PATH_ERRORS = os.getenv('LOG_PATH_ERRORS', 'logs/errors.log') -LOG_PATH_EVENTS = os.getenv('LOG_PATH_EVENTS', 'logs/events.log') -LOG_PATH_FLASK = os.getenv('LOG_PATH_FLASK', 'logs/flask.log') -LOG_ARCHIVE_PATH = os.getenv('LOG_ARCHIVE_PATH', 'logs/archive') - -# Create log directories if they do not exist -os.makedirs(os.path.dirname(LOG_PATH_ERRORS), exist_ok=True) -os.makedirs(os.path.dirname(LOG_PATH_EVENTS), exist_ok=True) -os.makedirs(LOG_ARCHIVE_PATH, exist_ok=True) - class UTF8StreamHandler(logging.StreamHandler): def __init__(self, stream=None): super().__init__(stream) @@ -48,120 +35,90 @@ class UTF8StreamHandler(logging.StreamHandler): if hasattr(stream, 'reconfigure'): stream.reconfigure(encoding='utf-8') -# Конфигурация логирования -handlers = {} -if ENABLE_CONSOLE_LOGGING: - handlers['console'] = { - 'class': 'telezab.UTF8StreamHandler', - 'stream': 'ext://sys.stdout', # Вывод в консоль - 'formatter': 'console', - } -if ENABLE_FILE_LOGGING: - handlers['file_errors'] = { - 'class': 'logging.handlers.TimedRotatingFileHandler', - 'filename': LOG_PATH_ERRORS, - 'when': 'midnight', - 'interval': 1, - 'backupCount': 7, - 'formatter': 'error', - 'encoding': 'utf-8', # Убедитесь, что используется кодировка UTF-8 - } - handlers['file_events'] = { - 'class': 'logging.handlers.TimedRotatingFileHandler', - 'filename': LOG_PATH_EVENTS, - 'when': 'midnight', - 'interval': 1, - 'backupCount': 7, - 'formatter': 'event', - 'encoding': 'utf-8', # Убедитесь, что используется кодировка UTF-8 - } -# Configure Flask logger -flask_handlers = { - 'flask': { - 'class': 'logging.handlers.TimedRotatingFileHandler', - 'filename': LOG_PATH_FLASK, - 'when': 'midnight', - 'interval': 1, - 'backupCount': 7, - 'formatter': 'default', - 'encoding': 'utf-8', - } -} -# Include flask_handlers in dictConfig +# Определение пути к основному лог-файлу +LOG_FILE = 'logs/app.log' + + + +# Определение функции архивирования логов +def archive_old_logs(): + # Получаем дату предыдущего дня + yesterday_date = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') + + # Проверяем существует ли основной лог-файл + if os.path.exists(LOG_FILE): + # Путь к архиву в той же папке + archive_name = f"app_{yesterday_date}.zip" + archive_path = os.path.join(os.path.dirname(LOG_FILE), archive_name) + + # Создание архива и добавление лог-файла + with zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + zipf.write(LOG_FILE, arcname=os.path.basename(LOG_FILE)) + + # Удаление старого лог-файла после архивирования + os.remove(LOG_FILE) + + + +class FilterByMessage(logging.Filter): + def filter(self, record): + # Фильтруем сообщения, содержащие 'Received 1 new updates' + return 'Received ' not in record.getMessage() + + +# Initialize Flask application +app = Flask(__name__) + +# Настройка логирования dictConfig({ 'version': 1, 'formatters': { 'default': { 'format': '[%(asctime)s] %(levelname)s %(module)s: %(message)s', }, + }, + 'handlers': { 'console': { - 'format': '[%(asctime)s] %(levelname)s %(module)s: %(message)s', + 'class': 'telezab.UTF8StreamHandler', # Замените на путь к вашему классу UTF8StreamHandler + 'stream': 'ext://sys.stdout', # Вывод в консоль + 'formatter': 'default', + 'filters': ['filter_by_message'] }, - 'error': { - 'format': '[%(asctime)s] ERROR %(module)s: %(message)s', - }, - 'event': { - 'format': '[%(asctime)s] EVENT %(module)s: %(message)s', + 'file': { + 'class': 'logging.FileHandler', + 'filename': 'app.log', # Запись в файл + 'formatter': 'default', + 'encoding': 'utf-8', # Кодировка файла + }, + }, + 'filters': { + 'filter_by_message': { + '()': FilterByMessage, }, }, - 'handlers': {**handlers, **flask_handlers}, 'loggers': { - 'default': { - 'level': 'INFO', - 'handlers': ['console', 'file_events'], - }, - 'error': { - 'level': 'ERROR', - 'handlers': ['console', 'file_errors'], - 'propagate': False, - }, 'flask': { - 'level': 'INFO', - 'handlers': ['flask'], + 'level': 'DEBUG', + 'handlers': ['console', 'file'], 'propagate': False, - } + }, + 'telebot': { + 'level': 'DEBUG', + 'handlers': ['console', 'file'], + 'propagate': False, + }, }, 'root': { - 'level': 'INFO', - 'handlers': ['console', 'file_events'], + 'level': 'DEBUG', + 'handlers': ['console', 'file'], } }) - - -# Set Flask app logger to use the 'flask' logger - - -# Определение функции архивирования логов -def archive_old_logs(): - yesterday_date = (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d') - for log_file in [LOG_PATH_ERRORS, LOG_PATH_EVENTS]: - log_dir, log_filename = os.path.split(log_file) - for filename in os.listdir(log_dir): - if filename.startswith(log_filename) and filename != log_filename: - log_file_path = os.path.join(log_dir, filename) - archive_name = f"{log_filename}_{yesterday_date}.zip" - archive_path = os.path.join(LOG_ARCHIVE_PATH, archive_name) - with zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_DEFLATED) as zipf: - zipf.write(log_file_path, arcname=filename) - os.remove(log_file_path) - -# Create loggers -logger = logging.getLogger('default') -error_logger = logging.getLogger('error') - -# Call archive_old_logs function after logging setup -archive_old_logs() - -# Initialize Flask application -app = Flask(__name__) - -app.logger.handlers = [] -app.logger.propagate = True -flask_logger = logging.getLogger('flask') -app.logger.addHandler(flask_logger.handlers[0]) - +# Настройка уровня логирования для Flask +app.logger.setLevel(logging.DEBUG) +# Настройка pyTelegramBotAPI logger +telebot.logger = logging.getLogger('telebot') # Get the token from environment variables TOKEN = os.getenv('TELEGRAM_TOKEN') ZABBIX_URL = os.getenv('ZABBIX_URL') @@ -191,17 +148,22 @@ user_timers = {} -# Initialize SQLite database def init_db(): + global st + st = datetime.now() try: with db_lock: conn = sqlite3.connect('telezab.db') cursor = conn.cursor() + + # Create events table cursor.execute('''CREATE TABLE IF NOT EXISTS events ( id INTEGER PRIMARY KEY AUTOINCREMENT, hash TEXT UNIQUE, data TEXT, delivered BOOLEAN)''') + + # Create subscriptions table with username and active flag cursor.execute('''CREATE TABLE IF NOT EXISTS subscriptions ( chat_id INTEGER, region_id TEXT, @@ -209,29 +171,39 @@ def init_db(): active BOOLEAN DEFAULT TRUE, skip BOOLEAN DEFAULT FALSE, UNIQUE(chat_id, region_id))''') + + # Create whitelist table cursor.execute('''CREATE TABLE IF NOT EXISTS whitelist ( chat_id INTEGER PRIMARY KEY)''') + + # Create regions table with active flag cursor.execute('''CREATE TABLE IF NOT EXISTS regions ( region_id TEXT PRIMARY KEY, region_name TEXT, active BOOLEAN DEFAULT TRUE)''') + + # Create user events table for logging cursor.execute('''CREATE TABLE IF NOT EXISTS user_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, chat_id INTEGER, username TEXT, action TEXT, timestamp TEXT)''') + + # Insert sample regions cursor.execute('''INSERT OR IGNORE INTO regions (region_id, region_name) VALUES ('01', 'Адыгея'), ('02', 'Башкортостан (Уфа)'), ('04', 'Алтай'), ('19', 'Республика Хакасия')''') + conn.commit() - logger.info("Database initialized successfully.") + app.logger.info("Database initialized successfully.") except Exception as e: - error_logger.error(f"Error initializing database: {e}") + app.logger.error(f"Error initializing database: {e}") finally: conn.close() + app.logger.info(f"init_db completed in {datetime.now() - st}") # Hash the incoming data @@ -245,7 +217,7 @@ def is_whitelisted(chat_id): conn = sqlite3.connect('telezab.db') cursor = conn.cursor() query = 'SELECT COUNT(*) FROM whitelist WHERE chat_id = ?' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}") cursor.execute(query, (chat_id,)) count = cursor.fetchone()[0] conn.close() @@ -258,7 +230,7 @@ def add_to_whitelist(chat_id, username): conn = sqlite3.connect('telezab.db') cursor = conn.cursor() query = 'INSERT OR IGNORE INTO whitelist (chat_id, username) VALUES (?, ?)' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}") cursor.execute(query, (chat_id, username)) conn.commit() conn.close() @@ -270,7 +242,7 @@ def remove_from_whitelist(chat_id): conn = sqlite3.connect('telezab.db') cursor = conn.cursor() query = 'DELETE FROM whitelist WHERE chat_id = ?' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}") cursor.execute(query, (chat_id,)) conn.commit() conn.close() @@ -355,12 +327,12 @@ def log_user_event(chat_id, username, action): conn = sqlite3.connect('telezab.db') cursor = conn.cursor() query = 'INSERT INTO user_events (chat_id, username, action, timestamp) VALUES (?, ?, ?, ?)' - logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}, action={action}, timestamp={timestamp}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, username={username}, action={action}, timestamp={timestamp}") cursor.execute(query, (chat_id, username, action, timestamp)) conn.commit() - logger.info(f"User event logged: {chat_id} ({username}) - {action} at {timestamp}.") + telebot.logger.info(f"User event logged: {chat_id} ({username}) - {action} at {timestamp}.") except Exception as e: - error_logger.error(f"Error logging user event: {e}") + telebot.logger.error(f"Error logging user event: {e}") finally: conn.close() @@ -397,7 +369,8 @@ def reset_settings_timer(chat_id): def transition_to_notification_mode(chat_id): set_user_state(chat_id, NOTIFICATION_MODE) bot.send_message(chat_id, "Вы были автоматически переведены в режим получения уведомлений.") - app.logger.info(f"User {chat_id} automatically transitioned to notification mode.") + show_main_menu(chat_id) + telebot.logger.info(f"User {chat_id} automatically transitioned to notification mode.") # Main menu for users @@ -434,7 +407,7 @@ def handle_start(message): set_user_state(chat_id, NOTIFICATION_MODE) show_main_menu(chat_id) - app.logger.info(f"User {chat_id} ({username}) started with command /start.") + telebot.logger.info(f"User {chat_id} ({username}) started with command /start.") # Handle menu button presses @@ -498,7 +471,7 @@ def handle_subscribe(message): chat_id = message.chat.id if not is_whitelisted(chat_id): bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") - app.logger.info(f"Unauthorized access attempt by {chat_id}") + telebot.logger.info(f"Unauthorized access attempt by {chat_id}") return username = message.from_user.username @@ -529,16 +502,16 @@ def process_subscription(message, chat_id, username): bot.send_message(chat_id, f"Регион с ID {region_id} не существует или недопустимый формат. Введите только существующие номера регионов.") return show_settings_menu(chat_id) query = 'INSERT OR IGNORE INTO subscriptions (chat_id, region_id, username, active) VALUES (?, ?, ?, TRUE)' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}, username={username}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}, username={username}") cursor.execute(query, (chat_id, region_id, username)) if cursor.rowcount == 0: query = 'UPDATE subscriptions SET active = TRUE WHERE chat_id = ? AND region_id = ?' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") cursor.execute(query, (chat_id, region_id)) conn.commit() conn.close() bot.send_message(chat_id, f"Подписка на регионы: {', '.join(region_ids)} оформлена.") - app.logger.info(f"User {chat_id} ({username}) subscribed to regions: {', '.join(region_ids)}.") + telebot.logger.info(f"User {chat_id} ({username}) subscribed to regions: {', '.join(region_ids)}.") log_user_event(chat_id, username, f"Subscribed to regions: {', '.join(region_ids)}") show_settings_menu(chat_id) @@ -549,7 +522,7 @@ def handle_unsubscribe(message): chat_id = message.chat.id if not is_whitelisted(chat_id): bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") - app.logger.info(f"Unauthorized access attempt by {chat_id}") + telebot.logger.info(f"Unauthorized access attempt by {chat_id}") return user_regions = get_user_subscribed_regions(chat_id) @@ -562,6 +535,7 @@ def handle_unsubscribe(message): bot.register_next_step_handler_by_chat_id(chat_id, process_unsubscription, chat_id) +# Пример функции, которая использует bot и log def process_unsubscription(message, chat_id): if message.text.lower() == 'отмена': bot.send_message(chat_id, "Действие отменено.") @@ -579,13 +553,13 @@ def process_unsubscription(message, chat_id): bot.send_message(chat_id, f"Регион с ID {region_id} не существует или недопустимый формат. Введите только номера регионов, на которые вы подписаны.") return show_settings_menu(chat_id) query = 'UPDATE subscriptions SET active = FALSE WHERE chat_id = ? AND region_id = ?' - app.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with chat_id={chat_id}, region_id={region_id}") cursor.execute(query, (chat_id, region_id)) conn.commit() conn.close() bot.send_message(chat_id, f"Отписка от регионов: {', '.join(region_ids)} оформлена.") - app.logger.info(f"User {chat_id} unsubscribed from regions: {', '.join(region_ids)}.") - username = message.from_user.username if message.from_user.username else "N/A" + telebot.logger.info(f"User {chat_id} unsubscribed from regions: {', '.join(region_ids)}.") + username = "@" + message.from_user.username if message.from_user.username else "N/A" log_user_event(chat_id, username, f"Unsubscribed from regions: {', '.join(region_ids)}") show_settings_menu(chat_id) @@ -663,7 +637,7 @@ def process_register(message, chat_id, username): reply_markup=markup ) bot.send_message(chat_id, "Запрос отправлен администратору для одобрения.") - app.logger.info(f"User {chat_id} ({username}) requested registration.") + telebot.logger.info(f"User {chat_id} ({username}) requested registration.") else: bot.send_message(chat_id, "Некорректный выбор. Регистрация отменена.") show_main_menu(chat_id) @@ -688,17 +662,17 @@ def process_add_region(message): conn = sqlite3.connect('telezab.db') cursor = conn.cursor() query = 'SELECT region_name, active FROM regions WHERE region_id = ?' - app.logger.debug(f"Executing query: {query} with region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) result = cursor.fetchone() if result: existing_region_name, active = result if existing_region_name == region_name: query = 'UPDATE regions SET active = TRUE WHERE region_id = ?' - app.logger.debug(f"Executing query: {query} with region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) bot.send_message(chat_id, f"Регион {region_id} - {region_name} активирован.") - app.logger.info(f"Admin {chat_id} reactivated region {region_id} - {region_name}.") + telebot.logger.info(f"Admin {chat_id} reactivated region {region_id} - {region_name}.") else: markup = telebot.types.InlineKeyboardMarkup() markup.add(telebot.types.InlineKeyboardButton(text="Заменить", callback_data=f"replace_{region_id}_{region_name}")) @@ -707,10 +681,10 @@ def process_add_region(message): bot.send_message(chat_id, f"Регион {region_id} уже существует с названием {existing_region_name}. Хотите заменить его или активировать старый регион?", reply_markup=markup) else: query = 'INSERT OR IGNORE INTO regions (region_id, region_name) VALUES (?, ?)' - app.logger.debug(f"Executing query: {query} with region_id={region_id}, region_name={region_name}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}, region_name={region_name}") cursor.execute(query, (region_id, region_name)) bot.send_message(chat_id, f"Регион {region_id} - {region_name} добавлен.") - app.logger.info(f"Admin {chat_id} added region {region_id} - {region_name}.") + telebot.logger.info(f"Admin {chat_id} added region {region_id} - {region_name}.") conn.commit() conn.close() except (IndexError, ValueError): @@ -736,19 +710,19 @@ def handle_region_action(call): cursor = conn.cursor() if action == "replace": query = 'UPDATE regions SET region_name = ?, active = TRUE WHERE region_id = ?' - app.logger.debug(f"Executing query: {query} with region_name={region_name}, region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_name={region_name}, region_id={region_id}") cursor.execute(query, (region_name, region_id)) bot.send_message(chat_id, f"Регион {region_id} обновлен до {region_name} и активирован.") - app.logger.info(f"Admin {chat_id} replaced and reactivated region {region_id} with {region_name}.") + telebot.logger.info(f"Admin {chat_id} replaced and reactivated region {region_id} with {region_name}.") elif action == "reactivate": query = 'UPDATE regions SET active = TRUE WHERE region_id = ?' - app.logger.debug(f"Executing query: {query} with region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) bot.send_message(chat_id, f"Регион {region_id} активирован.") - app.logger.info(f"Admin {chat_id} reactivated region {region_id}.") + telebot.logger.info(f"Admin {chat_id} reactivated region {region_id}.") elif action == "cancel_region": bot.send_message(chat_id, "Действие отменено.") - app.logger.info(f"Admin {chat_id} canceled region action.") + telebot.logger.info(f"Admin {chat_id} canceled region action.") conn.commit() conn.close() bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None) @@ -771,15 +745,15 @@ def process_remove_region(message): return show_settings_menu(chat_id) query = 'UPDATE regions SET active = FALSE WHERE region_id = ?' - app.logger.debug(f"Executing query: {query} with region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) query = 'UPDATE subscriptions SET active = FALSE WHERE region_id = ? AND active = TRUE' - app.logger.debug(f"Executing query: {query} with region_id={region_id}") + telebot.logger.debug(f"Executing query: {query} with region_id={region_id}") cursor.execute(query, (region_id,)) conn.commit() conn.close() bot.send_message(chat_id, f"Регион {region_id} теперь неактивен и все активные подписки обновлены.") - app.logger.info(f"Admin {chat_id} set region {region_id} to inactive and updated subscriptions.") + telebot.logger.info(f"Admin {chat_id} set region {region_id} to inactive and updated subscriptions.") except IndexError: bot.send_message(chat_id, "Неверный формат. Используйте: ") show_settings_menu(chat_id) @@ -789,7 +763,7 @@ def handle_my_subscriptions(message): chat_id = message.chat.id if not is_whitelisted(chat_id): bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") - app.logger.info(f"Unauthorized access attempt by {chat_id}") + telebot.logger.info(f"Unauthorized access attempt by {chat_id}") return user_regions = get_user_subscribed_regions(chat_id) @@ -807,7 +781,7 @@ def handle_active_regions(message): chat_id = message.chat.id if not is_whitelisted(chat_id): bot.send_message(chat_id, "Вы не авторизованы для использования этого бота.") - app.logger.info(f"Unauthorized access attempt by {chat_id}") + telebot.logger.info(f"Unauthorized access attempt by {chat_id}") return regions = get_sorted_regions() # Используем функцию для получения отсортированных регионов @@ -855,7 +829,7 @@ async def consume_from_queue(): await send_notification_message(chat_id, message_text) channel.basic_ack(method_frame.delivery_tag) except Exception as e: - app.logger.error(f"Error sending message from queue: {e}") + telebot.logger.error(f"Error sending message from queue: {e}") # Optionally, you can nack the message to requeue it # channel.basic_nack(method_frame.delivery_tag) @@ -869,13 +843,13 @@ async def send_message(chat_id, message, is_notification=False): await run_in_executor(bot.send_message, chat_id, message) except telebot.apihelper.ApiTelegramException as e: if "429" in str(e): - app.logger.warning(f"Rate limit exceeded for chat_id {chat_id}. Retrying...") + telebot.logger.warning(f"Rate limit exceeded for chat_id {chat_id}. Retrying...") await asyncio.sleep(1) await send_message(chat_id, message, is_notification) else: - app.logger.error(f"Failed to send message to {chat_id}: {e}") + telebot.logger.error(f"Failed to send message to {chat_id}: {e}") except Exception as e: - app.logger.error(f"Error sending message to {chat_id}: {e}") + telebot.logger.error(f"Error sending message to {chat_id}: {e}") await check_telegram_api() finally: if is_notification: @@ -897,11 +871,11 @@ async def check_telegram_api(): async with aiohttp.ClientSession() as session: async with session.get('https://api.telegram.org') as response: if response.status == 200: - app.logger.info("Telegram API is reachable.") + telebot.logger.info("Telegram API is reachable.") else: - app.logger.error("Telegram API is not reachable.") + telebot.logger.error("Telegram API is not reachable.") except Exception as e: - app.logger.error(f"Error checking Telegram API: {e}") + telebot.logger.error(f"Error checking Telegram API: {e}") def extract_region_number(host): @@ -1029,6 +1003,48 @@ def add_user(): app.logger.error("Invalid data received for adding user.") return jsonify({"status": "failure", "reason": "Invalid data"}), 400 + +# Обработчик для переключения уровня логирования Flask +@app.route('/debug/flask', methods=['POST']) +def toggle_flask_debug(): + try: + data = request.get_json() + level = data.get('level', 'DEBUG').upper() + if level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: + return jsonify({'status': 'error', 'message': 'Invalid log level'}), 400 + + log_level = getattr(logging, level, logging.DEBUG) + app.logger.setLevel(log_level) + + # Обновление уровня логирования для каждого обработчика + for handler in app.logger.handlers: + handler.setLevel(log_level) + + return jsonify({'status': 'success', 'level': level}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + + +# Обработчик для переключения уровня логирования Telebot +@app.route('/debug/telebot', methods=['POST']) +def toggle_telebot_debug(): + try: + data = request.get_json() + level = data.get('level', 'DEBUG').upper() + if level not in ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']: + return jsonify({'status': 'error', 'message': 'Invalid log level'}), 400 + + log_level = getattr(logging, level, logging.DEBUG) + telebot.logger.setLevel(log_level) + + # Обновление уровня логирования для каждого обработчика + for handler in telebot.logger.handlers: + handler.setLevel(log_level) + + return jsonify({'status': 'success', 'level': level}) + except Exception as e: + return jsonify({'status': 'error', 'message': str(e)}), 500 + # Handle active triggers def handle_active_triggers(message): chat_id = message.chat.id @@ -1090,7 +1106,7 @@ def handle_region_selection(call): bot.send_message(chat_id, f"Найдены следующие группы хостов для региона {region_id}:", reply_markup=markup) except Exception as e: - logging.error(f"Error connecting to Zabbix API: {e}") + telebot.logger.error(f"Error connecting to Zabbix API: {e}") bot.send_message(chat_id, "Не удалось подключиться к Zabbix API. Пожалуйста, попробуйте позже.") bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None) @@ -1113,7 +1129,7 @@ def handle_group_selection(call): bot.send_message(chat_id, trigger, parse_mode="html") time.sleep(1/5) except Exception as e: - logging.error(f"Error processing group selection: {e}") + telebot.logger.error(f"Error processing group selection: {e}") bot.send_message(chat_id, "Произошла ошибка при обработке вашего запроса. Пожалуйста, попробуйте позже.") bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=None) @@ -1219,7 +1235,7 @@ def get_zabbix_triggers(group_id): return trigger_messages except Exception as e: - logging.error(f"Error connecting to Zabbix API: {e}") + telebot.logger.error(f"Error connecting to Zabbix API: {e}") return None @@ -1264,20 +1280,34 @@ def simulate_triggers(message): def run_polling(): - bot.polling(none_stop=True, interval=0) + bot.polling(non_stop=True, interval=0) + +# Запуск Flask-приложения +def run_flask(): + app.run(port=5000, host='0.0.0.0', debug=True, use_reloader=False) -if __name__ == '__main__': +def schedule_jobs(): + schedule.every().day.at("00:00").do(archive_old_logs) + + while True: + schedule.run_pending() + time.sleep(60) # Проверять раз в минуту + +# Основная функция для запуска +def main(): + # Инициализация базы данных init_db() print('Bootstrap wait...') - # Start Flask app in a separate thread - Thread(target=app.run, kwargs={'port': 5000, 'host': '0.0.0.0', 'debug': True, 'use_reloader': False}, daemon=True).start() - # Start bot polling in a separate thread + # Запуск Flask и бота в отдельных потоках + Thread(target=run_flask, daemon=True).start() Thread(target=run_polling, daemon=True).start() + # Запуск планировщика задач в отдельном потоке + Thread(target=schedule_jobs, daemon=True).start() + # Запуск асинхронных задач + asyncio.run(consume_from_queue()) - # Start async message consumer - loop = asyncio.get_event_loop() - loop.create_task(consume_from_queue()) - loop.run_forever() +if __name__ == '__main__': + main()