Перейти к содержимому
Калькуляторы

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

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

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

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

 

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

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

response = request.post(url, data);

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

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

<?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.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.