Работая в большом проекте, с огромным числом пользователей, для поддержки критически важно получать оповещения о проблемах как можно быстрее. Не все системы мониторинга могут предоставить инструменты для мониторинга сложных бизнес процессов из коробки. Многое специфическое приходится писать самостоятельно. Для того, что бы быть уверенным, что в случае проблемы заинтересованные сотрудники получат сообщения, приняли решение использовать RabbitMQ. В очереди помещаем сообщения, которые являются результатом работы самописных скриптов, которые по сложной логике генерят сообщения в случае отклонения каких-либо показателей бизнес процессов от нормы.
Для того, что бы как можно быстрее поддержка была оповещена о проблемах, был написан скрипт на Python, который запускается как служба Windows. Скрипт выполняет следующие задачи:
- Получает сообщения из очереди RMQ.
- Обрабатывает полученное сообщение и отправляет сообщения в канал в Teams.
Получение сообщений из очереди:
Для начала требуется настроить входящий веб перехватчик в канале Teams:
1. Зайдем в настройки канала Teams
2. Добавим "Входящий веб-перехватчик"
Добавляем имя соединителя, получаем ссылку и сохраняем ее. Ссылку на соединитель нужно будет указать в файле config.py
Если Входящий веб-перехватчик уже добавлялся, то ссылку на него можно найти в "УПРАВЛЕНИЕ" - "Настроено"
Заполним значения переменных в конфигурационном файлике.
Файл config.py выглядит так:
# rmq
rmq_server = 'имя сервера rabbitmq'
rmq_port = порт
rmq_queue_name = 'имя очереди'
rmq_user_name = 'имя пользователя'
rmq_user_password = 'пароль пользователя'
# teams
teams_channel = 'url адрес настроенного соединителя в канале Teams'
# service
service_name = 'Имя службы'
service_display_name = 'Видимое имя службы'
Для получения сообщения из нужной очереди требуется выполнить следующий код
# Импортируем нужные модули
import pika
import pymsteams
import time
# Импортируем файл конфигурации
import config
# Задаем имя пользователя и пароль для Connection
credentials = pika.PlainCredentials(config.rmq_user_name, config.rmq_user_password)
# Создаем Connection с RMQ
connection = pika.BlockingConnection(pika.ConnectionParameters(host=config.rmq_server, port=config.rmq_port, credentials=credentials))
# Создаем оболочку channel для взаимодействия с RabbitMQ, реализующую методы и поведение для канала AMQP
channel = connection.channel()
# Получаем method_frame, header_frame и body, нас будут интересовать наличие method_frame и содержимое body
method_frame, header_frame, body = channel.basic_get(config.rmq_queue_name)
Обработка и отправка сообщений:
Для отправки сообщения в Teams требуется выполнить следующий код
# Начинаем бесконечный цикл
while 1:
# Проверяем наличие method_frame
if method_frame:
# Разбираем бинарную строку в body и делаем из нее словарь. Здесь может быть все, что угодно, мое сообщение удобнее сделать словарем
body = dict((a.strip(), b.strip()) for a, b in (element.split('":') for element in body.decode("utf-8").split(',"')))
# Задаем адрес соединителя с каналом в Teams
teams_channel = config.teams_channel
# Подключаемся к каналу
myTeamsMessage = pymsteams.connectorcard(hookurl=teams_channel, verify=False)
# Редактируем текст: убираем лишние слэши и меняем символы юникода, у которых удвоились слэши. Здесь тоже может быть все, что угодно
myTeamsMessage.text(str(body["message"]).replace('\\r', '\r').replace('\\n', '\n').replace('\\u0027', "'").replace('\\u003e', '>'))
# Задаем цвет текста
myTeamsMessage.color("#003333")
# Задаем заголовок сообщения
myTeamsMessage.title("¡alarm!")
# Отправляем сообщение
myTeamsMessage.send()
# Сообщаем RMQ, что мы забрали сообщение, после этого сообщение из очереди удаляется
channel.basic_ack(method_frame.delivery_tag)
# Спим 10 секунд
time.sleep(10)
else:
# Если method_frame нет спим 10 секунд
time.sleep(10)
Создание службы Windows
Для того, что бы данный код выполнялся как служба Windows, требуется использовать библиотеки pywin32 и добавить код для объявления, запуска и остановки службы. Окончательно код должен выглядеть так
import pika
import pymsteams
import time
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import config
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = config.service_name
_svc_display_name_ = config.service_display_name
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
# Здесь находится код из п.1 и п. 2 инструкции
while 1:
credentials = pika.PlainCredentials(config.rmq_user_name, config.rmq_user_password)
connection = pika.BlockingConnection(pika.ConnectionParameters(
host=config.rmq_server, port=config.rmq_port, credentials=credentials))
channel = connection.channel()
method_frame, header_frame, body = channel.basic_get(config.rmq_queue_name)
if method_frame:
body = dict((a.strip(), b.strip()) for a, b in (element.split('":') for element in body.decode("utf-8").split(',"')))
teams_channel = config.teams_channel
myTeamsMessage = pymsteams.connectorcard(hookurl=teams_channel, verify=False)
myTeamsMessage.text(str(body["message"]).replace('\\r', '\r').replace('\\n', '\n').replace('\\u0027', "'").replace('\\u003e', '>'))
myTeamsMessage.color("#003333")
myTeamsMessage.title("¡alarm!")
myTeamsMessage.send()
channel.basic_ack(method_frame.delivery_tag)
channel.basic_ack(method_frame.delivery_tag)
connection.close()
time.sleep(10)
else:
connection.close()
time.sleep(10)
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
Для того, что бы создать службу Windows, требуется запустить в cmd, открытой под администратором следующую команду
<"путь к python.exe"> <"путь к python файлу со скриптом"> install
При запуске возможны проблемы, т.к. в папке, где находится "pythonservice.exe", по умолчанию это "C:\Program Files\Python<XX>\Lib\site-packages\win32" может не быть библиотек python<XX>.dll, pythoncom<XX>.dll и pywintypes<XX>.dll.
XX - версия Python(например python39.dll, pythoncom39.dll, pywintypes39.dll)
Эти файлы можно найти в папках:
python<XX>.dll - C:\Program Files\Python<XX>
pythoncom<XX>.dll и pywintypes<XX>.dll - C:\Program Files\Python<XX>\Lib\site-packages\pywin32_system32
Достаточно просто скопировать эти файлы в папку "C:\Program Files\Python<XX>\Lib\site-packages\win32"