Jump to content
Калькуляторы

Zabbix, уведомление в Телеграм с прикреплением активных аварий

Есть Zabbix 5.4.2, в котором настроено оповещение в Телеграм.

Для оповещалки используется штатный js-скрипт.

Неудобством является то, что из оповещений Телеграма сложно понять, какие аварии все еще активны.

 

Хочу сделать так, чтобы все активные аварии автоматически прикреплялись, а при закрытии аварии откреплялись.

С закреплением проблем нет, в js-скрипте я после строчки

response = request.post(url, data);

добавлю еще вызов метода pinChatMessage и передам в нем response.message_id.

Но вот как потом откреплять — пока не придумал.

По идее, при возникновении аварии мне нужно где-то запоминать EVENT.ID и сопоставленный с ним идентификатор сообщения Телеграма.

А при закрытии аварии нужно по EVENT.ID находить идентификатор ранее отправленного сообщения Телеграм.

Но вот где хранить сопоставленный идентифиватор сообщения Телеграм — хороших идей нет.

Лучше всего было бы хранить прямо в самом событии Заббикса (EVENT), но из js-скрипта к нему доступа нет.

А изобретать костыли бы не хотелось.

Share this post


Link to post
Share on other sites

А мне бы для монтажников нужно в чате телеграмм писать только Recent Alarm.

Если данный список изменился, то удалять все записи в чате и писать новый обновленный список аварий.

Есть идеи как это можно реализовать?

Share this post


Link to post
Share on other sites

Запоминать при публикации message_id.
При изменениях в составе аварий редактировать сообщение.
Если аварий нет, то удалять сообщение и забывать message_id.

 

Но это все будет каким-то сторонним решением.

А я бы хотел без костылей, использовать штатный механизм заббикса.

Share this post


Link to post
Share on other sites

Хотя я тут немного покопался, можно по быстрому и почти штатно.

Нужно добавить способ оповещения с типом "скрипт", в параметрах скрипта прописать {EVENT.ID}, настроить скрипт на возникновение проблемы и восстановление проблемы.

Затем в /usr/lib/zabbix/alertscripts создать скрипт с указанным именем.

Заббикс будет вызывать скрипт, передавая в него идентификатор события. Но в принципе, идентификатор события особо не нужен.

Скрипт с помощью метода problem.get будет получать список текущих проблем, формировать текст и с помощью editMessageText обновлять текст сообщения.

А идентификатор сообщения можно просто прописать прямо в скрипте.

Share this post


Link to post
Share on other sites

А вот и скрипт.

<?php

print "Подключение к NMS Zabbix\n";
if (!$zb = new Zabbix (null)) {
        print "! Сбой инициализации NMS Zabbix\n";
        exit;
} elseif ($zb->error()) {
        print "! Сбой подключения NMS Zabbix: " . $zb->error() . "\n";
        exit;
}

file_put_contents("/tmp/{$script}_buffer.tmp", getmypid() . "\n", FILE_APPEND);
print "Запрос действующих проблем из Zabbix...\n";
$tmp = $zb->request("problem.get", ["output"=>"extend", "recent"=>false, "severities"=>[4,5], "groupids"=>[19,20,21,22], "sortfield"=>["eventid"], "sortorder"=>"DESC"]);
if (!$tmp)
{
        print "! Ошибка получения списка проблем из Zabbix\n";
        exit;
}
if (isset($tmp['error']))
{
        print "! Ошибка получения списка проблем из Zabbix: {$response['error']}\n";
        exit;
}
$tmp = $tmp['result'];
print "Запрос списка проблем из Zabbix выполнен, строк: " . count($tmp) . "\n";
$lst = [];
foreach ($tmp as $rec) $lst[$rec['eventid']] = ['id'=>$rec['eventid'], 'clock'=>$rec['clock'], 'problem'=>$rec['name'], 'level'=>$rec['severity']];

print "Запрос деталей проблем из Zabbix...\n";
$tmp = $zb->request("event.get", ["output"=>"extend", "eventids"=>array_keys($lst), "selectHosts"=>"extend"]);
if (!$tmp)
{
        print "! Ошибка получения деталей проблем из Zabbix\n";
        exit;
}
if (isset($tmp['error']))
{
        print "! Ошибка получения деталей проблем из Zabbix: {$response['error']}\n";
        exit;
}
$tmp = $tmp['result'];
foreach ($tmp as $rec)
{
        if (!isset($lst[$rec['eventid']])) continue;
        if (!$rec['value']) continue;
        if (isset($rec['hosts'], $rec['hosts'][0]))
        {
                if ($rec['hosts'][0]['status']) continue;
                $lst[$rec['eventid']]['host'] = $rec['hosts'][0]['host'];
                $lst[$rec['eventid']]['title'] = $rec['hosts'][0]['name'];
                $lst[$rec['eventid']]['date'] = date("Y-m-d H:i", $rec['clock']);
                $lst[$rec['eventid']]['time'] = time() -  $rec['clock'];
        }
}
$lst = array_filter($lst, function($rec) { return isset($rec['host']);});
$ids = array_keys($lst);
sort($ids);
$ids = implode(",", $ids);

$ref = null; $old = "";
if (file_exists("/tmp/{$script}_telegram.tmp"))
{
        $tmp = file_get_contents("/tmp/{$script}_telegram.tmp");
        if (($tmp !== false) && $tmp)
        {
                $ref = trim(strtok($tmp, ":"));
                $old = trim(strtok(":"));
        }
}

print "Буфферизация отправки команд...";
sleep(2);
if (!file_exists("/tmp/{$script}_buffer.tmp")) exit;
$tmp = file_get_contents("/tmp/{$script}_buffer.tmp");
if (!$tmp) exit;
$tmp = explode("\n", trim($tmp));
$tmp = end($tmp);
if ($tmp != getmypid()) exit;
unlink("/tmp/{$script}_buffer.tmp");

$tlg = new Telegram();
$rcpt = '...';

if ($ids) {
        print "# Есть аварии\n";
        if ($ids == $old) {
                print "# Состав аварий не изменился, ничего не делать\n";
                null;
        } else {
                print "# Состав аварий изменился\n";
                $tlg->build();
                $tlg->build("Список действующих аварий:\n");
                foreach ($lst as $rec)
                {
                        $tlg->build("- {$rec['title']} (с " . date("Y-m-d H:i", $rec['clock']) . ")\n");
                }
                $tlg->build("\nИнформация обновлена: " . date("Y-m-d H:i:s"));
                if ($ref) {
                        print "# Если есть закрепленное сообщение, то обновить его\n";
                        $tlg->editMessageText($rcpt, $ref);
                        file_put_contents("/tmp/{$script}_telegram.tmp", "{$ref}: {$ids}");
                } else {
                        print "# Если закрепленного сообщения нет, то создать его и сохранить кеш\n";
                        if ($tmp = $tlg->sendMessage($rcpt)) {
                                $ref = $tmp['message_id'];
                                $tlg->pinChatMessage($rcpt, $ref);
                                file_put_contents("/tmp/{$script}_telegram.tmp", "{$ref}: {$ids}");
                        }
                }
        }
} else {
        print "# Нет аварий\n";
        if ($ref) {
                print "# Если есть закрепленное сообщение, то закрыть его и удалить кеш\n";
                $tlg->build();
                $tlg->build("Активные аварии отсутствуют.\n");
                $tlg->build("\nИнформация обновлена: " . date("Y-m-d H:i:s"));
                $tlg->editMessageText($rcpt, $ref);
                $tlg->unpinChatMessage($rcpt, $ref);
                unlink("/tmp/{$script}_telegram.tmp");
        }
}

Обертки Zabbix и Telegram нужно подставить свои, но в принципе скрипт полный и рабочий.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.