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

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

Ресурсы:

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

Комментарии (3)


  1. m1skam
    19.09.2023 13:04

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

    Ээээм, как то странно, у меня поисковая выдача завалена решениями.


    1. nikitapaparimskiy Автор
      19.09.2023 13:04

      Да, выдача по запросу sentry-mattermost и правда завалена топиками, где в большинстве случаев просят помочь.
      Но я не нашел рабочих решений и туториалов, в которых рассказано как быстро и просто мне реализовать получение евентов из сентри в маттермост без лишнего функционала, может подскажите рабочие решения?


      1. m1skam
        19.09.2023 13:04
        -1

        Что в вашем понимании "лишний функционал"? Я имел ввиду, что решений, подобно вашему, достаточно много, из первой страницы выдачи гугла:

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