Fix logger system

Remove someuseless function
This commit is contained in:
Udo Chudo 2024-07-29 15:22:12 +05:00
parent 2d4d3f265e
commit b719850b15
4 changed files with 158 additions and 42 deletions

6
.dockerignore Normal file
View File

@ -0,0 +1,6 @@
/TODO.txt
/venv/
/.idea
/.env
/.gitignore
/.git

View File

@ -1,9 +1,23 @@
FROM python:3.11.9-slim FROM python:3.11.9-slim
LABEL authors="UdoChudo" LABEL authors="UdoChudo"
# Установим необходимые пакеты
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
gcc \
&& rm -rf /var/lib/apt/lists/*
# Установим рабочую директорию
WORKDIR /app WORKDIR /app
# Скопируем файлы проекта
COPY . /app COPY . /app
RUN pip install gunicorn
RUN pip install --no-cache-dir -r requests.txt # Установим зависимости проекта
RUN pip install --no-cache-dir -r requirements.txt
# Откроем порт для нашего приложения
EXPOSE 5000 EXPOSE 5000
ENV FLASK_APP=telezab.py ENV FLASK_APP=telezab.py
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "telezab:app"] # Запуск Gunicorn
CMD ["python3", "telezab.py"]

View File

@ -1,23 +1,25 @@
anyio==4.4.0 aiohttp==3.9.5
aiosignal==1.3.1
attrs==23.2.0
blinker==1.8.2 blinker==1.8.2
certifi==2024.6.2 certifi==2024.7.4
charset-normalizer==3.3.2 charset-normalizer==3.3.2
click==8.1.7 click==8.1.7
colorama==0.4.6 colorama==0.4.6
Flask==3.0.3 Flask==3.0.3
h11==0.14.0 frozenlist==1.4.1
httpcore==1.0.5
httpx==0.27.0
idna==3.7 idna==3.7
itsdangerous==2.2.0 itsdangerous==2.2.0
Jinja2==3.1.4 Jinja2==3.1.4
MarkupSafe==2.1.5 MarkupSafe==2.1.5
multidict==6.0.5
packaging==24.1 packaging==24.1
pyTelegramBotAPI==4.19.2 pika==1.3.2
pyTelegramBotAPI==4.21.0
python-dotenv==1.0.1 python-dotenv==1.0.1
python-telegram-bot==21.3 pyzabbix==1.3.1
requests==2.32.3 requests==2.32.3
sniffio==1.3.1
telebot==0.0.5 telebot==0.0.5
urllib3==2.2.2 urllib3==2.2.2
Werkzeug==3.0.3 Werkzeug==3.0.3
yarl==1.9.4

View File

@ -14,7 +14,7 @@ import pika
import json import json
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from pyzabbix import ZabbixAPI from pyzabbix import ZabbixAPI
import requests # Добавлено для имитации POST запроса import requests
# Load environment variables # Load environment variables
load_dotenv() load_dotenv()
@ -27,19 +27,72 @@ if DEBUG_LOGGING:
else: else:
log_level = 'INFO' log_level = 'INFO'
# Чтение переменных окружения
ENABLE_CONSOLE_LOGGING = os.getenv('ENABLE_CONSOLE_LOGGING', 'true').lower() in ['true', '1', 'yes']
ENABLE_WSGI_LOGGING = os.getenv('ENABLE_WSGI_LOGGING', 'true').lower() in ['true', '1', 'yes']
ENABLE_FILE_LOGGING_CONSOLE = os.getenv('ENABLE_FILE_LOGGING_CONSOLE', 'false').lower() in ['true', '1', 'yes']
ENABLE_FILE_LOGGING_FLASK = os.getenv('ENABLE_FILE_LOGGING_FLASK', 'false').lower() in ['true', '1', 'yes']
# Определение путей для файлов логирования
LOG_PATH_CONSOLE = os.getenv('LOG_PATH_CONSOLE', 'logs/console.log')
LOG_PATH_FLASK = os.getenv('LOG_PATH_FLASK', 'logs/flask.log')
# Создание директории для логов, если она не существует
os.makedirs(os.path.dirname(LOG_PATH_CONSOLE), exist_ok=True)
os.makedirs(os.path.dirname(LOG_PATH_FLASK), exist_ok=True)
# Определение обработчиков на основе переменных окружения
handlers = {}
if ENABLE_CONSOLE_LOGGING:
handlers['console'] = {
'class': 'logging.StreamHandler',
'stream': 'ext://sys.stdout', # Вывод в консоль
'formatter': 'console',
}
if ENABLE_WSGI_LOGGING:
handlers['wsgi'] = {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream', # Логирование ошибок WSGI
'formatter': 'flask',
}
if ENABLE_FILE_LOGGING_CONSOLE:
handlers['file_console'] = {
'class': 'logging.FileHandler',
'filename': LOG_PATH_CONSOLE,
'formatter': 'console',
}
if ENABLE_FILE_LOGGING_FLASK:
handlers['file_flask'] = {
'class': 'logging.FileHandler',
'filename': LOG_PATH_FLASK,
'formatter': 'flask',
}
dictConfig({ dictConfig({
'version': 1, 'version': 1,
'formatters': {'default': { 'formatters': {
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s', 'default': {
}}, 'format': '[%(asctime)s] %(levelname)s %(module)s: %(message)s [Location: %(extra)s]',
'handlers': {'wsgi': { },
'class': 'logging.StreamHandler', 'console': {
'stream': 'ext://flask.logging.wsgi_errors_stream', 'format': '[Location: console] [%(asctime)s] %(levelname)s %(module)s: %(message)s ',
'formatter': 'default' },
}}, 'flask': {
'format': '[Location: flask] [%(asctime)s] %(levelname)s %(module)s: %(message)s ',
},
},
'handlers': handlers,
'loggers': {
'werkzeug': { # Flask логер
'level': 'INFO',
'handlers': ['console'] if ENABLE_CONSOLE_LOGGING else [],
'propagate': False,
'formatter': 'flask',
}
},
'root': { 'root': {
'level': log_level, 'level': 'INFO',
'handlers': ['wsgi'] 'handlers': [handler for handler in handlers.keys()],
} }
}) })
@ -257,6 +310,11 @@ def cancel_settings_timer(chat_id):
user_timers[chat_id].cancel() user_timers[chat_id].cancel()
del user_timers[chat_id] del user_timers[chat_id]
def reset_settings_timer(chat_id):
if chat_id in user_timers:
user_timers[chat_id].cancel()
start_settings_timer(chat_id)
def transition_to_notification_mode(chat_id): def transition_to_notification_mode(chat_id):
set_user_state(chat_id, NOTIFICATION_MODE) set_user_state(chat_id, NOTIFICATION_MODE)
bot.send_message(chat_id, "Вы были автоматически переведены в режим получения уведомлений.") bot.send_message(chat_id, "Вы были автоматически переведены в режим получения уведомлений.")
@ -303,6 +361,7 @@ def handle_menu_selection(message):
text = message.text.strip().lower() text = message.text.strip().lower()
if user_states.get(chat_id, NOTIFICATION_MODE) == SETTINGS_MODE: if user_states.get(chat_id, NOTIFICATION_MODE) == SETTINGS_MODE:
reset_settings_timer(chat_id)
handle_settings_menu_selection(message) handle_settings_menu_selection(message)
else: else:
if text == 'регистрация': if text == 'регистрация':
@ -323,6 +382,8 @@ def handle_settings_menu_selection(message):
chat_id = message.chat.id chat_id = message.chat.id
text = message.text.strip().lower() text = message.text.strip().lower()
reset_settings_timer(chat_id)
if text == 'подписаться': if text == 'подписаться':
handle_subscribe(message) handle_subscribe(message)
elif text == 'отписаться': elif text == 'отписаться':
@ -535,9 +596,18 @@ def process_add_region(message):
@bot.callback_query_handler(func=lambda call: call.data.startswith("replace_") or call.data.startswith("reactivate_")) @bot.callback_query_handler(func=lambda call: call.data.startswith("replace_") or call.data.startswith("reactivate_"))
def handle_region_action(call): def handle_region_action(call):
action, region_id, region_name = call.data.split("_", 2) parts = call.data.split("_", 2)
action = parts[0]
region_id = parts[1]
region_name = parts[2] if len(parts) > 2 else None
chat_id = call.message.chat.id chat_id = call.message.chat.id
if not region_name:
bot.send_message(chat_id, "Ошибка: Недостаточно данных для выполнения действия.")
bot.answer_callback_query(call.id) # Завершение обработки callback
bot.delete_message(chat_id, call.message.message_id)
return show_settings_menu(chat_id)
with db_lock: with db_lock:
conn = sqlite3.connect('telezab.db') conn = sqlite3.connect('telezab.db')
cursor = conn.cursor() cursor = conn.cursor()
@ -556,6 +626,7 @@ def handle_region_action(call):
conn.commit() conn.commit()
conn.close() conn.close()
bot.answer_callback_query(call.id) # Завершение обработки callback
show_settings_menu(chat_id) show_settings_menu(chat_id)
def process_remove_region(message): def process_remove_region(message):
@ -654,16 +725,19 @@ def handle_active_regions(message):
bot.send_message(chat_id, f"Активные регионы:\n{regions_list}") bot.send_message(chat_id, f"Активные регионы:\n{regions_list}")
show_settings_menu(chat_id) show_settings_menu(chat_id)
# RabbitMQ configuration # RabbitMQ configuration
RABBITMQ_HOST = os.getenv('RABBITMQ_HOST', 'localhost') RABBITMQ_HOST = os.getenv('RABBITMQ_HOST', 'localhost')
RABBITMQ_QUEUE = 'telegram_notifications' RABBITMQ_QUEUE = 'telegram_notifications'
def rabbitmq_connection(): def rabbitmq_connection():
connection = pika.BlockingConnection(pika.ConnectionParameters(RABBITMQ_HOST)) connection = pika.BlockingConnection(pika.ConnectionParameters(RABBITMQ_HOST))
channel = connection.channel() channel = connection.channel()
channel.queue_declare(queue=RABBITMQ_QUEUE, durable=True) channel.queue_declare(queue=RABBITMQ_QUEUE, durable=True)
return connection, channel return connection, channel
def send_to_queue(message): def send_to_queue(message):
connection, channel = rabbitmq_connection() connection, channel = rabbitmq_connection()
channel.basic_publish( channel.basic_publish(
@ -675,6 +749,7 @@ def send_to_queue(message):
)) ))
connection.close() connection.close()
async def consume_from_queue(): async def consume_from_queue():
connection, channel = rabbitmq_connection() connection, channel = rabbitmq_connection()
@ -693,6 +768,7 @@ async def consume_from_queue():
connection.close() connection.close()
async def send_message(chat_id, message, is_notification=False): async def send_message(chat_id, message, is_notification=False):
try: try:
if is_notification: if is_notification:
@ -712,14 +788,17 @@ async def send_message(chat_id, message, is_notification=False):
if is_notification: if is_notification:
rate_limit_semaphore.release() rate_limit_semaphore.release()
async def send_notification_message(chat_id, message): async def send_notification_message(chat_id, message):
await send_message(chat_id, message, is_notification=True) await send_message(chat_id, message, is_notification=True)
async def run_in_executor(func, *args): async def run_in_executor(func, *args):
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
with ThreadPoolExecutor() as pool: with ThreadPoolExecutor() as pool:
return await loop.run_in_executor(pool, func, *args) return await loop.run_in_executor(pool, func, *args)
async def check_telegram_api(): async def check_telegram_api():
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
@ -731,6 +810,7 @@ async def check_telegram_api():
except Exception as e: except Exception as e:
app.logger.error(f"Error checking Telegram API: {e}") app.logger.error(f"Error checking Telegram API: {e}")
@app.route('/webhook', methods=['POST']) @app.route('/webhook', methods=['POST'])
def webhook(): def webhook():
data = request.get_json() data = request.get_json()
@ -777,6 +857,7 @@ def webhook():
return jsonify({"status": "success"}), 200 return jsonify({"status": "success"}), 200
def format_message(data): def format_message(data):
return (f"Zabbix Alert\n" return (f"Zabbix Alert\n"
f"Host: {data['host']}\n" f"Host: {data['host']}\n"
@ -784,6 +865,7 @@ def format_message(data):
f"Trigger: {data['trigger']}\n" f"Trigger: {data['trigger']}\n"
f"Value: {data['value']}") f"Value: {data['value']}")
# Handle active triggers # Handle active triggers
def handle_active_triggers(message): def handle_active_triggers(message):
chat_id = message.chat.id chat_id = message.chat.id
@ -794,6 +876,7 @@ def handle_active_triggers(message):
markup = create_region_markup(regions, start_index, regions_per_page) markup = create_region_markup(regions, start_index, regions_per_page)
bot.send_message(chat_id, "По какому региону хотите получить активные проблемы:", reply_markup=markup) bot.send_message(chat_id, "По какому региону хотите получить активные проблемы:", reply_markup=markup)
def create_region_markup(regions, start_index, regions_per_page): def create_region_markup(regions, start_index, regions_per_page):
markup = telebot.types.InlineKeyboardMarkup() markup = telebot.types.InlineKeyboardMarkup()
end_index = min(start_index + regions_per_page, len(regions)) end_index = min(start_index + regions_per_page, len(regions))
@ -812,18 +895,22 @@ def create_region_markup(regions, start_index, regions_per_page):
markup.row(*row_buttons) markup.row(*row_buttons)
return markup return markup
@bot.callback_query_handler(func=lambda call: call.data.startswith("region_")) @bot.callback_query_handler(func=lambda call: call.data.startswith("region_"))
def handle_region_selection(call): def handle_region_selection(call):
region_id = call.data.split("_")[1] region_id = call.data.split("_")[1]
chat_id = call.message.chat.id chat_id = call.message.chat.id
# Mocking the Zabbix triggers for the given region_id # Получение триггеров из реального Zabbix API
triggers = get_mocked_zabbix_triggers(region_id) triggers = get_zabbix_triggers(region_id)
if not triggers: if not triggers:
bot.send_message(chat_id, "Нет активных проблем по указанному региону за последние 24 часа.") bot.send_message(chat_id, "Нет активных проблем по указанному региону за последние 24 часа.")
else: else:
bot.send_message(chat_id, triggers, parse_mode="Markdown") bot.send_message(chat_id, triggers, parse_mode="Markdown")
bot.answer_callback_query(call.id) # Завершение обработки callback
@bot.callback_query_handler(func=lambda call: call.data.startswith("prev_") or call.data.startswith("next_")) @bot.callback_query_handler(func=lambda call: call.data.startswith("prev_") or call.data.startswith("next_"))
def handle_pagination(call): def handle_pagination(call):
direction, index = call.data.split("_") direction, index = call.data.split("_")
@ -839,22 +926,25 @@ def handle_pagination(call):
markup = create_region_markup(regions, start_index, regions_per_page) markup = create_region_markup(regions, start_index, regions_per_page)
bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup) bot.edit_message_reply_markup(call.message.chat.id, call.message.message_id, reply_markup=markup)
def get_mocked_zabbix_triggers(region_id): bot.answer_callback_query(call.id) # Завершение обработки callback
# Mocked Zabbix triggers
triggers = [
{ # Функция для получения активных триггеров из Zabbix API
"triggerid": "1", def get_zabbix_triggers(region_id):
"description": f"Проблема {region_id}-1", zapi = ZabbixAPI(ZABBIX_URL)
"priority": "4", zapi.login(api_token=ZABBIX_API_TOKEN)
"hosts": [{"hostid": region_id, "name": f"Хост {region_id}-1"}]
}, # Получение триггеров уровня "Высокая" и "Авария" за последние 24 часа
{ triggers = zapi.trigger.get(
"triggerid": "2", output=["triggerid", "description", "priority"],
"description": f"Проблема {region_id}-2", selectHosts=["hostid", "name"],
"priority": "5", filter={"priority": ["4", "5"], "value": "1"},
"hosts": [{"hostid": region_id, "name": f"Хост {region_id}-2"}] search={"host": region_id},
} only_true=1,
] active=1,
withLastEventUnacknowledged=1,
limit=100
)
priority_map = { priority_map = {
'4': 'Высокая', '4': 'Высокая',
@ -872,6 +962,7 @@ def get_mocked_zabbix_triggers(region_id):
return "\n\n---\n\n".join(trigger_messages) return "\n\n---\n\n".join(trigger_messages)
# Test functions for admin # Test functions for admin
def simulate_event(message): def simulate_event(message):
chat_id = message.chat.id chat_id = message.chat.id
@ -888,12 +979,13 @@ def simulate_event(message):
app.logger.info(f"Response from webhook: {response.status_code} - {response.text}") app.logger.info(f"Response from webhook: {response.status_code} - {response.text}")
bot.send_message(chat_id, f"Тестовое событие отправлено. Статус ответа: {response.status_code}") bot.send_message(chat_id, f"Тестовое событие отправлено. Статус ответа: {response.status_code}")
def simulate_triggers(message): def simulate_triggers(message):
chat_id = message.chat.id chat_id = message.chat.id
regions = ["12", "19", "35", "40"] regions = ["12", "19", "35", "40"]
trigger_messages = [] trigger_messages = []
for region_id in regions: for region_id in regions:
triggers = get_mocked_zabbix_triggers(region_id) triggers = get_zabbix_triggers(region_id)
if triggers: if triggers:
trigger_messages.append(f"Регион {region_id}:\n{triggers}") trigger_messages.append(f"Регион {region_id}:\n{triggers}")
@ -902,9 +994,11 @@ def simulate_triggers(message):
else: else:
bot.send_message(chat_id, "Нет активных проблем по указанным регионам за последние 24 часа.") bot.send_message(chat_id, "Нет активных проблем по указанным регионам за последние 24 часа.")
def run_polling(): def run_polling():
bot.polling(none_stop=True, interval=0) bot.polling(none_stop=True, interval=0)
if __name__ == '__main__': if __name__ == '__main__':
init_db() init_db()