diff --git a/app/bot/handlers/active_triggers.py b/app/bot/handlers/active_triggers.py
index f53eb17..db6deae 100644
--- a/app/bot/handlers/active_triggers.py
+++ b/app/bot/handlers/active_triggers.py
@@ -1,12 +1,12 @@
from telebot.types import Message, CallbackQuery
from app.bot.keyboards.active_triggers import create_region_keyboard
-from app.bot.utils.regions import get_sorted_regions_plain
from app.bot.processors.active_triggers_processor import (
process_region_selection,
process_group_selection,
process_all_groups_request,
)
+from app.bot.utils.regions import get_sorted_regions_plain
def register_active_triggers(bot, app, state_manager):
@@ -22,17 +22,28 @@ def register_callbacks_active_triggers(bot,app,state_manager):
@bot.callback_query_handler(func=lambda c: c.data.startswith("region_"))
def region_selected(callback_query: CallbackQuery):
region_id = callback_query.data.split("_")[1]
- process_region_selection(callback_query.message.chat.id,bot, region_id)
+ chat_id = callback_query.message.chat.id
+ bot.answer_callback_query(callback_query.id)
+ bot.delete_message(chat_id, callback_query.message.message_id)
+ process_region_selection(bot, chat_id, region_id)
@bot.callback_query_handler(func=lambda c: c.data.startswith("group_"))
def group_selected(callback_query: CallbackQuery):
group_id = callback_query.data.split("_")[1]
- process_group_selection(callback_query.message.chat.id,bot, group_id)
+ chat_id = callback_query.message.chat.id
+ bot.answer_callback_query(callback_query.id)
+ bot.delete_message(chat_id, callback_query.message.message_id)
+ bot.send_message(chat_id, f"Обработка...")
+ process_group_selection(bot, chat_id, group_id)
@bot.callback_query_handler(func=lambda c: c.data.startswith("all_groups_"))
def all_groups_selected(callback_query: CallbackQuery):
region_id = callback_query.data.split("_")[2]
- process_all_groups_request(callback_query.message.chat.id,bot, region_id)
+ chat_id = callback_query.message.chat.id
+ bot.answer_callback_query(callback_query.id)
+ bot.delete_message(chat_id, callback_query.message.message_id)
+ bot.send_message(chat_id, f"Обработка...")
+ process_all_groups_request(bot, chat_id, region_id)
@bot.callback_query_handler(func=lambda c: c.data.startswith("regions_page_"))
def regions_page_selected(callback_query: CallbackQuery):
diff --git a/app/bot/keyboards/active_triggers.py b/app/bot/keyboards/active_triggers.py
index d1879ff..6403fae 100644
--- a/app/bot/keyboards/active_triggers.py
+++ b/app/bot/keyboards/active_triggers.py
@@ -30,10 +30,3 @@ def create_region_keyboard(regions, page, page_size=REGIONS_PER_PAGE):
markup.add(cancel_button)
return markup
-
-def create_group_keyboard(groups, region_id):
- markup = InlineKeyboardMarkup()
- for group in groups:
- markup.add(InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
- markup.add(InlineKeyboardButton(text="Все группы региона\n(Долгое выполнение)", callback_data=f"all_groups_{region_id}"))
- return markup
diff --git a/app/bot/keyboards/groups.py b/app/bot/keyboards/groups.py
new file mode 100644
index 0000000..0a6a92c
--- /dev/null
+++ b/app/bot/keyboards/groups.py
@@ -0,0 +1,23 @@
+from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
+
+def create_groups_keyboard(groups, region_id):
+ """
+ Формирует InlineKeyboardMarkup для выбора группы хостов.
+
+ :param groups: список словарей с группами, у каждой есть 'name' и 'groupid'
+ :param region_id: id региона, нужен для callback_data кнопки "Все группы региона"
+ :return: telebot.types.InlineKeyboardMarkup
+ """
+ markup = InlineKeyboardMarkup()
+ for group in groups:
+ markup.add(InlineKeyboardButton(
+ text=group['name'],
+ callback_data=f"group_{group['groupid']}"
+ ))
+ markup.add(InlineKeyboardButton(
+ text="Все группы региона\n(Долгое выполнение)",
+ callback_data=f"all_groups_{region_id}"
+ ))
+ cancel_button = InlineKeyboardButton("Отмена", callback_data="cancel_input")
+ markup.add(cancel_button)
+ return markup
diff --git a/app/bot/processors/active_triggers_processor.py b/app/bot/processors/active_triggers_processor.py
index 676706c..8837182 100644
--- a/app/bot/processors/active_triggers_processor.py
+++ b/app/bot/processors/active_triggers_processor.py
@@ -1,19 +1,20 @@
-from telebot import types
-from app.bot.keyboards.main_menu import get_main_menu
-from app.bot.utils.zabbix import get_region_groups, get_all_groups_for_region, fetch_filtered_triggers
-from app.bot.utils.tg_formatter import format_trigger_message # ⬅️ добавлено
+from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
-def process_region_selection(bot,chat_id, region_id):
+from app.bot.keyboards.groups import create_groups_keyboard
+from app.bot.keyboards.main_menu import get_main_menu
+from app.bot.utils.tg_formatter import format_trigger_for_tg
+from app.bot.utils.zabbix_alt import (
+ get_region_groups,
+ get_all_groups_for_region,
+ fetch_triggers_data)
+
+
+def process_region_selection(bot, chat_id, region_id):
try:
groups = get_region_groups(region_id)
if not groups:
return bot.send_message(chat_id, "Нет групп хостов для этого региона.")
-
- markup = types.InlineKeyboardMarkup()
- for group in groups:
- markup.add(types.InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
- markup.add(types.InlineKeyboardButton(text="Все группы региона\n(Долгое выполнение)", callback_data=f"all_groups_{region_id}"))
-
+ markup = create_groups_keyboard(groups, region_id)
bot.send_message(chat_id, "Выберите группу хостов:", reply_markup=markup)
except Exception as e:
bot.send_message(chat_id, f"Ошибка при получении групп: {str(e)}", reply_markup=get_main_menu())
@@ -21,11 +22,16 @@ def process_region_selection(bot,chat_id, region_id):
def process_group_selection(bot, chat_id, group_id):
try:
- triggers = fetch_filtered_triggers(group_id)
+ triggers = fetch_triggers_data(group_id)
if not triggers:
bot.send_message(chat_id, "Нет активных событий.")
- else:
- send_trigger_messages(chat_id, triggers)
+ return
+
+ for trigger in triggers:
+ text, url = format_trigger_for_tg(trigger)
+ markup = InlineKeyboardMarkup()
+ markup.add(InlineKeyboardButton(text="Открыть график", url=url))
+ bot.send_message(chat_id, text, reply_markup=markup, parse_mode="HTML")
except Exception as e:
bot.send_message(chat_id, f"Ошибка при получении событий: {str(e)}")
@@ -36,21 +42,21 @@ def process_all_groups_request(bot, chat_id, region_id):
groups = get_all_groups_for_region(region_id)
for group in groups:
try:
- triggers = fetch_filtered_triggers(group['groupid'])
+ triggers = fetch_triggers_data(group['groupid'])
if triggers:
all_triggers.extend(triggers)
except Exception:
continue
- if all_triggers:
- send_trigger_messages(chat_id, all_triggers)
- else:
+ if not all_triggers:
bot.send_message(chat_id, "Нет активных событий.")
+ return
+
+ for trigger in all_triggers:
+ text, url = format_trigger_for_tg(trigger)
+ markup = InlineKeyboardMarkup()
+ markup.add(InlineKeyboardButton(text="Открыть график", url=url))
+ bot.send_message(chat_id, text, reply_markup=markup, parse_mode="HTML")
+
except Exception as e:
bot.send_message(chat_id, f"Ошибка при получении данных: {str(e)}")
-
-
-def send_trigger_messages(chat_id, triggers):
- for trigger in triggers:
- text = format_trigger_message(trigger)
- bot.send_message(chat_id, text, parse_mode="MarkdownV2")
diff --git a/app/bot/utils/zabbix.py b/app/bot/utils/zabbix.py
deleted file mode 100644
index 5a88f1e..0000000
--- a/app/bot/utils/zabbix.py
+++ /dev/null
@@ -1,119 +0,0 @@
-import time
-from datetime import datetime
-from pytz import timezone
-from pyzabbix import ZabbixAPI, ZabbixAPIException
-from telebot import logger
-
-from config import ZABBIX_URL, ZABBIX_API_TOKEN, ZABBIX_VERIFY_SSL, ZABBIX_TZ
-from app.bot.utils.tg_escape_chars import escape_telegram_chars
-TZ = timezone(ZABBIX_TZ)
-verify_ssl = ZABBIX_VERIFY_SSL
-
-def get_region_groups(region_id: str):
- """
- Получает список групп, имя которых содержит регион region_id, исключая 'test'.
- """
- try:
- zapi = ZabbixAPI(ZABBIX_URL)
- zapi.login(api_token=ZABBIX_API_TOKEN)
- zapi.session.verify = verify_ssl
-
- host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
- filtered_groups = [group for group in host_groups if 'test' not in group['name'].lower()]
- return filtered_groups
- except Exception as e:
- logger.error(f"Error getting region groups for '{region_id}': {e}")
- return []
-
-def get_all_groups_for_region(region_id: str):
- """
- Аналогично get_region_groups, получение всех групп по региону.
- """
- return get_region_groups(region_id)
-
-def fetch_filtered_triggers(group_id):
- """
- Получение и фильтрация триггеров с severities 4 и 5,
- формирование HTML сообщений для отправки в Telegram.
- """
- try:
- zapi = ZabbixAPI(ZABBIX_URL)
- zapi.login(api_token=ZABBIX_API_TOKEN)
- zapi.session.verify = verify_ssl
-
- problems = zapi.problem.get(
- severities=[4, 5],
- suppressed=0,
- acknowledged=0,
- groupids=group_id
- )
- trigger_ids = [problem["objectid"] for problem in problems]
-
- if not trigger_ids:
- return []
-
- triggers = zapi.trigger.get(
- triggerids=trigger_ids,
- output=["triggerid", "description", "priority"],
- selectHosts=["hostid", "name"],
- monitored=1,
- expandDescription=1,
- expandComment=1,
- selectItems=["itemid", "lastvalue"],
- selectLastEvent=["clock", "eventid"]
- )
-
- events = zapi.event.get(
- severities=[4, 5],
- objectids=trigger_ids,
- select_alerts="mediatype"
- )
-
- pnet_mediatypes = {"Pnet integration JS 2025", "Pnet integration JS 2024", "Pnet integration new2"}
-
- pnet_triggers = []
- event_dict = {event["objectid"]: event for event in events}
-
- for trigger in triggers:
- event = event_dict.get(trigger["triggerid"])
- if event:
- for alert in event["alerts"]:
- if alert["mediatypes"] and alert["mediatypes"][0]["name"] in pnet_mediatypes:
- pnet_triggers.append(trigger)
- break
-
- triggers_sorted = sorted(pnet_triggers, key=lambda t: int(t['lastEvent']['clock']))
-
-
- priority_map = {'4': 'HIGH', '5': 'DISASTER'}
- trigger_messages = []
-
- for trigger in triggers_sorted:
- event_time_epoch = int(trigger['lastEvent']['clock'])
- event_time = datetime.fromtimestamp(event_time_epoch, tz=TZ)
- description = escape_telegram_chars(trigger['description'])
- host = trigger['hosts'][0]['name']
- priority = priority_map.get(trigger['priority'], 'Неизвестно')
- item_ids = [item['itemid'] for item in trigger['items']]
- batchgraph_link = f"{ZABBIX_URL}/history.php?action=batchgraph&"
- batchgraph_link += "&".join([f"itemids[{item_id}]={item_id}" for item_id in item_ids])
- batchgraph_link += "&graphtype=0"
- description = description.replace("{HOST.NAME}", host)
- for i, item in enumerate(trigger['items']):
- lastvalue_placeholder = f"{{ITEM.LASTVALUE{i + 1}}}"
- if lastvalue_placeholder in description:
- description = description.replace(lastvalue_placeholder, item['lastvalue'])
- event_time_formatted = event_time.strftime('%Y-%m-%d %H:%M:%S Мск')
- message = (f"Host: {host}\n"
- f"Описание: {description}\n"
- f"Критичность: {priority}\n"
- f"Время создания: {event_time_formatted}\n"
- f'URL: Ссылка на график')
- trigger_messages.append(message)
-
- logger.info(f"Fetched {len(triggers_sorted)} triggers for group {group_id}.")
- return trigger_messages
-
- except Exception as e:
- logger.error(f"Error fetching triggers for group {group_id}: {e}")
- return []
diff --git a/app/bot/utils/zabbix_alt.py b/app/bot/utils/zabbix_alt.py
new file mode 100644
index 0000000..ce3c1d0
--- /dev/null
+++ b/app/bot/utils/zabbix_alt.py
@@ -0,0 +1,103 @@
+import re
+import time
+
+from pyzabbix import ZabbixAPI, ZabbixAPIException
+from telebot import logger
+
+from config import ZABBIX_URL, ZABBIX_API_TOKEN, ZABBIX_VERIFY_SSL
+
+
+def get_region_groups(region_id: str):
+ """
+ Получает список групп, имя которых содержит регион region_id, исключая 'test' и группы, не соответствующие шаблону 'имя_число'.
+ """
+ try:
+ zapi = ZabbixAPI(ZABBIX_URL)
+ zapi.login(api_token=ZABBIX_API_TOKEN)
+ zapi.session.verify = ZABBIX_VERIFY_SSL
+
+ host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
+
+ pattern = re.compile(r'.+_\d+$') # строка с нижним подчёркиванием перед числом в конце
+
+ filtered_groups = [
+ group for group in host_groups
+ if 'test' not in group['name'].lower() and pattern.match(group['name'])
+ ]
+ return filtered_groups
+
+ except Exception as e:
+ logger.error(f"[Zabbix] Error getting region groups for '{region_id}': {e}")
+ return []
+
+def get_all_groups_for_region(region_id: str):
+ """
+ Аналогично get_region_groups, получение всех групп по региону.
+ """
+ return get_region_groups(region_id)
+
+
+def fetch_triggers_data(group_id):
+ """
+ Возвращает список триггеров с необходимыми данными,
+ без форматирования сообщений.
+ """
+ pnet_mediatypes = {"Pnet integration JS 2025", "Pnet integration JS 2024", "Pnet integration new2"}
+ start_time = time.time()
+ try:
+ zapi = ZabbixAPI(ZABBIX_URL)
+ zapi.login(api_token=ZABBIX_API_TOKEN)
+
+ # Получаем проблемы с высокой и критической важностью
+ problems = zapi.problem.get(
+ severities=[4, 5],
+ suppressed=0,
+ acknowledged=0,
+ groupids=group_id
+ )
+ trigger_ids = [problem["objectid"] for problem in problems]
+
+ if not trigger_ids:
+ logger.info(f"No triggers found for group {group_id}")
+ return []
+
+ triggers = zapi.trigger.get(
+ triggerids=trigger_ids,
+ output=["triggerid", "description", "priority"],
+ selectHosts=["hostid", "name"],
+ monitored=1,
+ expandDescription=1,
+ expandComment=1,
+ selectItems=["itemid", "lastvalue"],
+ selectLastEvent=["clock", "eventid"]
+ )
+
+ events = zapi.event.get(
+ severities=[4, 5],
+ objectids=trigger_ids,
+ select_alerts="mediatype"
+ )
+
+ event_dict = {event["objectid"]: event for event in events}
+
+ pnet_triggers = []
+ for trigger in triggers:
+ event = event_dict.get(trigger["triggerid"])
+ if event:
+ for alert in event["alerts"]:
+ if alert["mediatypes"] and alert["mediatypes"][0]["name"] in pnet_mediatypes:
+ pnet_triggers.append(trigger)
+ break
+
+ triggers_sorted = sorted(pnet_triggers, key=lambda t: int(t['lastEvent']['clock']))
+ logger.debug(f"Found {len(pnet_triggers)} pnet triggers for group {group_id}")
+ end_time = time.time()
+ logger.info(f"[Zabbix] Fetched {len(triggers_sorted)} triggers for group {group_id} in {end_time - start_time:.2f} seconds.")
+ return triggers_sorted
+
+ except ZabbixAPIException as e:
+ logger.error(f"[Zabbix] Zabbix API error for group {group_id}: {e}")
+ return []
+ except Exception as e:
+ logger.error(f"[Zabbix] Unexpected error fetching triggers for group {group_id}: {e}")
+ return []