Представляем новый плагин для Grafana — Statusmap panel

    У Grafana есть возможность показывать статус, у Grafana есть возможность показывать данные во времени. Однако, как это ни парадоксально, у Grafana до настоящего момента не было удобного способа показывать статус во времени!

    Мы представляем свой плагин — Statusmap panel. Он позволяет наглядно отобразить состояния набора объектов за выбранный промежуток времени. В качестве примера, демонстрирующего работу плагина, представим себе множество локаций, в которых для кого-то готовят кофе:


    Можно увидеть, как Никки экономит электроэнергию, Герри быстро пополняет запасы воды, кофемашина Валеры частенько барахлит, а на Бифросте Wi-Fi явно лучше, чем на лунной станции, где, похоже, с водой совсем туго.

    Выглядит интересно? Но начнём с того, как мы вообще к этому пришли.

    Зачем?


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

    Актуальные для нашего бизнеса примеры использования такой визуализации — это здоровье серверов или подов Kubernetes, результаты проверки HTTP-сервисов. Так в компании «Флант» и родился плагин к Grafana под названием Statusmap. Размышляя над великим множеством возможностей его применения и для других задач, мы быстро приняли на себя обязательство поделиться кодом с мировым сообществом. Но неужели никто до нас не решал эту задачу?

    Почему не готовое?


    Задача в действительности популярная, так что первопроходцами мы в ней не стали. Началось всё с того, что у нас было несколько дашбордов с крутыми плагинами Status Panel и Status Dot. Эти плагины позволяют отобразить текущее состояние набора объектов, например, хостов или подов… или кофемашин в разных частях света.





    Всё шло хорошо, пока нам не захотелось видеть статусы этих объектов во времени. Первым, самым простым решением было добавить обычный граф с галочкой stacked.



    По задумке Status Panel + stacked Graph позволили бы видеть состояние объектов «на сейчас» и развитие ситуации во времени. Однако stacked Graph не очень нагляден:

    • цветом отмечаются различные timeseries, а не значения, которые отображаются цветом для Status Dot или Status Panel. То есть цвета для двух графиков не одинаковые и это сбивает с толку;
    • если среди значений появляется null, то графики проваливаются.

    Попробовали приспособить стандартный Heatmap — не получилось: плагин работает с осью Y только на уровне значений и не умеет выводить там лейблы. Тогда мы попробовали следующие плагины для Grafana:

    • Carpet plot — группирует значения по дню и по выбранному фрагменту дня;
    • Discrete Panel — хороший плагин, но нам нужно дискретно показывать статусы во времени;
    • Status By Group Panel — хорошее улучшение к Status panel, позволяющее отображать множество статусов, однако всё ещё без нужных нам возможностей.

    По результатам всех проведённых исследований мы сформулировали следующие требования к плагину:

    • выделенная чёткая строка графика для каждого объекта;
    • имя объекта отображается по оси Y и задаётся в поле легенды;
    • по одному объекту может быть несколько статусов — в таких случаях самый значимый будет отображаться цветом, а остальные показываться в tooltip’е;
    • корзины (buckets) отображать шириной не менее заданной (5 px), т.к. в однопиксельные неудобно наводить мышкой;
    • ручное управление цветом — возможность задать цвет каждому числовому значению из дискретного набора.

    Позвольте теперь сделать небольшое отступление про графики Heatmap, Prometheus и дискретные статусы…

    Немного теории


    Классический heatmap — это 3-мерный график:

    • по оси X откладывается время,
    • по оси Y — возможные значения некоторой величины,
    • по оси Z — количество наблюдаемых значений в данный момент времени.

    Стандартный плагин Heatmap отображает ось Z цветом — например, от белого до красного или через градиент зелёный-жёлтый-красный. Это очень хорошо работает для непрерывных значений: времени отклика, длины очереди, количества запросов к серверу… В случае дискретных статусов для набора объектов нужно следующее: по оси Y отобразить имена объектов, которые мы мониторим, а по оси Z — показать для каждого объекта наблюдаемые в данный момент времени статусы… Но стойте! Что значит множество статусов объекта в момент времени? Попробую описать.

    Те, кто использует Prometheus с Grafana, знают про step или interval — настройку на закладке Query. Если там указать 1m, а данные вы собираете с интервалом в 5s, то при выполнении простого запроса метрики coffee_maker_status Prometheus вернёт каждое 12-ое значение, а 11 значений на графике уже никак не увидеть. Как улучшить ситуацию?

    Первым, что приходит в голову, — воспользоваться функциями агрегации — например, *_over_time(coffee_maker_status[1m]). Какую именно функцию взять? Время разобраться с тем, как представляется статус в метриках Prometheus. В большинстве случаев статус обозначается неким набором значений. Например, для coffee_maker_status могут быть такие значения статуса:

    • 0 — ok,
    • 1 — off,
    • 2 — no beans,
    • 3 — no water,
    • 4 — fail.

    Далее казалось бы всё просто: взять количество нулей, единиц, двоек и т.д. в течение одной минуты… и мы имеем отличные данные для отображения на графике! Но у Prometheus свой взгляд на это: coffee_maker_status[1m] — это range vector, а потому выражения вроде max_over_time(coffee_maker_status[1m]==2) или count_values_over_time(coffee_maker_status[1m], 3), которые очень бы подошли, невозможны.

    Всё отлично работает, если в метрике есть два значения: 0 (статус не наблюдался) и 1 (статус наблюдался), — а сам статус хранится в лейбле. Тогда можно составлять такие запросы: (max_over_time(coffee_maker_status{status="3"}[1m]) == 1) *3

    Что же делать с метрикой, у которой несколько значений? Заметка «Composing range vector functions in PromQL» дала идею превратить метрику с дискретными значениями в метрики с лейблами. Это можно сделать с помощью такого recording rule:

    - record: coffee_maker_status:discrete
      expr: |
        count_values("status", coffee_maker_status)

    Это правило трансформирует метрику coffee_maker_status так: если пришло значение 3, то Prometheus создаёт метрику coffee_maker_status:discrete{status="3"} со значением 1. И так — для каждого наблюдаемого значения.

    Обычно статусы определены заранее, поэтому можно составить набор запросов, чтобы не пропускать нужные значения. Легенда у всех запросов должна совпадать, чтобы можно было сгруппировать значения:



    Теперь, если в течение минуты кофемашина была выключена 30 секунд (статус off — 1), а остальное время работала (статус ok — 0), то у нас будет информация о выключении, т.к. плагин получит два значения с одной легендой за один момент во времени: 0 от query A и 1 от query B.

    Хорошо: мы придумали, как агрегировать данные о дискретных статусах и при этом не терять информацию. Осталось придумать, как объединять данные на основе легенды и отрисовывать их на панели.

    Плагин Statusmap


    К тому, что описано выше мы, конечно же, пришли не сразу, но когда всё это сложилось воедино, стало понятно, что по сути не хватает механизма отрисовки. Теперь такой механизм есть — Statusmap panel plugin, который умеет следующее:

    • значения в каждой точке времени группируются в корзины по совпадению текста легенд, указанных в Query;
    • каждому тексту легенды соответствует своя строка на графике и текст отображается как метка на оси Y, а пустые значения отображаются пробелом или как 0:

    • для любого значения можно задать точный цвет корзины:

    • если в корзину попало несколько значений, то цвет будет взят для того значения, которое определено выше на вкладке Colors, а при наведении на корзину отображаются все значения, которые попали в неё:

    • плагин умеет формировать interval для запроса к Prometheus, чтобы корзины не превращались в пиксельные линии.

    В итоге получается очень удобное представление статуса нескольких объектов. Причем можно посмотреть как текущий статус (это самые правые корзины), так и статус объекта во времени.

    Где взять?


    Исходный код Grafana Statusmap plugin распространяется под свободной лицензией MIT (по аналогии с другими плагинами для Grafana). На данный момент он доступен в нашем GitHub. И мы искренне надеемся, что в ближайшее время он попадёт и в репозиторий плагинов Grafana. ОБНОВЛЕНО (03/10/18): Плагин принят в официальный каталог Grafana.

    И напоследок — иллюстрация, как Statusmap помогает визуализировать данные со статусами подов из production-кластера Kubernetes:



    P.S.


    Читайте также в нашем блоге:

    Флант

    277,43

    Специалисты по DevOps и высоким нагрузкам в вебе

    Поделиться публикацией
    Комментарии 12
      +2
      Мне кажется, что в данном контексте слово «status» во множественном числе будет «status».
        +1
        Согласен с вами — спасибо, везде исправим!
        +3

        Спасибо за плагин! У меня сейчас статус DNS серверов показывается как stacked, думаю с этим плагином можно сделать покрасивше.

          +3

          Да! У нас тоже статусы многих разных вещей stacked bar'ами раньше показывались, и что мы только не делали, чтобы это хоть как-то наглядно выглядело, вот так и пришли к созданию этого плагина.

          +1
          Не совсем понятно чем не устроил Discrete Panel
            +6
            • нет группировки по совпадающим легендам — это основное
            • статусы отображаются непрерывно, а не группируются в корзины, в итоге можно получить пиксельные полоски — это правда на вкус и цвет
            • ну и мелочь, что текст для оси Y рисуется прямо на графике — выбивается из общей картины, когда discrete panel оказывается на dashboard-e.

            image

            0
            Плагин добавили-таки в официальный каталог Grafana! grafana.com/plugins/flant-statusmap-panel
              +1

              Очень удобный плагин. Но при попытке определить панель в png отваливается по таймауту. Баг?

                0

                Определить=отрендерить (т9)

                  0

                  Действительно, с плагином ошибка 500, а без него всё ок. Завёл issue: https://github.com/flant/grafana-statusmap/issues/10

                    0

                    Оказывается пропала одна строчка, из-за этого скрипт для phantomjs не хотел останавливаться.
                    https://github.com/flant/grafana-statusmap/pull/15


                    Можно обновиться из мастера. Когда будет версия 0.0.2 в репозитории Grafana, знает только daniellee, PRы там по месяцу могут висеть :(

                      0
                      Спасибо ))

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

                  Самое читаемое