Здравствуй, %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