Легко разбираемый вывод из rrdtool
Я работаю с большой группой RRD-файлов, где мне приходится довольно часто запрашивать данные - и, в основном, читать все данные и передавать их.
В настоящее время я использую rrdtool fetch <filename> CF --start XXX --end YYY
, но так как он возвращает данные только для одного CF за раз, я сначала должен сделать отдельный запрос, чтобы найти CF (= run и parse rrdtool info <filename>
), а затем запустить rrdtool fetch
за каждый найденный CF. Тем не менее, выходные данные тривиальны для анализа.
Альтернативно, есть rrdtool xport DEF:XX=<filename>:RRA:CF ... XPORT:XX:XX ...
с несколькими "наборами" последних команд для каждой вещи, которую я хочу. С другой стороны, это может дать мне все данные за один раз, но мне все еще нужно иметь довольно хорошее представление о том, какие данные я хочу заблаговременно. Кроме того, он только выплевывает XML (всегда трудно разобрать).
У меня такое чувство, что я упускаю что-то очень очевидное, так как просто не может быть такой большой проблемы, чтобы получить список меток времени → чисел из файла... Любые подсказки?
4 ответа
Несмотря на наличие патчей для добавления JSON-поддержки, в настоящее время нет способа обойти это:
- Разбор как минимум двух разных форматов вывода (
rrdtool info
ASCII, а затем либо XML изrrdtool xport
или табличные данные изrrdtool fetch
). - Выгрузка всего содержимого файла в XML через
rrdtool dump
а затем повторно реализовать довольно многоlibrrd
внутренние органы.
Я написал парсер, который превращает вывод rrdtool info /tmp/pb_1_amp.rrd
во вложенный массив. Так из:
filename = "/tmp/pb_1_amp.rrd"
rrd_version = "0003"
step = 1800
last_update = 1372685403
header_size = 1208
ds[amp].index = 0
ds[amp].type = "GAUGE"
ds[amp].minimal_heartbeat = 3200
ds[amp].min = 0.0000000000e+00
ds[amp].max = 1.0000000000e+02
ds[amp].last_ds = "5.6"
ds[amp].value = 1.6800000000e+01
ds[amp].unknown_sec = 0
rra[0].cf = "AVERAGE"
rra[0].rows = 576
rra[0].cur_row = 385
rra[0].pdp_per_row = 1
rra[0].xff = 5.0000000000e-01
rra[0].cdp_prep[0].value = NaN
rra[0].cdp_prep[0].unknown_datapoints = 0
rra[1].cf = "AVERAGE"
rra[1].rows = 672
rra[1].cur_row = 159
rra[1].pdp_per_row = 6
rra[1].xff = 5.0000000000e-01
rra[1].cdp_prep[0].value = 1.6999833333e+01
rra[1].cdp_prep[0].unknown_datapoints = 0
rra[2].cf = "AVERAGE"
rra[2].rows = 732
rra[2].cur_row = 639
rra[2].pdp_per_row = 24
rra[2].xff = 5.0000000000e-01
rra[2].cdp_prep[0].value = 1.6999833333e+01
rra[2].cdp_prep[0].unknown_datapoints = 0
rra[3].cf = "AVERAGE"
rra[3].rows = 1460
rra[3].cur_row = 593
rra[3].pdp_per_row = 144
rra[3].xff = 5.0000000000e-01
rra[3].cdp_prep[0].value = 6.6083527778e+02
rra[3].cdp_prep[0].unknown_datapoints = 0
чтобы:
Array
(
[filename] => /tmp/pb_1_amp.rrd
[rrd_version] => 0003
[step] => 1800
[last_update] => 1372685403
[header_size] => 1208
[ds] => Array
(
[amp] => Array
(
[index] => 0
[type] => GAUGE
[minimal_heartbeat] => 3200
[min] => 0.0000000000e+00
[max] => 1.0000000000e+02
[last_ds] => 5.6
[value] => 1.6800000000e+01
[unknown_sec] => 0
)
)
[rra] => Array
(
[0] => Array
(
[cf] => AVERAGE
[rows] => 576
[cur_row] => 385
[pdp_per_row] => 1
[xff] => 5.0000000000e-01
[cdp_prep] => Array
(
[0] => Array
(
[value] => NaN
[unknown_datapoints] => 0
)
)
)
[1] => Array
(
[cf] => AVERAGE
[rows] => 672
[cur_row] => 159
[pdp_per_row] => 6
[xff] => 5.0000000000e-01
[cdp_prep] => Array
(
[0] => Array
(
[value] => 1.6999833333e+01
[unknown_datapoints] => 0
)
)
)
[2] => Array
(
[cf] => AVERAGE
[rows] => 732
[cur_row] => 639
[pdp_per_row] => 24
[xff] => 5.0000000000e-01
[cdp_prep] => Array
(
[0] => Array
(
[value] => 1.6999833333e+01
[unknown_datapoints] => 0
)
)
)
[3] => Array
(
[cf] => AVERAGE
[rows] => 1460
[cur_row] => 593
[pdp_per_row] => 144
[xff] => 5.0000000000e-01
[cdp_prep] => Array
(
[0] => Array
(
[value] => 6.6083527778e+02
[unknown_datapoints] => 0
)
)
)
)
)
Это на PHP, но его должно быть легко перенести на любой другой язык. Вот код:
$store = array();
foreach ($lines as $line) {
list($raw_key, $raw_val) = explode(' = ', $line);
$keys = preg_split('/[\.\[\]]/', $raw_key, -1, PREG_SPLIT_NO_EMPTY);
$key_count = count($keys);
$pointer = &$store;
foreach ($keys as $key_num => $key) {
if (!array_key_exists($key, $pointer)) {
$pointer[$key] = array();
}
$pointer = &$pointer[$key];
if ($key_num+1 === $key_count) {
$pointer = trim($raw_val, '"');
}
}
}
Предполагается, что rrdtool info
вывод делится на новую строку (\n
) и найден в $lines
, Надеюсь это поможет.
Я собрал этот инструмент, чтобы сделать это (если кто-то окажется здесь, как я)
Если вы хотите "оглавление", используйте rrdtool info
, если вы хотите весь контент, используйте rrdtool dump
,
НО... зачем тебе это?
ура Тоби