Jump to content

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


Recommended Posts

Posted

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

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

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

 

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

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

response = request.post(url, data);

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

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

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

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

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

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

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

Posted

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

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

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

Posted

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

 

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

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

Posted

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

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

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

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

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

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

Posted

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

<?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 нужно подставить свои, но в принципе скрипт полный и рабочий.

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.

×
×
  • Create New...
На сайте используются файлы cookie и сервисы аналитики для корректной работы форума и улучшения качества обслуживания. Продолжая использовать сайт, вы соглашаетесь с использованием файлов cookie и с Политикой конфиденциальности.