Подружим Sentry и Mattermost быстро и просто через адаптер

—

от автора

Всем привет, если у вас появилась идея связать эти два инструмента, то хочу вас огорчить, прямой интеграции у них пока нет…

4 простеньких шага для решения этой проблемы:

  • Создаем webhook в Mattermost

  • Создаем Custom Integration и Alert в Sentry

  • Пишем небольшой сервис, который будет принимать сообщение(event) из Sentry

  • Приводим event в нужный формат и отправляем в Mattermost с помощью webhook

Весь код сервиса лежит в этом репозитории на гитхибе.

Когда я столкнулся с проблемой, я начал искать готовые решения или хотя бы туториалы по интеграции этих инструментов, но не нашел ничего и решил это исправить, написав гайд и возможно, сэкономив кому-то пару часов, а может и дней жизни. Код сервиса будет максимально простой, главная идея статьи — показать один из способов решения проблемы и направить в какую сторону копать, надеюсь кому-то пригодится:)

Какие проблемы решает сервис

  1. Как я уже написал ранее, на сегодняшний день прямой интеграции Sentry и Mattermost нет.

    Если в Sentry зайти в settings -> integrations вы увидите очень много разных плагинов, но нужного нам нет.

  2. Интеграция напрямую через webhook так же не сработает, так как webhook Mattermost ждет один формат, а Sentry шлет совсем другой (вы получите 404 ошибку при отправке напрямую).

    Например если вы захотите получать уведомления из Gitlab в Mattermost, вам достаточно в Gitlab зайти в settings -> integrations -> добавить интеграцию Mattermost notification — done! Но с Sentry так не сработает:(

Приступим по шагам

Создаем webhook Mattermost:

Create incoming hook

Create incoming hook

Если у вас нет кнопки «Интеграции» — попросите админа сервера:
Зайти в админ панель Mattermost → Найти раздел Integrations → Enable Incoming Webhooks

Создаем Custom Integration и Alert в Sentry

  • Заходим Settings → Custom Integrations → Create new integration

    • Name — Имя интеграции

    • Webhook URL — домен + роут где будет лежать наш адаптер

    • Alert Rule Action — true

    • В разделе Webhooks ставим галочки на нужные events

    • Остальное можно оставить по дефолту → Создаем интеграцию

  • Заходим в Alert → Create new alert → Issues → Set Conditions

  • Далее в открывшемся окне в пункте Set Conditions вы можете задать правила отправки уведомлений, так называемые тригеры по условиям.

  • Главное в окне THEN выбрать раннее созданную интеграцию по имени, которые вы задали

  • Остальное можно оставить по дефолту, подробнее почитать тут

Пишем сам адаптер

  • Приложение напишем на Nodejs, ссылка на репо

  • Ниже прикрепляю 2 основных файла, с комментариями:

Точка входа в приложение — app.js

const express = require("express"); const bodyParser = require("body-parser"); const axios = require("axios"); const logger = require("./utils/logger"); const getTextForMattermost = require("./getTextForMattermost"); require("dotenv").config();  const app = express(); const PORT = process.env.PORT || 4045; // Сюда вставить вебхук из Mattermos const URL_WEBHOOK = process.env.URL_WEBHOOK;  app.use(bodyParser.json());  // Endpoint на который Sentry будет кидать event app.post("/webhook", ({ headers, body }) => {   try {     // Отправляем отформатированный формат eventа в Mattermost     axios.post(URL_WEBHOOK, { text: getTextForMattermost({ headers, body }) });   } catch (err) {     logger.error("Ошибка при отправке в Mattermost", error);   } });  app   .listen(PORT, () => {     logger.info(`Сервер успешно запущен на порту ${PORT}`);   })   .on("error", (error) => logger.error("Ошибка при запуске сервера", error)); 

Файл форматирования — getTextForMattermost.js

const findDeepValue = require("./utils/findDeepValue"); const logger = require("./utils/logger");  /** Замкнули обьект с данными, для удобного получения нужных полей из этого обьекта на любом уровне вложенности; */ const getDataFromRequest = (reqBody) => {   return (fieldName) => {     return findDeepValue(reqBody, fieldName);   }; }; /** Sentry кидает обьект ошибки, fieldName это нужны поля из этого обьекта; */ const configFields = [   { fieldName: "environment", labelName: "Окружение" },   { fieldName: "title", labelName: "Название" },   { fieldName: "action", labelName: "Действие" },   { fieldName: "web_url", labelName: "Сслыка на Sentry" },   { fieldName: "status", labelName: "Статус" },   { fieldName: "message", labelName: "Описание(message)" }, ]; /** Формируем сообщение для Mattermost */ module.exports = getTextForMattermost = ({ headers, body }) => {   try {     logger.info("Из Sentry пришло событие", { headers, body });      /**  Docs Sentry: https://docs.sentry.io/product/integrations/integration-platform/webhooks/?original_referrer=https%3A%2F%2Fwww.google.com%2F#sentry-hook-resource */     const resource = headers["Sentry-Hook-Resource"]; // installation | event_alert | issue | metric_alert | error | comment      const getFieldFromData = getDataFromRequest(body);      let message = "";     configFields.forEach((item) => {       const value = getFieldFromData(item.fieldName);       if (value) {         message += `###### ${item.labelName}: ${value}\n`;       }     });     if (resource) {       message += `###### Название ресурса: ${resource}`;     }      return `#### Ошибка в анкете, подробности ниже:\n ${message}`;   } catch (error) {     logger.error("Ошибка в методе getTextForMattermost", error);     return (       `#### Ошибка в адапторе:\nЧто-то сломалось в методе getTextForMattermost, проверьте логи на сервере адаптера ` +       error?.message     );   } }; 

Остается задеплоить ваш сервис на хостинг и запустить (я использую pm2 для управления процессами ноды), не забудьте правильно указать Webhook URL при создании интеграции с правильным доменом, на котором будет лежать ваш адаптер.

Чтобы проверить работы сервисы, вы можете на шаге создания Alert в Sentry, выбрав вашу Интеграцию, отправить “Send Test Notifications” → Должно прийти сообщение в Mattremost

Ресурсы:

Вот и все! Спасибо за внимание:)


ссылка на оригинал статьи https://habr.com/ru/articles/761962/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *