-
Sy
chevron_right
Поддержка хранилища ClickHouse в сервере Zabbix 3.4
pubsub.slavino.sk / sysadmblog · Sunday, 15 November, 2020 - 08:00 edit · 11 minutes
Готовую заплатку для сервера Zabbix с реализацией поддержки хранения исторических данных в ClickHouse можно найти по ссылке zabbix3_4_12_server_storage_per_table.patch .
Ниже описаны внесённые заплаткой доработки и объяснение их логики.
У меня ушло некоторое время на изучение функций для работы со структурами данных в формате JSON. Чтобы не пришлось вспоминать их снова, опишу те из них, которыми я пользовался непосредственно в описываемой заплатке.
Функции Zabbix для формирования JSON
Заголовочный файл include/zbxjson.h, файл с реализацией функций - src/libs/zbxjson/json.czbx_json_init(json)
Создание JSON, в котором корневым элементом является словарь. Фактически, в пустой буфер будут добавлены фигурные скобки {} , текущий указатель будет указывать на закрывающую скобку, уровень вложенности увеличится с 0 до 1, а в статусе будет ZBX_JSON_EMPTY.zbx_json_initarray(json)
Работает аналогично zbx_json_init, но корневым элементом структуры JSON будет массив, а в буфер вместо фигурных скобок {} будут вставлены квадратные скобки [] .zbx_json_clean(json)
Очищает буфер от хранящейся в нём структуры JSON. Сама память при этом не освобождается.zbx_json_free(json)
Освобождает буфер, который был занят сформированной структурой JSON.zbx_json_addobject(json, name)
Вставляет в то место буфера, куда указывает текущий указатель:- запятую , , если текущий статус равен ZBX_JSON_COMMA,
- текст "name": , если аргумент name не равен NULL,
- пару фигурных скобок {} .
Весь текст, который ранее лежал в буфере после указателя, сдвигается так, что оказывается позади вставленного текста.
zbx_json_addarray(json, name)
Работает аналогично zbx_json_addobject, но вместо фигурных скобок вставляются квадратные [] .Вставляет в то место буфера, куда указывает текущий указатель:
- запятую , , если текущий статус равен ZBX_JSON_COMMA,
- текст "name": , если аргумент name не равен NULL,
- пару квадратных скобок [] .
Весь текст, который ранее лежал в буфере после указателя, сдвигается так, что оказывается позади вставленного текста.
zbx_json_addstring(json, name, string, type)
Вставляет в то место буфера, куда указывает текущий указатель:- запятую , , если текущий статус равен ZBX_JSON_COMMA,
- текст "name": , если аргумент name не равен NULL,
- строку string .
Текущий указатель передвигается на символ, следующий за последним вставленным, уровень вложенности не меняется, в статус записывается ZBX_JSON_COMMA.
Весь текст, который ранее лежал в буфере после указателя, сдвигается так, что оказывается позади вставленного текста.
zbx_json_adduint64(json, name, value)
Вставляет в то место буфера, куда указывает текущий указатель:- запятую , , если текущий статус равен ZBX_JSON_COMMA,
- текст "name": , если аргумент name не равен NULL,
- 64-битное беззнаковое число value.
Весь текст, который ранее лежал в буфере после указателя, сдвигается так, что оказывается позади вставленного текста.
zbx_json_addint64(json, name, value)
Вставляет в то место буфера, куда указывает текущий указатель:- запятую , , если текущий статус равен ZBX_JSON_COMMA,
- текст "name": , если аргумент name не равен NULL,
- 64-битное число value со знаком.
Весь текст, который ранее лежал в буфере после указателя, сдвигается так, что оказывается позади вставленного текста.
zbx_json_close(json)
Передвигает текущий указатель так, что пропускается закрывающая фигурная } или квадратная скобка ] .Уровень вложенности уменьшается на единицу, статус меняется на ZBX_JSON_COMMA.
Функции Zabbix для разбора JSON
zbx_json_open(buffer, json)
buffer - строка с завершающим нулём, содержащая текст JSON.json - структура с указателями на начало и конец фрагмента JSON в буфере buffer.
Проверяет, что текст в буфере buffer является правильным JSON, инициализирует структуру json. При ошибках возвращает FAIL, в случае успеха - SUCCEED.
zbx_json_next(json, p)
json - структура с указателями на начало и конец фрагмента JSON, являющегося массивом.p - указатель внутри фрагмента json, указывающий на начальный символ элемента массива или словаря.
Ищет следующий элемент массива или словаря и возвращает указатель на его начальный символ. Если указанный в p элемент был последним, возвращает NULL.
zbx_json_pair_by_name(json, name)
json - структура с указателями на начало и конец фрагмента JSON, являющегося словарём.name - имя ключа в словаре, значение которого нужно найти.
Возвращает указатель на первый символ значения или NULL, если указанного ключа нет в словаре.
zbx_json_brackets_open(p, json)
p - указатель на открывающую скобку, указывающую на начало фрагмента JSON, который нужно найти.json - структура с указателями на начало и конец фрагмента JSON, являющегося массивом или словарём.
Ищет в указанном фрагменте JSON открывающую скобку, затем находит парную ей закрывающую скобку и записывает указатели на начало и конец найденного фрагмента в структуру json.
При ошибках возвращает FAIL, при успешном завершении - SUCCEED.
zbx_json_brackets_by_name(json, name, json_out)
json - структура с указателями на начало и конец фрагмента JSON, являющегося словарём.name - имя ключа в словаре, значение которого нужно найти.
json_out - фрагмент JSON, являющийся значением ключа name.
Ищет в указанном фрагменте JSON указанный ключ, находит открывающую и закрывающую скобки, в структуру json_out записывает указатели на начало и конец найденного фрагмента.
При ошибках возвращает FAIL, при успешном завершении - SUCCEED.
zbx_json_value_by_name_dyn(json, name, string, string_alloc)
json - структура с указателями на начало и конец фрагмента JSON, являющегося словарём.name - имя ключа в словаре, значение которого нужно найти.
string - указатель на указатель на буфер, в который будет помещено найденное значение.
string_alloc - указатель на переменную с размером буфера.
Ищет в указанном фрагменте JSON, являющемся словарём, значение элемента с указанным ключом name. Найденное значение записывается в буфер. Если в буфере не было достаточно места для сохранения найденного значения, функция выделяет под буфер другой фрагмент памяти, обновляет указатель на буфер и его размер.
Новая функция zbx_json_adddbl
Немного опережая события, заранее добавим в код Zabbix дополнительную функцию zbx_json_adddbl, которая позже понадобится нам для формирования JSON с данными, вставляемыми в таблицу history с числами с плавающей запятой. Объявление функции добавим в файл include/zbxjson.h, а реализацию функции добавим в файл src/libs/zbxjson/json.c следующим образом:Index: zabbix-3.4.12-1+buster/include/zbxjson.h
===================================================================
--- zabbix-3.4.12-1+buster.orig/include/zbxjson.h
+++ zabbix-3.4.12-1+buster/include/zbxjson.h
@@ -160,6 +160,7 @@ void zbx_json_addarray(struct zbx_json *
void zbx_json_addstring(struct zbx_json *j, const char *name, const char *string, zbx_json_type_t type);
void zbx_json_adduint64(struct zbx_json *j, const char *name, zbx_uint64_t value);
void zbx_json_addint64(struct zbx_json *j, const char *name, zbx_int64_t value);
+void zbx_json_adddbl(struct zbx_json *j, const char *name, double value);
int zbx_json_close(struct zbx_json *j);
int zbx_json_open(const char *buffer, struct zbx_json_parse *jp);
Index: zabbix-3.4.12-1+buster/src/libs/zbxjson/json.c
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxjson/json.c
+++ zabbix-3.4.12-1+buster/src/libs/zbxjson/json.c
@@ -385,6 +385,14 @@ void zbx_json_addint64(struct zbx_json *
zbx_json_addstring(j, name, buffer, ZBX_JSON_TYPE_INT);
}
+void zbx_json_adddbl(struct zbx_json *j, const char *name, double value)
+{
+ char buffer[MAX_ID_LEN];
+
+ zbx_snprintf(buffer, sizeof(buffer), ZBX_FS_DBL, value);
+ zbx_json_addstring(j, name, buffer, ZBX_JSON_TYPE_INT);
+}
+
int zbx_json_close(struct zbx_json *j)
{
if (1 == j->level)
Доработка основы библиотеки zbxhistory
В файле src/libs/zbxhistory/history.c раскомментируем ранее добавленный нами комментарий с намёком на поддержку ClickHouse:Index: zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.cВ добавленном коде используется указатель на строку clickhouse_url, добавим его объявление:
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxhistory/history.c
+++ zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.c
@@ -62,8 +63,8 @@ int zbx_history_init(char **error)
{
if (elastic_url = zbx_strstartswith(opts[i], "elastic,"))
ret = zbx_history_elastic_init(&history_ifaces[i], i, elastic_url, error);
- /*else if (clickhouse_url = zbx_strstartswith(opts[i], "clickhouse,"))
- ret = zbx_history_clickhouse_init(&history_ifaces[i], i, clickhouse_url, error);*/
+ else if (clickhouse_url = zbx_strstartswith(opts[i], "clickhouse,"))
+ ret = zbx_history_clickhouse_init(&history_ifaces[i], i, clickhouse_url, error);
else
ret = zbx_history_sql_init(&history_ifaces[i], i, error);
Index: zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.cОбъявление функции zbx_history_clickhouse_init нужно добавить в заголовочный файл src/libs/zbxhistory/history.h:
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxhistory/history.c
+++ zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.c
@@ -50,6 +50,7 @@ int zbx_history_init(char **error)
{
int i, ret;
char *elastic_url;
+ char *clickhouse_url;
const char *opts[] = {
CONFIG_HISTORY_STORAGE,
CONFIG_HISTORY_STR_STORAGE,
Index: zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.h
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxhistory/history.h
+++ zabbix-3.4.12-1+buster/src/libs/zbxhistory/history.h
@@ -49,4 +49,7 @@ int zbx_history_sql_init(zbx_history_ifa
/* elastic hist */
int zbx_history_elastic_init(zbx_history_iface_t *hist, unsigned char value_type, const char *url, char **error);
+/* ClickHouse hist */
+int zbx_history_clickhouse_init(zbx_history_iface_t *hist, unsigned char value_type, const char *url, char **error);
+
#endif
Добавление файла history_clickhouse.c
Перед дальнейшими действиями скопируем файл src/libs/zbxhistory/history_elastic.c в файл src/libs/zbxhistory/history_clickhouse.c и заменим все упоминания Elasticsearch на ClickHouse, в том числе в отладочных сообщениях, комментариях и именах функций.Теперь нужно прописать новый файл history_clickhouse.c в Make-файлы src/libs/zbxhistory/Makefile.am и src/libs/zbxhistory/Makefile.in, чтобы они участвовали в процессе сборки:
Index: zabbix-3.4.12-1+buster/src/libs/zbxhistory/Makefile.amПолучилось два полностью аналогичных по сути модуля поддержки хранилищ с разными именами. Продолжим переделку нового модуля. Сначала пройдусь кратко по мелким изменениям.
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxhistory/Makefile.am
+++ zabbix-3.4.12-1+buster/src/libs/zbxhistory/Makefile.am
@@ -5,4 +5,5 @@ noinst_LIBRARIES = libzbxhistory.a
libzbxhistory_a_SOURCES = \
history.c history.h \
history_sql.c \
- history_elastic.c
+ history_elastic.c \
+ history_clickhouse.c
Index: zabbix-3.4.12-1+buster/src/libs/zbxhistory/Makefile.in
===================================================================
--- zabbix-3.4.12-1+buster.orig/src/libs/zbxhistory/Makefile.in
+++ zabbix-3.4.12-1+buster/src/libs/zbxhistory/Makefile.in
@@ -120,7 +120,8 @@ am__v_AR_1 =
libzbxhistory_a_AR = $(AR) $(ARFLAGS)
libzbxhistory_a_LIBADD =
am_libzbxhistory_a_OBJECTS = history.$(OBJEXT) history_sql.$(OBJEXT) \
- history_elastic.$(OBJEXT)
+ history_elastic.$(OBJEXT) \
+ history_clickhouse.$(OBJEXT)
libzbxhistory_a_OBJECTS = $(am_libzbxhistory_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -366,7 +367,8 @@ noinst_LIBRARIES = libzbxhistory.a
libzbxhistory_a_SOURCES = \
history.c history.h \
history_sql.c \
- history_elastic.c
+ history_elastic.c \
+ history_clickhouse.c
all: all-am
@@ -417,6 +419,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history_clickhouse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history_elastic.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/history_sql.Po@am__quote@
В функции clickhouse_writer_flush была удалена обработка сообщений об ошибках Elasticsearch при успешном коде ответа HTTP, т.к. ClickHouse о любых ошибках выполнения запросов всегда сообщает соответствующим кодом статуса HTTP:
@@ -402,19 +401,6 @@Было удалено макроопределение константы ZBX_IDX_JSON_ALLOCATE, т.к. в коде поддержки ClickHouse оно не использовалось.
zbx_vector_ptr_append(&retries, msg->easy_handle);
curl_multi_remove_handle(writer.handle, msg->easy_handle);
}
- else if (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **)&curl_page)
- && SUCCEED == clickhouse_is_error_present(&curl_page->page, &error))
- {
- zabbix_log(LOG_LEVEL_WARNING, "%s() %s: %s", __function_name,
- "cannot send data to ClickHouse", error);
- zbx_free(error);
-
- /* If the error is due to ClickHouse internal problems (for example an index */
- /* became read-only), we put the handle in a retry list and */
- /* remove it from the current execution loop */
- zbx_vector_ptr_append(&retries, msg->easy_handle);
- curl_multi_remove_handle(writer.handle, msg->easy_handle);
- }
}
previous = running;
В структуре zbx_clickhouse_data_t было удалено поле post_url, т.к. оказалось достаточно уже имеющегося в структуре поля base_url.
Были удалены функции history_value2str и clickhouse_is_error_present (бывшая elastic_is_error_present), т.к. они больше не используются.
Что касается доработок по существу, то они затрагивают функции clickhouse_get_values и clickhouse_add_values. Приведу обе функции полностью в окончательном виде:
/************************************************************************************При доработке функции clickhouse_get_values массив строковых констант value_type_str был заменён на массив строковых констант value_type_table:
* *
* Function: clickhouse_get_values *
* *
* Purpose: gets item history data from history storage *
* *
* Parameters: hist - [IN] the history storage interface *
* itemid - [IN] the itemid *
* start - [IN] the period start timestamp *
* count - [IN] the number of values to read *
* end - [IN] the period end timestamp *
* values - [OUT] the item history data values *
* *
* Return value: SUCCEED - the history data were read successfully *
* FAIL - otherwise *
* *
* Comments: This function reads <count> values from [<start>,<end>] interval or *
* all values from the specified interval if count is zero. *
* *
************************************************************************************/
static int clickhouse_get_values(zbx_history_iface_t *hist, zbx_uint64_t itemid, int start, int count, int end,
zbx_vector_history_record_t *values)
{
const char *__function_name = "clickhouse_get_values";
zbx_clickhouse_data_t *data = hist->data;
size_t sql_alloc = 0, sql_offset;
int ret = SUCCEED;
CURLcode err;
struct curl_slist *curl_headers = NULL;
char *sql = NULL, errbuf[CURL_ERROR_SIZE];
const char *p = NULL;
struct zbx_json_parse jp, jp_sub, jp_data, jp_item;
zbx_history_record_t hr;
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
if (NULL == (data->handle = curl_easy_init()))
{
zabbix_log(LOG_LEVEL_ERR, "cannot initialize cURL session");
return FAIL;
}
if (ITEM_VALUE_TYPE_LOG == hist->value_type)
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
"SELECT clock, ns, value, timestamp, source, severity, logeventid"
" FROM %s"
" WHERE itemid=" ZBX_FS_UI64,
value_type_table[hist->value_type], itemid);
else
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset,
"SELECT clock, ns, value"
" FROM %s"
" WHERE itemid=" ZBX_FS_UI64,
value_type_table[hist->value_type], itemid);
if (0 < start)
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " AND clock>%d", start);
if (0 < end)
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " AND clock<=%d", end);
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " ORDER BY clock DESC");
if (0 < count)
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " LIMIT %d", count);
zbx_snprintf_alloc(&sql, &sql_alloc, &sql_offset, " FORMAT JSON");
curl_headers = curl_slist_append(curl_headers, "Content-Type: application/json");
curl_easy_setopt(data->handle, CURLOPT_URL, data->base_url);
curl_easy_setopt(data->handle, CURLOPT_POSTFIELDS, sql);
curl_easy_setopt(data->handle, CURLOPT_WRITEFUNCTION, curl_write_cb);
curl_easy_setopt(data->handle, CURLOPT_WRITEDATA, &page_r);
curl_easy_setopt(data->handle, CURLOPT_HTTPHEADER, curl_headers);
curl_easy_setopt(data->handle, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(data->handle, CURLOPT_ERRORBUFFER, errbuf);
zabbix_log(LOG_LEVEL_DEBUG, "sending query to %s; post data: %s", data->base_url, sql);
page_r.offset = 0;
*errbuf = '\0';
if (CURLE_OK != (err = curl_easy_perform(data->handle)))
{
clickhouse_log_error(data->handle, err, errbuf);
ret = FAIL;
goto out;
}
zabbix_log(LOG_LEVEL_DEBUG, "received from ClickHouse: %s", page_r.data);
zbx_json_open(page_r.data, &jp);
zbx_json_brackets_open(jp.start, &jp_sub);
zbx_json_brackets_by_name(&jp_sub, "data", &jp_data);
while (NULL != (p = zbx_json_next(&jp_data, p)))
{
if (SUCCEED != zbx_json_brackets_open(p, &jp_item))
continue;
if (SUCCEED != history_parse_value(&jp_item, hist->value_type, &hr))
continue;
zbx_vector_history_record_append_ptr(values, &hr);
}
out:
clickhouse_close(hist);
curl_slist_free_all(curl_headers);
zbx_free(sql);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
return ret;
}
/************************************************************************************
* *
* Function: clickhouse_add_values *
* *
* Purpose: sends history data to the storage *
* *
* Parameters: hist - [IN] the history storage interface *
* history - [IN] the history data vector (may have mixed value types) *
* *
************************************************************************************/
static int clickhouse_add_values(zbx_history_iface_t *hist, const zbx_vector_ptr_t *history)
{
const char *__function_name = "clickhouse_add_values";
zbx_clickhouse_data_t *data = hist->data;
int i, num = 0;
ZBX_DC_HISTORY *h;
struct zbx_json json;
size_t buf_offset = 0;
zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
if (ITEM_VALUE_TYPE_LOG == hist->value_type)
zbx_snprintf_alloc(&data->buf, &data->buf_alloc, &buf_offset,
"INSERT INTO %s(itemid, value, timestamp, source, severity, logeventid, clock, ns)"
" FORMAT JSONEachRow\n", value_type_table[hist->value_type]);
else
zbx_snprintf_alloc(&data->buf, &data->buf_alloc, &buf_offset,
"INSERT INTO %s(itemid, value, clock, ns) FORMAT JSONEachRow\n",
value_type_table[hist->value_type]);
for (i = 0; i < history->values_num; i++)
{
h = (ZBX_DC_HISTORY *)history->values[i];
if (hist->value_type != h->value_type)
continue;
zbx_json_init(&json, ZBX_JSON_ALLOCATE);
zbx_json_adduint64(&json, "itemid", h->itemid);
switch (h->value_type)
{
case ITEM_VALUE_TYPE_STR:
case ITEM_VALUE_TYPE_TEXT:
zbx_json_addstring(&json, "value", h->value.str, ZBX_JSON_TYPE_STRING);
break;
case ITEM_VALUE_TYPE_LOG:
zbx_json_addstring(&json, "value", h->value.log->value, ZBX_JSON_TYPE_STRING);
break;
case ITEM_VALUE_TYPE_FLOAT:
zbx_json_adddbl(&json, "value", h->value.dbl);
break;
case ITEM_VALUE_TYPE_UINT64:
zbx_json_adduint64(&json, "value", h->value.ui64);
break;
}
if (ITEM_VALUE_TYPE_LOG == h->value_type)
{
const zbx_log_value_t *log;
log = h->value.log;
zbx_json_adduint64(&json, "timestamp", log->timestamp);
zbx_json_addstring(&json, "source", ZBX_NULL2EMPTY_STR(log->source), ZBX_JSON_TYPE_STRING);
zbx_json_adduint64(&json, "severity", log->severity);
zbx_json_adduint64(&json, "logeventid", log->logeventid);
}
zbx_json_adduint64(&json, "clock", h->ts.sec);
zbx_json_adduint64(&json, "ns", h->ts.ns);
zbx_json_close(&json);
zbx_snprintf_alloc(&data->buf, &data->buf_alloc, &buf_offset, "%s\n", json.buffer);
zbx_json_free(&json);
num++;
}
if (num > 0)
clickhouse_writer_add_iface(hist);
zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
return num;
}
-const char *value_type_str[] = {"dbl", "str", "log", "uint", "text"};Из всех сделанных изменений отдельно остановлюсь на исправлении одной из ошибок, которая перекочевала в файл history_clickhouse.c из файла history_elastic.c. Не могу скзать, является ли это ошибкой в исходном файле, но в коде поддержки ClickHouse эта проблема проявлялась следующим образом: в журнале сервера Zabbix при попытках вставки новых данных в таблицы истории в файле /var/log/zabbix/zabbix_server.log появлялись ошибки "400 Bad Request", хотя на первый взгляд данные в таблицы всё-таки записывались.
+const char *value_type_table[] = {"history", "history_str", "history_log", "history_uint", "history_text"};
Оказалось, что часть запросов к ClickHouse были попросту пустыми POST-запросами. Более пристальное изучение причин проблемы позволило обнаружить ошибку: при формировании запроса к ClickHouse на вставку данных иногда, при попытке добавить в него очередное значение, данные в буфере попросту очищались. Получившийся пустой запрос и выполнялся, из-за чего ClickHouse периодически сообщал об ошибках, а графики в веб-интерфейсе прерывались.
В функции добавки значений использовался уже распределённый ранее буфер hist->data->buf, но при каждом вызове этой функции считалось, что его размер buf_alloc равен нулю. Вот как это выглядит в исходном модуле history_elastic.c:
static int elastic_add_values(zbx_history_iface_t *hist, const zbx_vector_ptr_t *history)Чтобы устранить ошибку, я решил вынести переменную с размером буфера из тела функции в структуру, содержащую указатель на буфер:
{
const char *__function_name = "elastic_add_values";
zbx_elastic_data_t *data = hist->data;
int i, num = 0;
ZBX_DC_HISTORY *h;
struct zbx_json json_idx, json;
size_t buf_alloc = 0, buf_offset = 0;
typedef structПосле этой доработки сервер Zabbix, наконец, начал исправно писать данные в ClickHouse.
{
char *base_url;
char *buf;
+ size_t buf_alloc;
CURL *handle;
}
zbx_clickhouse_data_t;
Značky: #3.4, #buster, #debian, #zabbix, #Linux, #linux, #clickhouse