oleggr / grafana-webhook-redirect

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

FastAPI boilerplate для получения вебхуков из Grafana в ICQ/Myteam

Цель данного шаблона - облегчить задачу отправки уведомлений в неподдерживаемые Grafana мессенджеры из коробки.

Поддерживаются как Grafana Alerts https://grafana.com/docs/grafana/latest/alerting/unified-alerting/contact-points/#webhook

Так и Legacy Grafana Alerts https://grafana.com/docs/grafana/latest/alerting/old-alerting/notifications/#webhook

Installing

git clone 
cd grafana-hook
pip install -r requirements.txt

Start

Все необходимые для работы параметры указываются через переменные окружения:

API_PREFIX - префикс для path методов FastAPI
TOKEN - токен для бота в ICQ/Myteam
GRAFANA_URL - доменное имя Grafana, будет использоваться в сообщениях
API_URL - URL бот API ICQ/Myteam
GF_LOGIN - логин для авторизации в Grafana
GF_PASSWORD - пароль от Grafana

GF_LOGIN и GF_PASSWORD используются для получения графиков через headless chrome
uvicorn main:app --host 0.0.0.0 --port 80 --loop=asyncio

--loop=asyncio - необходимо для запуска асинхронного бота с сессией, так как uvloop невозможно пропатчить

Examples

Из коробоки в репозитории уже лежит app.middleware.handler.event_handler.

async def event_handler(
        event: Union[OldEvent, NewEvent],
        chatId: str,
        token: Optional[str] = None
) -> Response:
    """
    Функция обработки Event от Grafana
    :param event: Event от Grafana
    :param chatId: ID чата в ICQ/Myteam
    :param token: токен бота (необязательный переметр)
    :return: fastapi.responses.Response
    """

    #  Подменяем токен бота если он был указан,
    #  в противном случае используем указанный в переменной окружения
    if token:
        notifier.token = token
    else:
        notifier.token = os.getenv('TOKEN')

    text = event.to_string()

    print(text)

    keyboard = InlineKeyboardMarkup()

    # Преобразуем эвент в текстовое сообщение
    if isinstance(event, OldEvent):

        keyboard.row(
            KeyboardButton(
                text=f'[URL] {event.ruleName}',
                url=event.ruleUrl
            )
        )
    else:

        keyboard.row(
            KeyboardButton(
                text=f'[URL] {event.externalURL}',
                url=event.externalURL
            )
        )

    if isinstance(event, OldEvent) and event.imageUrl:
        # Если Grafana отправляет в
        # Event ссылку на график - пытаемся его сохранить
        try:
            with tempfile.NamedTemporaryFile(
                    prefix='graphic.', suffix='.png') as upstream:
                async with aiohttp.ClientSession() as session:
                    resp = await session.get(event.imageUrl)

                    upstream.write(
                        await resp.read()
                    )

                await notifier.send_file(
                    chatId=chatId,
                    file_path=upstream.name,
                    caption=text,
                    inlineKeyboardMarkup=keyboard
                )
        except Exception as error:
            await log.exception(error)  # Обрабатываем ошибку
            # если скачать график не удалось

            await notifier.send_text(
                chatId=chatId,
                text=text,
                inlineKeyboardMarkup=keyboard
            )

    else:
        # Если imageUrl не указан - отправляем обычное сообщение
        await notifier.send_text(
            chatId=chatId,
            text=text,
            inlineKeyboardMarkup=keyboard
        )

    return Response()

Эта функция обрабатывает входящие Event от Grafana и просто пересылает их в ICQ/Myteam.

Если необходимо другая логика работы с Event или работа с другими мессенджарами - нужно переопределить эту функцию и расположить ее в app.event_handler. !ВАЖНО - функция должна уметь принимать такие же аргументы и возвращать класс Response

Настройки в Grafana

В Alerting -> Notifications channels при созданиее вебхука необходимо указать URL следующего вида:

http(s)://GRAFANA-HOOK-URL:PORT/API_PREFIX/{CHAT_ID}

или

http(s)://GRAFANA-HOOK-URL:PORT/{API_PREFIX}/{TOKEN/{CHAT_ID}

About


Languages

Language:Python 87.5%Language:Shell 6.0%Language:Dockerfile 3.6%Language:JavaScript 2.5%Language:Makefile 0.4%