Здравствуй, %habraUser%
В этой статье пойдет речь о том, как расширять систему сбора статистики collectd путем добавления новых биндингов на python.
Эта статья является дополнением этой статьи
Нужно собирать данные с помощью collectd с модуля ustats для nginx. Нужно собирать HTTP 499, HTTP 500, HTTP 503 и TCP ошибки и выводить их на одном графике.
После изучения способов сбора статистики collectd, стало ясно, что собирать данные следующими способами:
Решил написать свой плагин на python чтобы детальнее разобраться в работе самого collectd
Алгоритм работы плагина следующий
Любой модуль для collectd должен содержать в себе
Подгрузим также нужные нам модули
В переменной url будем хранить ссылку, где расположены данные ustats в json формате, которую будем получать из конфига collectd.
Получаем данные с ustats
Забираем данные из конфига:
Далее, плагин у нас будет «читателем», соотвественно, нужно будет разобратся с функцией dispatch(), которая будет класть данные в collectd.
dispatch([type][, values][, plugin_instance][, type_instance][, plugin][, host][, time][, interval]) -> None.
type — тип данных
values — Актуальные значения, которые отправляются в collectd. Типы данных описаны в types.db
plugin_instance — инстанция плагина
type_instance — инстанция типа
plugin — имя плагина, по дефолту python
interval — Промежуток времени в секундах, между первой и второй отправкой одного и того же типа данных. Должно быть положительным целым числом. Если число отрицательное, то interval принимает значение по умолчанию(10 секунд)
Функция для отправки данных в collectd
collectd хранит данные по такой схеме:
Тут у нас:
plugin_instance = upstream
type = backend
type_instance = ошибки
На выходе мы получим примерно следующее:
host/plugin-upstream/backend-tcperror.rrd
Теперь основная функция, которая будет выполнятся collectd в цикле
После регестрируем функцию читателя и конфигурирующую функцию
Плагин готов, но мы использовали типы, которые не известны collectd, добавляем в my_types.db
описываем плагин в collectd.conf
Графики получаются такого вида

Полный текст скрипта на GitHub
Надеюсь, что статья поможет кому-нибудь в расширении сбора статистики collectd
В этой статье пойдет речь о том, как расширять систему сбора статистики collectd путем добавления новых биндингов на python.
Эта статья является дополнением этой статьи
Постановка задачи
Нужно собирать данные с помощью collectd с модуля ustats для nginx. Нужно собирать HTTP 499, HTTP 500, HTTP 503 и TCP ошибки и выводить их на одном графике.
Решение задачи
После изучения способов сбора статистики collectd, стало ясно, что собирать данные следующими способами:
- curl-json
- exec плагин
- python/perl/java плагин
Решил написать свой плагин на python чтобы детальнее разобраться в работе самого collectd
Алгоритм работы плагина следующий
- Забрать данные
- Распарсить их
- Положить в collectd.
Забираем данные:
Любой модуль для collectd должен содержать в себе
import collectdПодгрузим также нужные нам модули
import json, urllib2В переменной url будем хранить ссылку, где расположены данные ustats в json формате, которую будем получать из конфига collectd.
url = NoneПолучаем данные с ustats
def fetch_data(url): response = urllib2.urlopen(urllib2.Request(url)) data = json.loads(response.read()) return data
Забираем данные из конфига:
def configure_callback(conf): global url for c in conf.children: if c.key == 'UstatsURL': url = c.values[0] elif c.key == 'Verbose': VERBOSE_LOGGING = bool(c.values[0]) else: collectd.warning ('ustats_info plugin: Unknown config key: %s.' % c.key) log_verbose('Configured with url=%s' % (url))
Далее, плагин у нас будет «читателем», соотвественно, нужно будет разобратся с функцией dispatch(), которая будет класть данные в collectd.
dispatch([type][, values][, plugin_instance][, type_instance][, plugin][, host][, time][, interval]) -> None.
type — тип данных
values — Актуальные значения, которые отправляются в collectd. Типы данных описаны в types.db
plugin_instance — инстанция плагина
type_instance — инстанция типа
plugin — имя плагина, по дефолту python
interval — Промежуток времени в секундах, между первой и второй отправкой одного и того же типа данных. Должно быть положительным целым числом. Если число отрицательное, то interval принимает значение по умолчанию(10 секунд)
Функция для отправки данных в collectd
def dispatch_value(plugin_instance, info, key, type, type_instance=None): if not type_instance: type_instance = key value = int(info) log_verbose('Sending value: %s=%s' % (type_instance, value)) val = collectd.Values(plugin='ustats_info') val.plugin_instance = plugin_instance val.type = type val.type_instance = type_instance val.values = [value] val.dispatch()
collectd хранит данные по такой схеме:
host "/" plugin ["-" plugin instance] "/" type ["-" type instance]Тут у нас:
plugin_instance = upstream
type = backend
type_instance = ошибки
На выходе мы получим примерно следующее:
host/plugin-upstream/backend-tcperror.rrd
Теперь основная функция, которая будет выполнятся collectd в цикле
def read_callback(): global old_data log_verbose('Read callback called') data = fetch_data(url) last_backend = None if not data: collectd.error('ustats plugin: No data received') return if old_data == None: old_data = data upstreams = [] for key in data.keys(): upstreams.append(key) for upstream in upstreams: for index in range(len(data[upstream])): if data[upstream][index] and data[upstream][index] !=1 and data[upstream][index][0] != last_backend: dispatch_value(upstream, getValue(data[upstream][index][4], old_data[upstream][index][4]), 'http_499_errors', data[upstream][index][0].partition(":")[0]) dispatch_value(upstream, getValue(data[upstream][index][5], old_data[upstream][index][5]), 'http_500_errors', data[upstream][index][0].partition(":")[0]) dispatch_value(upstream, getValue(data[upstream][index][6], old_data[upstream][index][6]), 'http_503_errors', data[upstream][index][0].partition(":")[0]) dispatch_value(upstream, getValue(data[upstream][index][7], old_data[upstream][index][7]), 'tcp_errors', data[upstream][index][0].partition(":")[0]) dispatch_value(upstream, getValue(data[upstream][index][13], old_data[upstream][index][13]), 'total_errors', data[upstream][index][0].partition(":")[0]) last_backend = data[upstream][index][0] old_data = data
После регестрируем функцию читателя и конфигурирующую функцию
collectd.register_config(configure_callback) collectd.register_read(read_callback)
Плагин готов, но мы использовали типы, которые не известны collectd, добавляем в my_types.db
backend value:GAUGE:0:65535описываем плагин в collectd.conf
<Plugin python > ModulePath "/usr/lib/collectd/plugins/python" # Пусть до папки, где лежит модуль Import "ustats_info" # Импортируем модуль <Module ustats_info> UstatsURL "http://localhost/ustats?json" Verbose true </Module> </Plugin>
Заключение
Графики получаются такого вида

Полный текст скрипта на GitHub
Надеюсь, что статья поможет кому-нибудь в расширении сбора статистики collectd
