Приручение py-rrdtool

    Как говорится в одной древней мудрости: можно вечно наблюдать три вещи: как горит огонь, как течёт вода и как рисует графики rrdtool. Этот пост как раз о последнем.
    И так, что же такое rrdtool? rddtool — замечательная утилита, которая позволяет управлять данными, хранимыми в формать rrd (round-robin database). Данный формат примечателен тем, что изначально предназначен для хранения периодичной информации, причём так, что размер самой БД получается фиксированным (довольно небольшим) независимо от количества данных. При этом сохраняется возможность получать отчёты за продолжительные отрезки времени с произвольной точностью. Наибольшее распространение данная система нашла в системах мониторинга, где, как говорится, лучше один раз увидеть картинку, чем 7 раз прочитать логи. В конце статьи Вы сможете получить нечто, похожее на

    пример




    Для этого потребуется: python, rrdtool, py-rrdtool.
    После установки необходимых компонент получим готовые python-биндинги к rrdtool, с которыми можно дальше продолжать фантазировать. Конечно, количество возможностей rrdtool может поначалу отпугнуть, но я попробую рассмотреть несколько базовых действий + приведу немного собственного кода, который можно прямо запускать и наслаждаться.

    Говорят, что настоящие гики рисуют графики всего, чего только можно, вплоть до ежедневного количества прогулок их собаки. Для примера я рассматриваю два типа хранимой-анализируемой информации:

    1. информация, автоматически подсчитываемая аппроксимацией производной входных значений (например скорость на сетевом интерфейсе по значениям количества переданных байт)
    2. простая информация, которая заносится и хранится в виде отдельных, независимых значений (температура hdd, количество подписчиков ленты и т. д)

    Работа с rrd, как и с любой другой БД, начинается с определения структуры хранимых данных.
    Из python это выглядит приблизительно следующим образом: первым делом импортируем необходимый модуль и указываем имя файла БД:

    from rrdtool import *
    fname = 'database.rrd'
    rrd = RoundRobinDatabase(fname)
    далее, собственно, создаём БД, задавая структуру.


    rrd.create(
       # БД будет содержать два независимых источника данных (`rrdtool.DataSource`),
       # названных 'in' и 'out', типа DeriveDST — производная. Тут же задаются предельные
       # значения этих показателей:
       DataSource(«in», type=DeriveDST, heartbeat=600, min=0, max=12500000),
       DataSource(«out», type=DeriveDST, heartbeat=600, min=0, max=12500000),
       # описываем какие отчёты хотим хранить в БД.
       # последние 48 часов, каждые 5 мин
       RoundRobinArchive(cf=AverageCF, xff=0.5, steps=1, rows=576),
       # последние 2 недели, среднее зн. за 30
       RoundRobinArchive(cf=AverageCF, xff=0.5, steps=6, rows=672),
       # последние 2 месяца, средне за каждые 2 часа
       RoundRobinArchive(cf=AverageCF, xff=0.5, steps=24, rows=732),
       # последние 2 года, среднее за 12 часов
       RoundRobinArchive(cf=AverageCF, xff=0.5, steps=144, rows=1460),
       # шаг 300с — данные, хранимые в БД будут привязаны к «сетке», шагом в пять минут
       step=300
       )


    Пример 2 будет отличаться лишь строками с DataSource:

    DataSource(«value», type=GaugeDST, heartbeat=600, min=_min, max=_max)

    Теперь у нас есть БД, в которую с периодичностью 5 минут нужно вносить данные из двух источников — in и out.

    Для этого используется метод rrd.update(), который в качестве аргумента принимает значение (класса rrd.Val) и необязательный шаблон, необходимый для того, чтобы задавать данные в порядке отличном от умолчания.

    Например:


    values=(323132312, 128539593)
    template = («in», «out»)
    rrd.update(Val(*values), template=template)
    Это действие логично оформить в виде отдельного скрипта и запускать кроном с пятиминутной периодичностью для этого примера.

    Следующий шаг — собственно создание самой картинки c информацией за период period (day, week, month, year) из БД в файле fname


    graph = RoundRobinGraph('eth0-%s.png' % (period))
      

    graph.graph(
      
    Def(«in», fname, data_source=«in», cf=AverageCF),
      

    Def(«out», fname, data_source=«out», cf=AverageCF),
      

    Cdef(«out_neg», «out,-1,*»),
      
    AREA(«in», rrggbb=«32CD32», legend=«Incoming»),
      

    LINE1(«in», rrggbb=«336600»),
      
    GPRINT(«in», cf=MaxCF, format=r" Max\: %5.1lf %S"),
      

    GPRINT(«in», cf=AverageCF, format=r" Avg\: %5.1lf %S"),
      

    GPRINT(«in», cf=LastCF, format=r" Current\: %5.1lf %Sbytes/sec\n"),
      

    AREA(«out_neg», rrggbb=«4169E1», legend=«Outgoing»),
      

    LINE1(«out_neg», rrggbb=«0033CC»),
      
    GPRINT(«out», cf=MaxCF, format=r" Max\: %5.1lf %S"),
      

    GPRINT(«out», cf=AverageCF, format=r" Avg\: %5.1lf %S"),
      

    GPRINT(«out», cf=LastCF, format=r" Current\: %5.1lf %Sbytes/sec\n"),
      

    HRULE(«0», rrggbb=«000000»),
      

    vertical_label=«bytes/sec»,
      

    lower_limit=0,
      
    start="-1%s" % (period,),
      

    title=title,
      
    width=600,
      
    height=80,
      

    lazy=None,
      
    )
      

    В двух словах — здесь задаются данные из базы, которые необходимо отобразить и детали оформления, как то: линии, залитые участки, их цвета и пр.

    В результате работы этого куска можем получить что-то, напоминающее

    my_example

    или для примера 2 — график количества подписчиков на ленту из google reader:

    subscribers_example

    Я попытался оформить данные действия в более комфортную для использования (хотя, похоже, хреновом для расширения) библиотечку, которая включает в себя несколько готовых счётчико-рисовалок (для трафика, температуры hdd, количества клиентов на wifi интерфейсе, кол-во подписчиков) и пригодный для расширения простейший класс GaugeRRD, при помощи которого можно самостоятельно создавать свои классы для работы с py-rrdtool.

    Примеры использования можно найти на http://undefined.org.ua/static/rrdtool/src.
    Мой пример работы скриптов, оформленный в “аналитический центр” лежит на http://xa4a.org.ua/rrdtool.

    В заключение хочу отметить, что целью статьи было показать возможность использования такого инструмента, как rrdtool, для анализа нетривиальных данных, или в своих python-приложений. Если же Вам необходим инструмент мониторинга системы, который готов к работе из коробки, — существует уже множество готовых проектов, например: munin, mrtg, cacti и другие.


    Оригинал статьи находится в личном блоге по адресу: http://undefined.org.ua/blog/2008/08/05/py-rrdtool/
    Метки:
    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 12
    • +1
      А я недавно развлекался рисованием графиков через pycairo :) А за статью спасибо, полезно.
      • 0
        Кстати да. На нём ведь целый пакет мониторинга - graphite. (на который я смотрю с сильной надеждой и любопытством, поскольку мой предыдущий опыт с RRD был провальным).
      • 0
        До таких красивых штуковин скорее всего дело не дойдёт. Обычно получается как раз сине-зелёное УГ со стрёмными рамками. На которое надо положить немало сил только затем, чтобы после показа начальству оно сказало - хотим вот это другим шрифтом, а вот это - другим графиком. После чего все труды выбрасываются и изобретается велосипед )=
        • 0
          А почему копипаст, а не анонс или ссылка?
          • +1
            Чтобы Вам было удобнее
          • 0
            Здорово, что рассказали про rrdtool! Замечательная утилита! Используем ее в разрабатываемой OSS-системе, только при помощи perl. :)
            • 0
              А чем rrdtool лучше mrtg?
              • 0
                утилита rrdtool появилась, как развитие mrtg
                • 0
                  интервал записи данных в мртг фиксированный, насколько я помню (минута?)
                  в ррд базу можно каждую секунду
                • 0
                  по сабжу: очень жаль, что в py-rrdtool нет аналога rrdfetch,а только create/update/graph. Это бы позволило использовать rra архив, как db backend для round-robin данных. Думаю, что для своих целей добавлю еще один метод в класс RoundRobinDatabase. При беглом взгляде это кажется не сильно трудным... Пока у меня workaround решение с запуском внешнего "rrdtool fetch"
                  • 0
                    In [1]: from rrdtool import fetch

                    In [2]: fetch
                    Out[2]: <built-in function fetch>

                    похоже есть
                  • 0
                    Опечатка в строке
                    «LINE1(»in", rrggbb=«336600»),"

                    должно быть «out»

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