@cryptotaxi247 / netdata-1 / commits / d2daa19bf

JSON internal API, IEEE754 base64/hex streaming, weights endpoint optimization (#14493)

* first work on standardizing json formatting * renamed old grouping to time_grouping and added group_by * add dummy functions to enable compilation * buffer json api work * jsonwrap opening with buffer_json_X() functions * cleanup * storage for quotes * optimize buffer printing for both numbers and strings * removed ; from define * contexts json generation using the new json functions * fix buffer overflow at unit test * weights endpoint using new json api * fixes to weights endpoint * check buffer overflow on all buffer functions * do synchronous queries for weights * buffer_flush() now resets json state too * content type typedef * print double values that are above the max 64-bit value * str2ndd() can now parse values above UINT64_MAX * faster number parsing by avoiding double calculations as much as possible * faster number parsing * faster hex parsing * accurate printing and parsing of double values, even for very large numbers that cannot fit in 64bit integers * full printing and parsing without using library functions - and related unit tests * added IEEE754 streaming capability to enable streaming of double values in hex * streaming and replication to transfer all values in hex * use our own str2ndd for set2 * remove subnormal check from ieee * base64 encoding for numbers, instead of hex * when increasing double precision, also make sure the fractional number printed is aligned to the wanted precision * str2ndd_encoded() parses all encoding formats, including integers * prevent uninitialized use * /api/v1/info using the new json API * Fix error when compiling with --disable-ml * Remove redundant 'buffer_unittest' declaration * Fix formatting * Fix formatting * Fix formatting * fix buffer unit test * apps.plugin using the new JSON API * make sure the metrics registry does not accept negative timestamps * do not allow pages with negative timestamps to be loaded from db files; do not accept pages with negative timestamps in the cache * Fix more formatting --------- Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>

Costa Tsaousis committed Feb 15, 2023 at 21:16 UTC d2daa19bf53c9a8cb781c8e50a86b9961b0503a9
92 files changed +3006 -2269
aclk/aclk_query.c
+1 -1
@@ -192,7 +192,7 @@ static int http_api_v2(struct aclk_query_thread *query_thr, aclk_query_t query)
192 w->response.data->date = w->tv_ready.tv_sec;
193 web_client_build_http_header(w);
194 local_buffer = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE, &netdata_buffers_statistics.buffers_aclk);
195 - local_buffer->contenttype = CT_APPLICATION_JSON;
195 + local_buffer->content_type = CT_APPLICATION_JSON;
196
197 buffer_strcat(local_buffer, w->response.header_output->buffer);
198
collectors/apps.plugin/apps_plugin.c
+305 -178
@@ -638,9 +638,9 @@ int read_user_or_group_ids(struct user_or_group_ids *ids, struct timespec *last_
638 struct user_or_group_id *user_or_group_id = callocz(1, sizeof(struct user_or_group_id));
639
640 if(ids->type == USER_ID)
641 - user_or_group_id->id.uid = (uid_t)str2ull(id_string);
641 + user_or_group_id->id.uid = (uid_t) str2ull(id_string, NULL);
642 else
643 - user_or_group_id->id.gid = (uid_t)str2ull(id_string);
643 + user_or_group_id->id.gid = (uid_t) str2ull(id_string, NULL);
644
645 user_or_group_id->name = strdupz(name);
646 user_or_group_id->updated = 1;
@@ -1452,7 +1452,7 @@ static inline int read_proc_pid_stat(struct pid_stat *p, void *ptr) {
1452 pid_incremental_rate(stat, p->cstime, str2kernel_uint_t(procfile_lineword(ff, 0, 16)));
1453 // p->priority = str2kernel_uint_t(procfile_lineword(ff, 0, 17));
1454 // p->nice = str2kernel_uint_t(procfile_lineword(ff, 0, 18));
1455 - p->num_threads = (int32_t)str2uint32_t(procfile_lineword(ff, 0, 19));
1455 + p->num_threads = (int32_t) str2uint32_t(procfile_lineword(ff, 0, 19), NULL);
1456 // p->itrealvalue = str2kernel_uint_t(procfile_lineword(ff, 0, 20));
1457 p->collected_starttime = str2kernel_uint_t(procfile_lineword(ff, 0, 21)) / system_hz;
1458 p->uptime = (global_uptime > p->collected_starttime)?(global_uptime - p->collected_starttime):0;
@@ -4234,7 +4234,7 @@ static void get_MemTotal(void) {
4234 for(line = 0; line < lines ;line++) {
4235 size_t words = procfile_linewords(ff, line);
4236 if(words == 3 && strcmp(procfile_lineword(ff, line, 0), "MemTotal") == 0 && strcmp(procfile_lineword(ff, line, 2), "kB") == 0) {
4237 - kernel_uint_t n = str2ull(procfile_lineword(ff, line, 1));
4237 + kernel_uint_t n = str2ull(procfile_lineword(ff, line, 1), NULL);
4238 if(n) MemTotal = n;
4239 break;
4240 }
@@ -4289,47 +4289,41 @@ static void apps_plugin_function_processes_help(const char *transaction) {
4289 }
4290
4291 #define add_table_field(wb, key, name, visible, type, visualization, transform, decimal_points, units, max, sort, sortable, sticky, unique_key, pointer_to, summary, range) do { \
4292 - if(fields_added) buffer_strcat(wb, ","); \
4293 - buffer_sprintf(wb, "\n \"%s\": {", key); \
4294 - buffer_sprintf(wb, "\n \"index\":%d,", fields_added); \
4295 - buffer_sprintf(wb, "\n \"unique_key\":%s,", (unique_key)?"true":"false"); \
4296 - buffer_sprintf(wb, "\n \"name\":\"%s\",", name); \
4297 - buffer_sprintf(wb, "\n \"visible\":%s,", (visible)?"true":"false"); \
4298 - buffer_sprintf(wb, "\n \"type\":\"%s\",", type); \
4299 - if(units) \
4300 - buffer_sprintf(wb, "\n \"units\":\"%s\",", (char*)(units)); \
4301 - buffer_sprintf(wb, "\n \"visualization\":\"%s\",", visualization); \
4302 - buffer_sprintf(wb, "\n \"value_options\":{"); \
4303 - if(units) \
4304 - buffer_sprintf(wb, "\n \"units\":\"%s\",", (char*)(units)); \
4305 - buffer_sprintf(wb, "\n \"transform\":\"%s\",", transform); \
4306 - buffer_sprintf(wb, "\n \"decimal_points\":%d", decimal_points); \
4307 - buffer_sprintf(wb, "\n },"); \
4292 + buffer_json_member_add_object(wb, key); \
4293 + buffer_json_member_add_uint64(wb, "index", fields_added); \
4294 + buffer_json_member_add_boolean(wb, "unique_key", unique_key); \
4295 + buffer_json_member_add_string(wb, "name", name); \
4296 + buffer_json_member_add_boolean(wb, "visible", visible); \
4297 + buffer_json_member_add_string(wb, "type", type); \
4298 + buffer_json_member_add_string_or_omit(wb, "units", (char*)(units)); \
4299 + buffer_json_member_add_string(wb, "visualization", visualization); \
4300 + buffer_json_member_add_object(wb, "value_options"); \
4301 + buffer_json_member_add_string_or_omit(wb, "units", (char*)(units)); \
4302 + buffer_json_member_add_string(wb, "transform", transform); \
4303 + buffer_json_member_add_uint64(wb, "decimal_points", decimal_points); \
4304 + buffer_json_object_close(wb); \
4305 if(!isnan((NETDATA_DOUBLE)(max))) \
4309 - buffer_sprintf(wb, "\n \"max\":%f,", (NETDATA_DOUBLE)(max)); \
4310 - if(pointer_to) \
4311 - buffer_sprintf(wb, "\n \"pointer_to\":\"%s\",", (char *)(pointer_to)); \
4312 - buffer_sprintf(wb, "\n \"sort\":\"%s\",", sort); \
4313 - buffer_sprintf(wb, "\n \"sortable\":%s,", (sortable)?"true":"false"); \
4314 - buffer_sprintf(wb, "\n \"sticky\":%s,", (sticky)?"true":"false"); \
4315 - buffer_sprintf(wb, "\n \"summary\":\"%s\",", summary); \
4316 - buffer_sprintf(wb, "\n \"filter\":\"%s\"", (range)?"range":"multiselect"); \
4317 - buffer_sprintf(wb, "\n }"); \
4306 + buffer_json_member_add_double(wb, "max", (NETDATA_DOUBLE)(max)); \
4307 + buffer_json_member_add_string_or_omit(wb, "pointer_to", (char *)(pointer_to)); \
4308 + buffer_json_member_add_string(wb, "sort", sort); \
4309 + buffer_json_member_add_boolean(wb, "sortable", sortable); \
4310 + buffer_json_member_add_boolean(wb, "sticky", sticky); \
4311 + buffer_json_member_add_string(wb, "summary", summary); \
4312 + buffer_json_member_add_string(wb, "filter", (range)?"range":"multiselect"); \
4313 + buffer_json_object_close(wb); \
4314 fields_added++; \
4315 } while(0)
4316
4317 #define add_value_field_llu_with_max(wb, key, value) do { \
4318 unsigned long long _tmp = (value); \
4319 key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \
4324 - buffer_fast_strcat(wb, ",", 1); \
4325 - buffer_print_llu(wb, _tmp); \
4320 + buffer_json_add_array_item_uint64(wb, _tmp); \
4321 } while(0)
4322
4323 #define add_value_field_ndd_with_max(wb, key, value) do { \
4324 NETDATA_DOUBLE _tmp = (value); \
4325 key ## _max = (rows == 0) ? (_tmp) : MAX(key ## _max, _tmp); \
4331 - buffer_fast_strcat(wb, ",", 1); \
4332 - buffer_rrd_value(wb, _tmp); \
4326 + buffer_json_add_array_item_double(wb, _tmp); \
4327 } while(0)
4328
4329 static void apps_plugin_function_processes(const char *transaction, char *function __maybe_unused, char *line_buffer __maybe_unused, int line_max __maybe_unused, int timeout __maybe_unused) {
@@ -4406,18 +4400,12 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4400 unsigned int io_divisor = 1024 * RATES_DETAIL;
4401
4402 BUFFER *wb = buffer_create(PLUGINSD_LINE_MAX, NULL);
4409 - buffer_sprintf(wb,
4410 - "{"
4411 - "\n \"status\":%d"
4412 - ",\n \"type\":\"table\""
4413 - ",\n \"update_every\":%d"
4414 - ",\n \"help\":\"%s\""
4415 - ",\n \"data\":["
4416 - "\n"
4417 - , HTTP_RESP_OK
4418 - , update_every
4419 - , APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION
4420 - );
4403 + buffer_json_initialize(wb, "\"", "\"", 0, true);
4404 + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
4405 + buffer_json_member_add_string(wb, "type", "table");
4406 + buffer_json_member_add_time_t(wb, "update_every", update_every);
4407 + buffer_json_member_add_string(wb, "help", APPS_PLUGIN_PROCESSES_FUNCTION_DESCRIPTION);
4408 + buffer_json_member_add_array(wb, "data");
4409
4410 NETDATA_DOUBLE
4411 UserCPU_max = 0.0
@@ -4493,52 +4481,41 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4481 if(filter_gid && p->gid != gid)
4482 continue;
4483
4496 - if(rows) buffer_fast_strcat(wb, ",\n", 2);
4484 rows++;
4485
4499 - buffer_strcat(wb, " [");
4486 + buffer_json_add_array_item_array(wb);
4487
4488 // IMPORTANT!
4489 // THE ORDER SHOULD BE THE SAME WITH THE FIELDS!
4490
4491 // pid
4505 - buffer_print_llu(wb, p->pid);
4492 + buffer_json_add_array_item_uint64(wb, p->pid);
4493
4494 // cmd
4508 - buffer_fast_strcat(wb, ",\"", 2);
4509 - buffer_strcat_jsonescape(wb, p->comm);
4510 - buffer_fast_strcat(wb, "\"", 1);
4495 + buffer_json_add_array_item_string(wb, p->comm);
4496
4497 #ifdef NETDATA_DEV_MODE
4498 // cmdline
4514 - buffer_fast_strcat(wb, ",\"", 2);
4515 - buffer_strcat_jsonescape(wb, (p->cmdline && *p->cmdline) ? p->cmdline : p->comm);
4516 - buffer_fast_strcat(wb, "\"", 1);
4499 + buffer_json_add_array_item_string(wb, (p->cmdline && *p->cmdline) ? p->cmdline : p->comm);
4500 #endif
4501
4502 // ppid
4520 - buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->ppid);
4503 + buffer_json_add_array_item_uint64(wb, p->ppid);
4504
4505 // category
4523 - buffer_fast_strcat(wb, ",\"", 2);
4524 - buffer_strcat_jsonescape(wb, p->target ? p->target->name : "-");
4525 - buffer_fast_strcat(wb, "\"", 1);
4506 + buffer_json_add_array_item_string(wb, p->target ? p->target->name : "-");
4507
4508 // user
4528 - buffer_fast_strcat(wb, ",\"", 2);
4529 - buffer_strcat_jsonescape(wb, p->user_target ? p->user_target->name : "-");
4530 - buffer_fast_strcat(wb, "\"", 1);
4509 + buffer_json_add_array_item_string(wb, p->user_target ? p->user_target->name : "-");
4510
4511 // uid
4533 - buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->uid);
4512 + buffer_json_add_array_item_uint64(wb, p->uid);
4513
4514 // group
4536 - buffer_fast_strcat(wb, ",\"", 2);
4537 - buffer_strcat_jsonescape(wb, p->group_target ? p->group_target->name : "-");
4538 - buffer_fast_strcat(wb, "\"", 1);
4515 + buffer_json_add_array_item_string(wb, p->group_target ? p->group_target->name : "-");
4516
4517 // gid
4541 - buffer_fast_strcat(wb, ",", 1); buffer_print_llu(wb, p->gid);
4518 + buffer_json_add_array_item_uint64(wb, p->gid);
4519
4520 // CPU utilization %
4521 add_value_field_ndd_with_max(wb, CPU, (NETDATA_DOUBLE)(p->utime + p->stime + p->gtime + p->cutime + p->cstime + p->cgtime) / cpu_divisor);
@@ -4599,18 +4576,15 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4576 add_value_field_llu_with_max(wb, Threads, p->num_threads);
4577 add_value_field_llu_with_max(wb, Uptime, p->uptime);
4578
4602 - buffer_fast_strcat(wb, "]", 1);
4603 -
4604 - fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
4605 - buffer_flush(wb);
4579 + buffer_json_array_close(wb);
4580 }
4581
4582 + buffer_json_array_close(wb);
4583 + buffer_json_member_add_object(wb, "columns");
4584 +
4585 {
4586 int fields_added = 0;
4587
4611 - buffer_flush(wb);
4612 - buffer_sprintf(wb, "\n ],\n \"columns\": {");
4613 -
4588 // IMPORTANT!
4589 // THE ORDER SHOULD BE THE SAME WITH THE VALUES!
4590 add_table_field(wb, "PID", "Process ID", true, "integer", "value", "number", 0, NULL, NAN, "ascending", true, true, true, NULL, "count_unique", false);
@@ -4684,118 +4658,271 @@ static void apps_plugin_function_processes(const char *transaction, char *functi
4658 add_table_field(wb, "Processes", "Processes", true, "bar-with-integer", "bar", "number", 0, "processes", Processes_max, "descending", true, false, false, NULL, "sum", true);
4659 add_table_field(wb, "Threads", "Threads", true, "bar-with-integer", "bar", "number", 0, "threads", Threads_max, "descending", true, false, false, NULL, "sum", true);
4660 add_table_field(wb, "Uptime", "Uptime in seconds", true, "duration", "bar", "duration", 2, "seconds", Uptime_max, "descending", true, false, false, NULL, "max", true);
4661 + }
4662 + buffer_json_object_close(wb);
4663
4688 - buffer_strcat(
4689 - wb,
4690 - ""
4691 - "\n },"
4692 - "\n \"default_sort_column\": \"CPU\","
4693 - "\n \"charts\": {"
4694 - "\n \"CPU\": {"
4695 - "\n \"name\":\"CPU Utilization\","
4696 - "\n \"type\":\"stacked-bar\","
4697 - "\n \"columns\": [ \"UserCPU\", \"SysCPU\", \"GuestCPU\", \"CUserCPU\", \"CSysCPU\", \"CGuestCPU\" ]"
4698 - "\n },"
4699 - "\n \"Memory\": {"
4700 - "\n \"name\":\"Memory\","
4701 - "\n \"type\":\"stacked-bar\","
4702 - "\n \"columns\": [ \"Virtual\", \"Resident\", \"Shared\", \"Swap\" ]"
4703 - "\n },"
4704 - );
4664 + buffer_json_member_add_string(wb, "default_sort_column", "CPU");
4665
4706 - if(MemTotal)
4707 - buffer_strcat(
4708 - wb,
4709 - ""
4710 - "\n \"MemoryPercent\": {"
4711 - "\n \"name\":\"Memory Percentage\","
4712 - "\n \"type\":\"stacked-bar\","
4713 - "\n \"columns\": [ \"Memory\" ]"
4714 - "\n },"
4715 - );
4666 + buffer_json_member_add_object(wb, "charts");
4667 + {
4668 + // CPU chart
4669 + buffer_json_member_add_object(wb, "CPU");
4670 + {
4671 + buffer_json_member_add_string(wb, "name", "CPU Utilization");
4672 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4673 + buffer_json_member_add_array(wb, "columns");
4674 + {
4675 + buffer_json_add_array_item_string(wb, "UserCPU");
4676 + buffer_json_add_array_item_string(wb, "SysCPU");
4677 + buffer_json_add_array_item_string(wb, "GuestCPU");
4678 + buffer_json_add_array_item_string(wb, "CUserCPU");
4679 + buffer_json_add_array_item_string(wb, "CSysCPU");
4680 + buffer_json_add_array_item_string(wb, "CGuestCPU");
4681 + }
4682 + buffer_json_array_close(wb);
4683 + }
4684 + buffer_json_object_close(wb);
4685 +
4686 + // Memory chart
4687 + buffer_json_member_add_object(wb, "Memory");
4688 + {
4689 + buffer_json_member_add_string(wb, "name", "Memory");
4690 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4691 + buffer_json_member_add_array(wb, "columns");
4692 + {
4693 + buffer_json_add_array_item_string(wb, "Virtual");
4694 + buffer_json_add_array_item_string(wb, "Resident");
4695 + buffer_json_add_array_item_string(wb, "Shared");
4696 + buffer_json_add_array_item_string(wb, "Swap");
4697 + }
4698 + buffer_json_array_close(wb);
4699 + }
4700 + buffer_json_object_close(wb);
4701 +
4702 + if(MemTotal) {
4703 + // Memory chart
4704 + buffer_json_member_add_object(wb, "MemoryPercent");
4705 + {
4706 + buffer_json_member_add_string(wb, "name", "Memory Percentage");
4707 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4708 + buffer_json_member_add_array(wb, "columns");
4709 + {
4710 + buffer_json_add_array_item_string(wb, "Memory");
4711 + }
4712 + buffer_json_array_close(wb);
4713 + }
4714 + buffer_json_object_close(wb);
4715 + }
4716
4717 - buffer_strcat(
4718 - wb, ""
4719 - #ifndef __FreeBSD__
4720 - "\n \"Reads\": {"
4721 - "\n \"name\":\"I/O Reads\","
4722 - "\n \"type\":\"stacked-bar\","
4723 - "\n \"columns\": [ \"LReads\", \"PReads\" ]"
4724 - "\n },"
4725 - "\n \"Writes\": {"
4726 - "\n \"name\":\"I/O Writes\","
4727 - "\n \"type\":\"stacked-bar\","
4728 - "\n \"columns\": [ \"LWrites\", \"PWrites\" ]"
4729 - "\n },"
4730 - "\n \"LogicalIO\": {"
4731 - "\n \"name\":\"Logical I/O\","
4732 - "\n \"type\":\"stacked-bar\","
4733 - "\n \"columns\": [ \"LReads\", \"LWrites\" ]"
4734 - "\n },"
4735 - #endif
4736 - "\n \"PhysicalIO\": {"
4737 - "\n \"name\":\"Physical I/O\","
4738 - "\n \"type\":\"stacked-bar\","
4739 - "\n \"columns\": [ \"PReads\", \"PWrites\" ]"
4740 - "\n },"
4741 - "\n \"IOCalls\": {"
4742 - "\n \"name\":\"I/O Calls\","
4743 - "\n \"type\":\"stacked-bar\","
4744 - "\n \"columns\": [ \"RCalls\", \"WCalls\" ]"
4745 - "\n },"
4746 - "\n \"MinFlt\": {"
4747 - "\n \"name\":\"Minor Page Faults\","
4748 - "\n \"type\":\"stacked-bar\","
4749 - "\n \"columns\": [ \"MinFlt\", \"CMinFlt\" ]"
4750 - "\n },"
4751 - "\n \"MajFlt\": {"
4752 - "\n \"name\":\"Major Page Faults\","
4753 - "\n \"type\":\"stacked-bar\","
4754 - "\n \"columns\": [ \"MajFlt\", \"CMajFlt\" ]"
4755 - "\n },"
4756 - "\n \"Threads\": {"
4757 - "\n \"name\":\"Threads\","
4758 - "\n \"type\":\"stacked-bar\","
4759 - "\n \"columns\": [ \"Threads\" ]"
4760 - "\n },"
4761 - "\n \"Processes\": {"
4762 - "\n \"name\":\"Processes\","
4763 - "\n \"type\":\"stacked-bar\","
4764 - "\n \"columns\": [ \"Processes\" ]"
4765 - "\n },"
4766 - "\n \"FDs\": {"
4767 - "\n \"name\":\"File Descriptors\","
4768 - "\n \"type\":\"stacked-bar\","
4769 - "\n \"columns\": [ \"Files\", \"Pipes\", \"Sockets\", \"iNotiFDs\", \"EventFDs\", \"TimerFDs\", \"SigFDs\", \"EvPollFDs\", \"OtherFDs\" ]"
4770 - "\n }"
4771 - "\n },"
4772 - "\n \"group_by\": {"
4773 - "\n \"pid\": {"
4774 - "\n \"name\":\"Process Tree by PID\","
4775 - "\n \"columns\":[ \"PPID\" ]"
4776 - "\n },"
4777 - "\n \"category\": {"
4778 - "\n \"name\":\"Process Tree by Category\","
4779 - "\n \"columns\":[ \"Category\", \"PPID\" ]"
4780 - "\n },"
4781 - "\n \"user\": {"
4782 - "\n \"name\":\"Process Tree by User\","
4783 - "\n \"columns\":[ \"User\", \"PPID\" ]"
4784 - "\n },"
4785 - "\n \"group\": {"
4786 - "\n \"name\":\"Process Tree by Group\","
4787 - "\n \"columns\":[ \"Group\", \"PPID\" ]"
4788 - "\n }"
4789 - "\n }"
4790 - );
4717 +#ifndef __FreeBSD__
4718 + // I/O Reads chart
4719 + buffer_json_member_add_object(wb, "Reads");
4720 + {
4721 + buffer_json_member_add_string(wb, "name", "I/O Reads");
4722 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4723 + buffer_json_member_add_array(wb, "columns");
4724 + {
4725 + buffer_json_add_array_item_string(wb, "LReads");
4726 + buffer_json_add_array_item_string(wb, "PReads");
4727 + }
4728 + buffer_json_array_close(wb);
4729 + }
4730 + buffer_json_object_close(wb);
4731 +
4732 + // I/O Writes chart
4733 + buffer_json_member_add_object(wb, "Writes");
4734 + {
4735 + buffer_json_member_add_string(wb, "name", "I/O Writes");
4736 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4737 + buffer_json_member_add_array(wb, "columns");
4738 + {
4739 + buffer_json_add_array_item_string(wb, "LWrites");
4740 + buffer_json_add_array_item_string(wb, "PWrites");
4741 + }
4742 + buffer_json_array_close(wb);
4743 + }
4744 + buffer_json_object_close(wb);
4745 +
4746 + // Logical I/O chart
4747 + buffer_json_member_add_object(wb, "LogicalIO");
4748 + {
4749 + buffer_json_member_add_string(wb, "name", "Logical I/O");
4750 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4751 + buffer_json_member_add_array(wb, "columns");
4752 + {
4753 + buffer_json_add_array_item_string(wb, "LReads");
4754 + buffer_json_add_array_item_string(wb, "LWrites");
4755 + }
4756 + buffer_json_array_close(wb);
4757 + }
4758 + buffer_json_object_close(wb);
4759 +#endif
4760 +
4761 + // Physical I/O chart
4762 + buffer_json_member_add_object(wb, "PhysicalIO");
4763 + {
4764 + buffer_json_member_add_string(wb, "name", "Physical I/O");
4765 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4766 + buffer_json_member_add_array(wb, "columns");
4767 + {
4768 + buffer_json_add_array_item_string(wb, "PReads");
4769 + buffer_json_add_array_item_string(wb, "PWrites");
4770 + }
4771 + buffer_json_array_close(wb);
4772 + }
4773 + buffer_json_object_close(wb);
4774 +
4775 + // I/O Calls chart
4776 + buffer_json_member_add_object(wb, "IOCalls");
4777 + {
4778 + buffer_json_member_add_string(wb, "name", "I/O Calls");
4779 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4780 + buffer_json_member_add_array(wb, "columns");
4781 + {
4782 + buffer_json_add_array_item_string(wb, "RCalls");
4783 + buffer_json_add_array_item_string(wb, "WCalls");
4784 + }
4785 + buffer_json_array_close(wb);
4786 + }
4787 + buffer_json_object_close(wb);
4788 +
4789 + // Minor Page Faults chart
4790 + buffer_json_member_add_object(wb, "MinFlt");
4791 + {
4792 + buffer_json_member_add_string(wb, "name", "Minor Page Faults");
4793 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4794 + buffer_json_member_add_array(wb, "columns");
4795 + {
4796 + buffer_json_add_array_item_string(wb, "MinFlt");
4797 + buffer_json_add_array_item_string(wb, "CMinFlt");
4798 + }
4799 + buffer_json_array_close(wb);
4800 + }
4801 + buffer_json_object_close(wb);
4802 +
4803 + // Major Page Faults chart
4804 + buffer_json_member_add_object(wb, "MajFlt");
4805 + {
4806 + buffer_json_member_add_string(wb, "name", "Major Page Faults");
4807 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4808 + buffer_json_member_add_array(wb, "columns");
4809 + {
4810 + buffer_json_add_array_item_string(wb, "MajFlt");
4811 + buffer_json_add_array_item_string(wb, "CMajFlt");
4812 + }
4813 + buffer_json_array_close(wb);
4814 + }
4815 + buffer_json_object_close(wb);
4816 +
4817 + // Threads chart
4818 + buffer_json_member_add_object(wb, "Threads");
4819 + {
4820 + buffer_json_member_add_string(wb, "name", "Threads");
4821 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4822 + buffer_json_member_add_array(wb, "columns");
4823 + {
4824 + buffer_json_add_array_item_string(wb, "Threads");
4825 + }
4826 + buffer_json_array_close(wb);
4827 + }
4828 + buffer_json_object_close(wb);
4829 +
4830 + // Processes chart
4831 + buffer_json_member_add_object(wb, "Processes");
4832 + {
4833 + buffer_json_member_add_string(wb, "name", "Processes");
4834 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4835 + buffer_json_member_add_array(wb, "columns");
4836 + {
4837 + buffer_json_add_array_item_string(wb, "Processes");
4838 + }
4839 + buffer_json_array_close(wb);
4840 + }
4841 + buffer_json_object_close(wb);
4842 +
4843 + // FDs chart
4844 + buffer_json_member_add_object(wb, "FDs");
4845 + {
4846 + buffer_json_member_add_string(wb, "name", "File Descriptors");
4847 + buffer_json_member_add_string(wb, "type", "stacked-bar");
4848 + buffer_json_member_add_array(wb, "columns");
4849 + {
4850 + buffer_json_add_array_item_string(wb, "Files");
4851 + buffer_json_add_array_item_string(wb, "Pipes");
4852 + buffer_json_add_array_item_string(wb, "Sockets");
4853 + buffer_json_add_array_item_string(wb, "iNotiFDs");
4854 + buffer_json_add_array_item_string(wb, "EventFDs");
4855 + buffer_json_add_array_item_string(wb, "TimerFDs");
4856 + buffer_json_add_array_item_string(wb, "SigFDs");
4857 + buffer_json_add_array_item_string(wb, "EvPollFDs");
4858 + buffer_json_add_array_item_string(wb, "OtherFDs");
4859 + }
4860 + buffer_json_array_close(wb);
4861 + }
4862 + buffer_json_object_close(wb);
4863 + }
4864 + buffer_json_object_close(wb); // charts
4865
4792 - fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
4866 + buffer_json_member_add_object(wb, "group_by");
4867 + {
4868 + // group by PID
4869 + buffer_json_member_add_object(wb, "PID");
4870 + {
4871 + buffer_json_member_add_string(wb, "name", "Process Tree by PID");
4872 + buffer_json_member_add_array(wb, "columns");
4873 + {
4874 + buffer_json_add_array_item_string(wb, "PPID");
4875 + }
4876 + buffer_json_array_close(wb);
4877 + }
4878 + buffer_json_object_close(wb);
4879 +
4880 + // group by Category
4881 + buffer_json_member_add_object(wb, "Category");
4882 + {
4883 + buffer_json_member_add_string(wb, "name", "Process Tree by Category");
4884 + buffer_json_member_add_array(wb, "columns");
4885 + {
4886 + buffer_json_add_array_item_string(wb, "Category");
4887 + buffer_json_add_array_item_string(wb, "PPID");
4888 + }
4889 + buffer_json_array_close(wb);
4890 + }
4891 + buffer_json_object_close(wb);
4892 +
4893 + // group by User
4894 + buffer_json_member_add_object(wb, "User");
4895 + {
4896 + buffer_json_member_add_string(wb, "name", "Process Tree by User");
4897 + buffer_json_member_add_array(wb, "columns");
4898 + {
4899 + buffer_json_add_array_item_string(wb, "User");
4900 + buffer_json_add_array_item_string(wb, "PPID");
4901 + }
4902 + buffer_json_array_close(wb);
4903 + }
4904 + buffer_json_object_close(wb);
4905 +
4906 + // group by Group
4907 + buffer_json_member_add_object(wb, "Group");
4908 + {
4909 + buffer_json_member_add_string(wb, "name", "Process Tree by Group");
4910 + buffer_json_member_add_array(wb, "columns");
4911 + {
4912 + buffer_json_add_array_item_string(wb, "Group");
4913 + buffer_json_add_array_item_string(wb, "PPID");
4914 + }
4915 + buffer_json_array_close(wb);
4916 + }
4917 + buffer_json_object_close(wb);
4918 }
4919 + buffer_json_object_close(wb); // group_by
4920
4795 - buffer_free(wb);
4921 + buffer_json_member_add_time_t(wb, "expires", expires);
4922 + buffer_json_finalize(wb);
4923
4797 - fprintf(stdout, ",\n \"expires\":%lld", (long long)expires);
4798 - fprintf(stdout, "\n}");
4924 + fwrite(buffer_tostring(wb), buffer_strlen(wb), 1, stdout);
4925 + buffer_free(wb);
4926
4927 pluginsd_function_result_end_to_stdout();
4928 }
collectors/cgroups.plugin/sys_fs_cgroup.c
+21 -21
@@ -1089,10 +1089,10 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
1089 uint32_t hash = simple_hash(s);
1090
1091 if(unlikely(hash == user_hash && !strcmp(s, "user")))
1092 - cp->user = str2ull(procfile_lineword(ff, i, 1));
1092 + cp->user = str2ull(procfile_lineword(ff, i, 1), NULL);
1093
1094 else if(unlikely(hash == system_hash && !strcmp(s, "system")))
1095 - cp->system = str2ull(procfile_lineword(ff, i, 1));
1095 + cp->system = str2ull(procfile_lineword(ff, i, 1), NULL);
1096 }
1097
1098 cp->updated = 1;
@@ -1138,11 +1138,11 @@ static inline void cgroup_read_cpuacct_cpu_stat(struct cpuacct_cpu_throttling *c
1138 uint32_t hash = simple_hash(s);
1139
1140 if (unlikely(hash == nr_periods_hash && !strcmp(s, "nr_periods"))) {
1141 - cp->nr_periods = str2ull(procfile_lineword(ff, i, 1));
1141 + cp->nr_periods = str2ull(procfile_lineword(ff, i, 1), NULL);
1142 } else if (unlikely(hash == nr_throttled_hash && !strcmp(s, "nr_throttled"))) {
1143 - cp->nr_throttled = str2ull(procfile_lineword(ff, i, 1));
1143 + cp->nr_throttled = str2ull(procfile_lineword(ff, i, 1), NULL);
1144 } else if (unlikely(hash == throttled_time_hash && !strcmp(s, "throttled_time"))) {
1145 - cp->throttled_time = str2ull(procfile_lineword(ff, i, 1));
1145 + cp->throttled_time = str2ull(procfile_lineword(ff, i, 1), NULL);
1146 }
1147 }
1148 cp->nr_throttled_perc =
@@ -1195,15 +1195,15 @@ static inline void cgroup2_read_cpuacct_cpu_stat(struct cpuacct_stat *cp, struct
1195 uint32_t hash = simple_hash(s);
1196
1197 if (unlikely(hash == user_usec_hash && !strcmp(s, "user_usec"))) {
1198 - cp->user = str2ull(procfile_lineword(ff, i, 1));
1198 + cp->user = str2ull(procfile_lineword(ff, i, 1), NULL);
1199 } else if (unlikely(hash == system_usec_hash && !strcmp(s, "system_usec"))) {
1200 - cp->system = str2ull(procfile_lineword(ff, i, 1));
1200 + cp->system = str2ull(procfile_lineword(ff, i, 1), NULL);
1201 } else if (unlikely(hash == nr_periods_hash && !strcmp(s, "nr_periods"))) {
1202 - cpt->nr_periods = str2ull(procfile_lineword(ff, i, 1));
1202 + cpt->nr_periods = str2ull(procfile_lineword(ff, i, 1), NULL);
1203 } else if (unlikely(hash == nr_throttled_hash && !strcmp(s, "nr_throttled"))) {
1204 - cpt->nr_throttled = str2ull(procfile_lineword(ff, i, 1));
1204 + cpt->nr_throttled = str2ull(procfile_lineword(ff, i, 1), NULL);
1205 } else if (unlikely(hash == throttled_usec_hash && !strcmp(s, "throttled_usec"))) {
1206 - cpt->throttled_time = str2ull(procfile_lineword(ff, i, 1)) * 1000; // usec -> ns
1206 + cpt->throttled_time = str2ull(procfile_lineword(ff, i, 1), NULL) * 1000; // usec -> ns
1207 }
1208 }
1209 cpt->nr_throttled_perc =
@@ -1289,7 +1289,7 @@ static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
1289
1290 unsigned long long total = 0;
1291 for(i = 0; i < ca->cpus ;i++) {
1292 - unsigned long long n = str2ull(procfile_lineword(ff, 0, i));
1292 + unsigned long long n = str2ull(procfile_lineword(ff, 0, i), NULL);
1293 ca->cpu_percpu[i] = n;
1294 total += n;
1295 }
@@ -1346,10 +1346,10 @@ static inline void cgroup_read_blkio(struct blkio *io) {
1346 uint32_t hash = simple_hash(s);
1347
1348 if(unlikely(hash == Read_hash && !strcmp(s, "Read")))
1349 - io->Read += str2ull(procfile_lineword(ff, i, 2));
1349 + io->Read += str2ull(procfile_lineword(ff, i, 2), NULL);
1350
1351 else if(unlikely(hash == Write_hash && !strcmp(s, "Write")))
1352 - io->Write += str2ull(procfile_lineword(ff, i, 2));
1352 + io->Write += str2ull(procfile_lineword(ff, i, 2), NULL);
1353
1354 /*
1355 else if(unlikely(hash == Sync_hash && !strcmp(s, "Sync")))
@@ -1409,8 +1409,8 @@ static inline void cgroup2_read_blkio(struct blkio *io, unsigned int word_offset
1409 io->Write = 0;
1410
1411 for (i = 0; i < lines; i++) {
1412 - io->Read += str2ull(procfile_lineword(ff, i, 2 + word_offset));
1413 - io->Write += str2ull(procfile_lineword(ff, i, 4 + word_offset));
1412 + io->Read += str2ull(procfile_lineword(ff, i, 2 + word_offset), NULL);
1413 + io->Write += str2ull(procfile_lineword(ff, i, 4 + word_offset), NULL);
1414 }
1415
1416 io->updated = 1;
@@ -1452,13 +1452,13 @@ static inline void cgroup2_read_pressure(struct pressure *res) {
1452 res->some.share_time.value10 = strtod(procfile_lineword(ff, 0, 2), NULL);
1453 res->some.share_time.value60 = strtod(procfile_lineword(ff, 0, 4), NULL);
1454 res->some.share_time.value300 = strtod(procfile_lineword(ff, 0, 6), NULL);
1455 - res->some.total_time.value_total = str2ull(procfile_lineword(ff, 0, 8)) / 1000; // us->ms
1455 + res->some.total_time.value_total = str2ull(procfile_lineword(ff, 0, 8), NULL) / 1000; // us->ms
1456
1457 if (lines > 2) {
1458 res->full.share_time.value10 = strtod(procfile_lineword(ff, 1, 2), NULL);
1459 res->full.share_time.value60 = strtod(procfile_lineword(ff, 1, 4), NULL);
1460 res->full.share_time.value300 = strtod(procfile_lineword(ff, 1, 6), NULL);
1461 - res->full.total_time.value_total = str2ull(procfile_lineword(ff, 1, 8)) / 1000; // us->ms
1461 + res->full.total_time.value_total = str2ull(procfile_lineword(ff, 1, 8), NULL) / 1000; // us->ms
1462 }
1463
1464 res->updated = 1;
@@ -3566,14 +3566,14 @@ static inline void update_cpu_limits2(struct cgroup *cg) {
3566 return;
3567 }
3568
3569 - cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1));
3569 + cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1), NULL);
3570 cg->cpuset_cpus = get_system_cpus();
3571
3572 char *s = "max\n\0";
3573 if(strcmp(s, procfile_lineword(ff, 0, 0)) == 0){
3574 cg->cpu_cfs_quota = cg->cpu_cfs_period * cg->cpuset_cpus;
3575 } else {
3576 - cg->cpu_cfs_quota = str2ull(procfile_lineword(ff, 0, 0));
3576 + cg->cpu_cfs_quota = str2ull(procfile_lineword(ff, 0, 0), NULL);
3577 }
3578 debug(D_CGROUP, "CPU limits values: %llu %llu %llu", cg->cpu_cfs_period, cg->cpuset_cpus, cg->cpu_cfs_quota);
3579 return;
@@ -3623,7 +3623,7 @@ static inline int update_memory_limits(char **filename, const RRDSETVAR_ACQUIRED
3623 rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value / (1024 * 1024)));
3624 return 1;
3625 }
3626 - *value = str2ull(buffer);
3626 + *value = str2ull(buffer, NULL);
3627 rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value / (1024 * 1024)));
3628 return 1;
3629 }
@@ -4111,7 +4111,7 @@ void update_cgroup_charts(int update_every) {
4111 if(likely(ff))
4112 ff = procfile_readall(ff);
4113 if(likely(ff && procfile_lines(ff) && !strncmp(procfile_word(ff, 0), "MemTotal", 8)))
4114 - ram_total = str2ull(procfile_word(ff, 1)) * 1024;
4114 + ram_total = str2ull(procfile_word(ff, 1), NULL) * 1024;
4115 else {
4116 collector_error("Cannot read file %s. Will not update cgroup %s RAM limit anymore.", filename, cg->id);
4117 freez(cg->filename_memory_limit);
collectors/ebpf.plugin/ebpf.c
+1 -1
@@ -2088,7 +2088,7 @@ static pid_t ebpf_read_previous_pid(char *filename)
2088 length = 63;
2089
2090 buffer[length] = '\0';
2091 - old_pid = (pid_t)str2uint32_t(buffer);
2091 + old_pid = (pid_t) str2uint32_t(buffer, NULL);
2092 }
2093 fclose(fp);
2094
collectors/plugins.d/pluginsd_parser.c
+62 -31
@@ -221,7 +221,7 @@ PARSER_RC pluginsd_set(char **words, size_t num_words, void *user)
221 rrdhost_hostname(host), rrdset_id(st), dimension, value && *value ? value : "UNSET");
222
223 if (value && *value)
224 - rrddim_set_by_pointer(st, rd, str2ll_hex_or_dec(value));
224 + rrddim_set_by_pointer(st, rd, str2ll_encoded(value));
225
226 return PARSER_RC_OK;
227 }
@@ -616,14 +616,14 @@ PARSER_RC pluginsd_dimension(char **words, size_t num_words, void *user)
616
617 long multiplier = 1;
618 if (multiplier_s && *multiplier_s) {
619 - multiplier = str2ll_hex_or_dec(multiplier_s);
619 + multiplier = str2ll_encoded(multiplier_s);
620 if (unlikely(!multiplier))
621 multiplier = 1;
622 }
623
624 long divisor = 1;
625 if (likely(divisor_s && *divisor_s)) {
626 - divisor = str2ll_hex_or_dec(divisor_s);
626 + divisor = str2ll_encoded(divisor_s);
627 if (unlikely(!divisor))
628 divisor = 1;
629 }
@@ -901,7 +901,7 @@ PARSER_RC pluginsd_function_result_begin(char **words, size_t num_words, void *u
901 }
902 else {
903 if(format && *format)
904 - pf->destination_wb->contenttype = functions_format_to_content_type(format);
904 + pf->destination_wb->content_type = functions_format_to_content_type(format);
905
906 pf->code = code;
907
@@ -967,7 +967,7 @@ PARSER_RC pluginsd_variable(char **words, size_t num_words, void *user)
967 return PLUGINSD_DISABLE_PLUGIN(user, PLUGINSD_KEYWORD_VARIABLE, "no chart is defined and no GLOBAL is given");
968
969 char *endptr = NULL;
970 - v = (NETDATA_DOUBLE)str2ndd(value, &endptr);
970 + v = (NETDATA_DOUBLE) str2ndd_encoded(value, &endptr);
971 if (unlikely(endptr && *endptr)) {
972 if (endptr == value)
973 error("PLUGINSD: 'host:%s/chart:%s' the value '%s' of VARIABLE '%s' cannot be parsed as a number",
@@ -1162,13 +1162,13 @@ PARSER_RC pluginsd_replay_begin(char **words, size_t num_words, void *user) {
1162 pluginsd_set_chart_from_parent(user, st, PLUGINSD_KEYWORD_REPLAY_BEGIN);
1163
1164 if(start_time_str && end_time_str) {
1165 - time_t start_time = (time_t)str2ul(start_time_str);
1166 - time_t end_time = (time_t)str2ul(end_time_str);
1165 + time_t start_time = (time_t) str2ull_encoded(start_time_str);
1166 + time_t end_time = (time_t) str2ull_encoded(end_time_str);
1167
1168 time_t wall_clock_time = 0, tolerance;
1169 bool wall_clock_comes_from_child; (void)wall_clock_comes_from_child;
1170 if(child_now_str) {
1171 - wall_clock_time = (time_t)str2ul(child_now_str);
1171 + wall_clock_time = (time_t) str2ull_encoded(child_now_str);
1172 tolerance = st->update_every + 1;
1173 wall_clock_comes_from_child = true;
1174 }
@@ -1314,7 +1314,7 @@ PARSER_RC pluginsd_replay_set(char **words, size_t num_words, void *user)
1314 RRDDIM_FLAGS rd_flags = rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE | RRDDIM_FLAG_ARCHIVED);
1315
1316 if(!(rd_flags & RRDDIM_FLAG_ARCHIVED)) {
1317 - NETDATA_DOUBLE value = strtondd(value_str, NULL);
1317 + NETDATA_DOUBLE value = str2ndd_encoded(value_str, NULL);
1318 SN_FLAGS flags = pluginsd_parse_storage_number_flags(flags_str);
1319
1320 if (!netdata_double_isnumber(value) || (flags == SN_EMPTY_SLOT)) {
@@ -1358,15 +1358,15 @@ PARSER_RC pluginsd_replay_rrddim_collection_state(char **words, size_t num_words
1358 if(!rd) return PLUGINSD_DISABLE_PLUGIN(user, NULL, NULL);
1359
1360 usec_t dim_last_collected_ut = (usec_t)rd->last_collected_time.tv_sec * USEC_PER_SEC + (usec_t)rd->last_collected_time.tv_usec;
1361 - usec_t last_collected_ut = last_collected_ut_str ? str2ull(last_collected_ut_str) : 0;
1361 + usec_t last_collected_ut = last_collected_ut_str ? str2ull_encoded(last_collected_ut_str) : 0;
1362 if(last_collected_ut > dim_last_collected_ut) {
1363 rd->last_collected_time.tv_sec = (time_t)(last_collected_ut / USEC_PER_SEC);
1364 rd->last_collected_time.tv_usec = (last_collected_ut % USEC_PER_SEC);
1365 }
1366
1367 - rd->last_collected_value = last_collected_value_str ? str2ll(last_collected_value_str, NULL) : 0;
1368 - rd->last_calculated_value = last_calculated_value_str ? str2ndd(last_calculated_value_str, NULL) : 0;
1369 - rd->last_stored_value = last_stored_value_str ? str2ndd(last_stored_value_str, NULL) : 0.0;
1367 + rd->last_collected_value = last_collected_value_str ? str2ll_encoded(last_collected_value_str) : 0;
1368 + rd->last_calculated_value = last_calculated_value_str ? str2ndd_encoded(last_calculated_value_str, NULL) : 0;
1369 + rd->last_stored_value = last_stored_value_str ? str2ndd_encoded(last_stored_value_str, NULL) : 0.0;
1370
1371 return PARSER_RC_OK;
1372 }
@@ -1386,14 +1386,14 @@ PARSER_RC pluginsd_replay_rrdset_collection_state(char **words, size_t num_words
1386 if(!st) return PLUGINSD_DISABLE_PLUGIN(user, NULL, NULL);
1387
1388 usec_t chart_last_collected_ut = (usec_t)st->last_collected_time.tv_sec * USEC_PER_SEC + (usec_t)st->last_collected_time.tv_usec;
1389 - usec_t last_collected_ut = last_collected_ut_str ? str2ull(last_collected_ut_str) : 0;
1389 + usec_t last_collected_ut = last_collected_ut_str ? str2ull_encoded(last_collected_ut_str) : 0;
1390 if(last_collected_ut > chart_last_collected_ut) {
1391 st->last_collected_time.tv_sec = (time_t)(last_collected_ut / USEC_PER_SEC);
1392 st->last_collected_time.tv_usec = (last_collected_ut % USEC_PER_SEC);
1393 }
1394
1395 usec_t chart_last_updated_ut = (usec_t)st->last_updated.tv_sec * USEC_PER_SEC + (usec_t)st->last_updated.tv_usec;
1396 - usec_t last_updated_ut = last_updated_ut_str ? str2ull(last_updated_ut_str) : 0;
1396 + usec_t last_updated_ut = last_updated_ut_str ? str2ull_encoded(last_updated_ut_str) : 0;
1397 if(last_updated_ut > chart_last_updated_ut) {
1398 st->last_updated.tv_sec = (time_t)(last_updated_ut / USEC_PER_SEC);
1399 st->last_updated.tv_usec = (last_updated_ut % USEC_PER_SEC);
@@ -1420,16 +1420,17 @@ PARSER_RC pluginsd_replay_end(char **words, size_t num_words, void *user)
1420 const char *last_entry_requested_txt = get_word(words, num_words, 6);
1421 const char *child_world_time_txt = get_word(words, num_words, 7); // optional
1422
1423 - time_t update_every_child = (time_t)str2ul(update_every_child_txt);
1424 - time_t first_entry_child = (time_t)str2ul(first_entry_child_txt);
1425 - time_t last_entry_child = (time_t)str2ul(last_entry_child_txt);
1423 + time_t update_every_child = (time_t) str2ull_encoded(update_every_child_txt);
1424 + time_t first_entry_child = (time_t) str2ull_encoded(first_entry_child_txt);
1425 + time_t last_entry_child = (time_t) str2ull_encoded(last_entry_child_txt);
1426
1427 bool start_streaming = (strcmp(start_streaming_txt, "true") == 0);
1428 - time_t first_entry_requested = (time_t)str2ul(first_entry_requested_txt);
1429 - time_t last_entry_requested = (time_t)str2ul(last_entry_requested_txt);
1428 + time_t first_entry_requested = (time_t) str2ull_encoded(first_entry_requested_txt);
1429 + time_t last_entry_requested = (time_t) str2ull_encoded(last_entry_requested_txt);
1430
1431 // the optional child world time
1432 - time_t child_world_time = (child_world_time_txt && *child_world_time_txt) ? (time_t)str2ul(child_world_time_txt) : now_realtime_sec();
1432 + time_t child_world_time = (child_world_time_txt && *child_world_time_txt) ? (time_t) str2ull_encoded(
1433 + child_world_time_txt) : now_realtime_sec();
1434
1435 PARSER_USER_OBJECT *user_object = user;
1436
@@ -1543,14 +1544,14 @@ PARSER_RC pluginsd_begin_v2(char **words, size_t num_words, void *user) {
1544 // ------------------------------------------------------------------------
1545 // parse the parameters
1546
1546 - time_t update_every = (time_t)str2ull_hex_or_dec(update_every_str);
1547 - time_t end_time = (time_t)str2ull_hex_or_dec(end_time_str);
1547 + time_t update_every = (time_t) str2ull_encoded(update_every_str);
1548 + time_t end_time = (time_t) str2ull_encoded(end_time_str);
1549
1550 time_t wall_clock_time;
1551 if(likely(*wall_clock_time_str == '#'))
1552 wall_clock_time = end_time;
1553 else
1553 - wall_clock_time = (time_t)str2ull_hex_or_dec(wall_clock_time_str);
1554 + wall_clock_time = (time_t) str2ull_encoded(wall_clock_time_str);
1555
1556 if (unlikely(update_every != st->update_every))
1557 rrdset_set_update_every_s(st, update_every);
@@ -1577,6 +1578,10 @@ PARSER_RC pluginsd_begin_v2(char **words, size_t num_words, void *user) {
1578 u->v2.stream_buffer = rrdset_push_metric_initialize(u->st, wall_clock_time);
1579
1580 if(u->v2.stream_buffer.v2 && u->v2.stream_buffer.wb) {
1581 + // check if receiver and sender have the same number parsing capabilities
1582 + bool can_copy = stream_has_capability(u, STREAM_CAP_IEEE754) == stream_has_capability(&u->v2.stream_buffer, STREAM_CAP_IEEE754);
1583 + NUMBER_ENCODING encoding = stream_has_capability(&u->v2.stream_buffer, STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_HEX;
1584 +
1585 BUFFER *wb = u->v2.stream_buffer.wb;
1586
1587 buffer_need_bytes(wb, 1024);
@@ -1587,11 +1592,26 @@ PARSER_RC pluginsd_begin_v2(char **words, size_t num_words, void *user) {
1592 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_BEGIN_V2 " '", sizeof(PLUGINSD_KEYWORD_BEGIN_V2) - 1 + 2);
1593 buffer_fast_strcat(wb, rrdset_id(st), string_strlen(st->id));
1594 buffer_fast_strcat(wb, "' ", 2);
1590 - buffer_strcat(wb, update_every_str);
1595 +
1596 + if(can_copy)
1597 + buffer_strcat(wb, update_every_str);
1598 + else
1599 + buffer_print_uint64_encoded(wb, encoding, update_every);
1600 +
1601 buffer_fast_strcat(wb, " ", 1);
1592 - buffer_strcat(wb, end_time_str);
1602 +
1603 + if(can_copy)
1604 + buffer_strcat(wb, end_time_str);
1605 + else
1606 + buffer_print_uint64_encoded(wb, encoding, end_time);
1607 +
1608 buffer_fast_strcat(wb, " ", 1);
1594 - buffer_strcat(wb, wall_clock_time_str);
1609 +
1610 + if(can_copy)
1611 + buffer_strcat(wb, wall_clock_time_str);
1612 + else
1613 + buffer_print_uint64_encoded(wb, encoding, wall_clock_time);
1614 +
1615 buffer_fast_strcat(wb, "\n", 1);
1616
1617 u->v2.stream_buffer.last_point_end_time_s = end_time;
@@ -1652,13 +1672,13 @@ PARSER_RC pluginsd_set_v2(char **words, size_t num_words, void *user) {
1672 // ------------------------------------------------------------------------
1673 // parse the parameters
1674
1655 - collected_number collected_value = (collected_number)str2ll_hex_or_dec(collected_str);
1675 + collected_number collected_value = (collected_number) str2ll_encoded(collected_str);
1676
1677 NETDATA_DOUBLE value;
1678 if(*value_str == '#')
1679 value = (NETDATA_DOUBLE)collected_value;
1680 else
1661 - value = strtondd(value_str, NULL);
1681 + value = str2ndd_encoded(value_str, NULL);
1682
1683 SN_FLAGS flags = pluginsd_parse_storage_number_flags(flags_str);
1684
@@ -1689,14 +1709,25 @@ PARSER_RC pluginsd_set_v2(char **words, size_t num_words, void *user) {
1709 // propagate it forward in v2
1710
1711 if(u->v2.stream_buffer.v2 && u->v2.stream_buffer.begin_v2_added && u->v2.stream_buffer.wb) {
1712 + // check if receiver and sender have the same number parsing capabilities
1713 + bool can_copy = stream_has_capability(u, STREAM_CAP_IEEE754) == stream_has_capability(&u->v2.stream_buffer, STREAM_CAP_IEEE754);
1714 + NUMBER_ENCODING integer_encoding = stream_has_capability(&u->v2.stream_buffer, STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_HEX;
1715 + NUMBER_ENCODING doubles_encoding = stream_has_capability(&u->v2.stream_buffer, STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_DECIMAL;
1716 +
1717 BUFFER *wb = u->v2.stream_buffer.wb;
1718 buffer_need_bytes(wb, 1024);
1719 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_SET_V2 " '", sizeof(PLUGINSD_KEYWORD_SET_V2) - 1 + 2);
1720 buffer_fast_strcat(wb, rrddim_id(rd), string_strlen(rd->id));
1721 buffer_fast_strcat(wb, "' ", 2);
1697 - buffer_strcat(wb, collected_str);
1722 + if(can_copy)
1723 + buffer_strcat(wb, collected_str);
1724 + else
1725 + buffer_print_int64_encoded(wb, integer_encoding, collected_value); // original v2 had hex
1726 buffer_fast_strcat(wb, " ", 1);
1699 - buffer_strcat(wb, value_str);
1727 + if(can_copy)
1728 + buffer_strcat(wb, value_str);
1729 + else
1730 + buffer_print_netdata_double_encoded(wb, doubles_encoding, value); // original v2 had decimal
1731 buffer_fast_strcat(wb, " ", 1);
1732 buffer_print_sn_flags(wb, flags, true);
1733 buffer_fast_strcat(wb, "\n", 1);
collectors/plugins.d/pluginsd_parser.h
+3 -1
@@ -22,6 +22,8 @@ typedef struct parser_user_object {
22 size_t data_collections_count;
23 int enabled;
24
25 + STREAM_CAPABILITIES capabilities; // receiver capabilities
26 +
27 struct {
28 bool parsing_host;
29 uuid_t machine_guid;
@@ -44,7 +46,7 @@ typedef struct parser_user_object {
46
47 struct parser_user_object_v2 {
48 bool locked_data_collection;
47 - RRDSET_STREAM_BUFFER stream_buffer;
49 + RRDSET_STREAM_BUFFER stream_buffer; // sender capabilities in this
50 time_t update_every;
51 time_t end_time;
52 time_t wall_clock_time;
collectors/proc.plugin/ipc.c
+4 -4
@@ -212,7 +212,7 @@ int ipc_msq_get_info(char *msg_filename, struct message_queue **message_queue_ro
212 // find the id in the linked list or create a new structure
213 int found = 0;
214
215 - unsigned long long id = str2ull(procfile_lineword(ff, l, 1));
215 + unsigned long long id = str2ull(procfile_lineword(ff, l, 1), NULL);
216 for(msq = *message_queue_root; msq ; msq = msq->next) {
217 if(unlikely(id == msq->id)) {
218 found = 1;
@@ -227,8 +227,8 @@ int ipc_msq_get_info(char *msg_filename, struct message_queue **message_queue_ro
227 msq->id = id;
228 }
229
230 - msq->messages = str2ull(procfile_lineword(ff, l, 4));
231 - msq->bytes = str2ull(procfile_lineword(ff, l, 3));
230 + msq->messages = str2ull(procfile_lineword(ff, l, 4), NULL);
231 + msq->bytes = str2ull(procfile_lineword(ff, l, 3), NULL);
232 msq->found = 1;
233 }
234
@@ -268,7 +268,7 @@ int ipc_shm_get_info(char *shm_filename, struct shm_stats *shm) {
268 }
269
270 shm->segments++;
271 - shm->bytes += str2ull(procfile_lineword(ff, l, 3));
271 + shm->bytes += str2ull(procfile_lineword(ff, l, 3), NULL);
272 }
273
274 return 0;
collectors/proc.plugin/proc_diskstats.c
+17 -17
@@ -993,35 +993,35 @@ int do_proc_diskstats(int update_every, usec_t dt) {
993
994 // # of reads completed # of writes completed
995 // This is the total number of reads or writes completed successfully.
996 - reads = str2ull(procfile_lineword(ff, l, 3)); // rd_ios
997 - writes = str2ull(procfile_lineword(ff, l, 7)); // wr_ios
996 + reads = str2ull(procfile_lineword(ff, l, 3), NULL); // rd_ios
997 + writes = str2ull(procfile_lineword(ff, l, 7), NULL); // wr_ios
998
999 // # of reads merged # of writes merged
1000 // Reads and writes which are adjacent to each other may be merged for
1001 // efficiency. Thus two 4K reads may become one 8K read before it is
1002 // ultimately handed to the disk, and so it will be counted (and queued)
1003 - mreads = str2ull(procfile_lineword(ff, l, 4)); // rd_merges_or_rd_sec
1004 - mwrites = str2ull(procfile_lineword(ff, l, 8)); // wr_merges
1003 + mreads = str2ull(procfile_lineword(ff, l, 4), NULL); // rd_merges_or_rd_sec
1004 + mwrites = str2ull(procfile_lineword(ff, l, 8), NULL); // wr_merges
1005
1006 // # of sectors read # of sectors written
1007 // This is the total number of sectors read or written successfully.
1008 - readsectors = str2ull(procfile_lineword(ff, l, 5)); // rd_sec_or_wr_ios
1009 - writesectors = str2ull(procfile_lineword(ff, l, 9)); // wr_sec
1008 + readsectors = str2ull(procfile_lineword(ff, l, 5), NULL); // rd_sec_or_wr_ios
1009 + writesectors = str2ull(procfile_lineword(ff, l, 9), NULL); // wr_sec
1010
1011 // # of milliseconds spent reading # of milliseconds spent writing
1012 // This is the total number of milliseconds spent by all reads or writes (as
1013 // measured from __make_request() to end_that_request_last()).
1014 - readms = str2ull(procfile_lineword(ff, l, 6)); // rd_ticks_or_wr_sec
1015 - writems = str2ull(procfile_lineword(ff, l, 10)); // wr_ticks
1014 + readms = str2ull(procfile_lineword(ff, l, 6), NULL); // rd_ticks_or_wr_sec
1015 + writems = str2ull(procfile_lineword(ff, l, 10), NULL); // wr_ticks
1016
1017 // # of I/Os currently in progress
1018 // The only field that should go to zero. Incremented as requests are
1019 // given to appropriate struct request_queue and decremented as they finish.
1020 - queued_ios = str2ull(procfile_lineword(ff, l, 11)); // ios_pgr
1020 + queued_ios = str2ull(procfile_lineword(ff, l, 11), NULL); // ios_pgr
1021
1022 // # of milliseconds spent doing I/Os
1023 // This field increases so long as field queued_ios is nonzero.
1024 - busy_ms = str2ull(procfile_lineword(ff, l, 12)); // tot_ticks
1024 + busy_ms = str2ull(procfile_lineword(ff, l, 12), NULL); // tot_ticks
1025
1026 // weighted # of milliseconds spent doing I/Os
1027 // This field is incremented at each I/O start, I/O completion, I/O
@@ -1029,27 +1029,27 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1029 // (field queued_ios) times the number of milliseconds spent doing I/O since the
1030 // last update of this field. This can provide an easy measure of both
1031 // I/O completion time and the backlog that may be accumulating.
1032 - backlog_ms = str2ull(procfile_lineword(ff, l, 13)); // rq_ticks
1032 + backlog_ms = str2ull(procfile_lineword(ff, l, 13), NULL); // rq_ticks
1033
1034 if (unlikely(words > 13)) {
1035 do_dc_stats = 1;
1036
1037 // # of discards completed
1038 // This is the total number of discards completed successfully.
1039 - discards = str2ull(procfile_lineword(ff, l, 14)); // dc_ios
1039 + discards = str2ull(procfile_lineword(ff, l, 14), NULL); // dc_ios
1040
1041 // # of discards merged
1042 // See the description of mreads/mwrites
1043 - mdiscards = str2ull(procfile_lineword(ff, l, 15)); // dc_merges
1043 + mdiscards = str2ull(procfile_lineword(ff, l, 15), NULL); // dc_merges
1044
1045 // # of sectors discarded
1046 // This is the total number of sectors discarded successfully.
1047 - discardsectors = str2ull(procfile_lineword(ff, l, 16)); // dc_sec
1047 + discardsectors = str2ull(procfile_lineword(ff, l, 16), NULL); // dc_sec
1048
1049 // # of milliseconds spent discarding
1050 // This is the total number of milliseconds spent by all discards (as
1051 // measured from __make_request() to end_that_request_last()).
1052 - discardms = str2ull(procfile_lineword(ff, l, 17)); // dc_ticks
1052 + discardms = str2ull(procfile_lineword(ff, l, 17), NULL); // dc_ticks
1053 }
1054
1055 if (unlikely(words > 17)) {
@@ -1059,10 +1059,10 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1059 // These values increment when an flush I/O request completes.
1060 // Block layer combines flush requests and executes at most one at a time.
1061 // This counts flush requests executed by disk. Not tracked for partitions.
1062 - flushes = str2ull(procfile_lineword(ff, l, 18)); // fl_ios
1062 + flushes = str2ull(procfile_lineword(ff, l, 18), NULL); // fl_ios
1063
1064 // total wait time for flush requests
1065 - flushms = str2ull(procfile_lineword(ff, l, 19)); // fl_ticks
1065 + flushms = str2ull(procfile_lineword(ff, l, 19), NULL); // fl_ticks
1066 }
1067
1068 // --------------------------------------------------------------------------
collectors/proc.plugin/proc_interrupts.c
+1 -1
@@ -120,7 +120,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
120 int c;
121 for(c = 0; c < cpus ;c++) {
122 if(likely((c + 1) < (int)words))
123 - irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t)(c + 1)));
123 + irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t) (c + 1)), NULL);
124 else
125 irr->cpu[c].value = 0;
126
collectors/proc.plugin/proc_loadavg.c
+1 -1
@@ -45,7 +45,7 @@ int do_proc_loadavg(int update_every, usec_t dt) {
45 double load15 = strtod(procfile_lineword(ff, 0, 2), NULL);
46
47 //unsigned long long running_processes = str2ull(procfile_lineword(ff, 0, 3));
48 - unsigned long long active_processes = str2ull(procfile_lineword(ff, 0, 4));
48 + unsigned long long active_processes = str2ull(procfile_lineword(ff, 0, 4), NULL);
49
50 //get system pid_max
51 unsigned long long max_processes = get_system_pid_max();
collectors/proc.plugin/proc_mdstat.c
+3 -3
@@ -231,8 +231,8 @@ int do_proc_mdstat(int update_every, usec_t dt)
231 continue;
232 }
233
234 - raid->inuse_disks = str2ull(str_inuse);
235 - raid->total_disks = str2ull(str_total);
234 + raid->inuse_disks = str2ull(str_inuse, NULL);
235 + raid->total_disks = str2ull(str_total, NULL);
236 raid->failed_disks = raid->total_disks - raid->inuse_disks;
237 }
238
@@ -300,7 +300,7 @@ int do_proc_mdstat(int update_every, usec_t dt)
300 word += 6; // skip leading "speed="
301
302 if (likely(s > word))
303 - raid->speed = str2ull(word);
303 + raid->speed = str2ull(word, NULL);
304 }
305 }
306
collectors/proc.plugin/proc_net_rpc_nfs.c
+10 -10
@@ -187,10 +187,10 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
187 continue;
188 }
189
190 - net_count = str2ull(procfile_lineword(ff, l, 1));
191 - net_udp_count = str2ull(procfile_lineword(ff, l, 2));
192 - net_tcp_count = str2ull(procfile_lineword(ff, l, 3));
193 - net_tcp_connections = str2ull(procfile_lineword(ff, l, 4));
190 + net_count = str2ull(procfile_lineword(ff, l, 1), NULL);
191 + net_udp_count = str2ull(procfile_lineword(ff, l, 2), NULL);
192 + net_tcp_count = str2ull(procfile_lineword(ff, l, 3), NULL);
193 + net_tcp_connections = str2ull(procfile_lineword(ff, l, 4), NULL);
194
195 unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
196 if(sum == 0ULL) do_net = -1;
@@ -202,9 +202,9 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
202 continue;
203 }
204
205 - rpc_calls = str2ull(procfile_lineword(ff, l, 1));
206 - rpc_retransmits = str2ull(procfile_lineword(ff, l, 2));
207 - rpc_auth_refresh = str2ull(procfile_lineword(ff, l, 3));
205 + rpc_calls = str2ull(procfile_lineword(ff, l, 1), NULL);
206 + rpc_retransmits = str2ull(procfile_lineword(ff, l, 2), NULL);
207 + rpc_auth_refresh = str2ull(procfile_lineword(ff, l, 3), NULL);
208
209 unsigned long long sum = rpc_calls + rpc_retransmits + rpc_auth_refresh;
210 if(sum == 0ULL) do_rpc = -1;
@@ -217,7 +217,7 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
217 unsigned long long sum = 0;
218 unsigned int i, j;
219 for(i = 0, j = 2; j < words && nfs_proc2_values[i].name[0] ; i++, j++) {
220 - nfs_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j));
220 + nfs_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
221 nfs_proc2_values[i].present = 1;
222 sum += nfs_proc2_values[i].value;
223 }
@@ -238,7 +238,7 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
238 unsigned long long sum = 0;
239 unsigned int i, j;
240 for(i = 0, j = 2; j < words && nfs_proc3_values[i].name[0] ; i++, j++) {
241 - nfs_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j));
241 + nfs_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
242 nfs_proc3_values[i].present = 1;
243 sum += nfs_proc3_values[i].value;
244 }
@@ -259,7 +259,7 @@ int do_proc_net_rpc_nfs(int update_every, usec_t dt) {
259 unsigned long long sum = 0;
260 unsigned int i, j;
261 for(i = 0, j = 2; j < words && nfs_proc4_values[i].name[0] ; i++, j++) {
262 - nfs_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j));
262 + nfs_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
263 nfs_proc4_values[i].present = 1;
264 sum += nfs_proc4_values[i].value;
265 }
collectors/proc.plugin/proc_net_rpc_nfsd.c
+19 -19
@@ -286,9 +286,9 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
286 continue;
287 }
288
289 - rc_hits = str2ull(procfile_lineword(ff, l, 1));
290 - rc_misses = str2ull(procfile_lineword(ff, l, 2));
291 - rc_nocache = str2ull(procfile_lineword(ff, l, 3));
289 + rc_hits = str2ull(procfile_lineword(ff, l, 1), NULL);
290 + rc_misses = str2ull(procfile_lineword(ff, l, 2), NULL);
291 + rc_nocache = str2ull(procfile_lineword(ff, l, 3), NULL);
292
293 unsigned long long sum = rc_hits + rc_misses + rc_nocache;
294 if(sum == 0ULL) do_rc = -1;
@@ -300,7 +300,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
300 continue;
301 }
302
303 - fh_stale = str2ull(procfile_lineword(ff, l, 1));
303 + fh_stale = str2ull(procfile_lineword(ff, l, 1), NULL);
304
305 // other file handler metrics were never used and are always zero
306
@@ -313,8 +313,8 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
313 continue;
314 }
315
316 - io_read = str2ull(procfile_lineword(ff, l, 1));
317 - io_write = str2ull(procfile_lineword(ff, l, 2));
316 + io_read = str2ull(procfile_lineword(ff, l, 1), NULL);
317 + io_write = str2ull(procfile_lineword(ff, l, 2), NULL);
318
319 unsigned long long sum = io_read + io_write;
320 if(sum == 0ULL) do_io = -1;
@@ -326,7 +326,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
326 continue;
327 }
328
329 - th_threads = str2ull(procfile_lineword(ff, l, 1));
329 + th_threads = str2ull(procfile_lineword(ff, l, 1), NULL);
330
331 // thread histogram has been disabled since 2009 (kernel 2.6.30)
332 // https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=8bbfa9f3889b643fc7de82c0c761ef17097f8faf
@@ -339,10 +339,10 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
339 continue;
340 }
341
342 - net_count = str2ull(procfile_lineword(ff, l, 1));
343 - net_udp_count = str2ull(procfile_lineword(ff, l, 2));
344 - net_tcp_count = str2ull(procfile_lineword(ff, l, 3));
345 - net_tcp_connections = str2ull(procfile_lineword(ff, l, 4));
342 + net_count = str2ull(procfile_lineword(ff, l, 1), NULL);
343 + net_udp_count = str2ull(procfile_lineword(ff, l, 2), NULL);
344 + net_tcp_count = str2ull(procfile_lineword(ff, l, 3), NULL);
345 + net_tcp_connections = str2ull(procfile_lineword(ff, l, 4), NULL);
346
347 unsigned long long sum = net_count + net_udp_count + net_tcp_count + net_tcp_connections;
348 if(sum == 0ULL) do_net = -1;
@@ -354,10 +354,10 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
354 continue;
355 }
356
357 - rpc_calls = str2ull(procfile_lineword(ff, l, 1));
358 - rpc_bad_format = str2ull(procfile_lineword(ff, l, 3));
359 - rpc_bad_auth = str2ull(procfile_lineword(ff, l, 4));
360 - rpc_bad_client = str2ull(procfile_lineword(ff, l, 5));
357 + rpc_calls = str2ull(procfile_lineword(ff, l, 1), NULL);
358 + rpc_bad_format = str2ull(procfile_lineword(ff, l, 3), NULL);
359 + rpc_bad_auth = str2ull(procfile_lineword(ff, l, 4), NULL);
360 + rpc_bad_client = str2ull(procfile_lineword(ff, l, 5), NULL);
361
362 unsigned long long sum = rpc_calls + rpc_bad_format + rpc_bad_auth + rpc_bad_client;
363 if(sum == 0ULL) do_rpc = -1;
@@ -370,7 +370,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
370 unsigned long long sum = 0;
371 unsigned int i, j;
372 for(i = 0, j = 2; j < words && nfsd_proc2_values[i].name[0] ; i++, j++) {
373 - nfsd_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j));
373 + nfsd_proc2_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
374 nfsd_proc2_values[i].present = 1;
375 sum += nfsd_proc2_values[i].value;
376 }
@@ -391,7 +391,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
391 unsigned long long sum = 0;
392 unsigned int i, j;
393 for(i = 0, j = 2; j < words && nfsd_proc3_values[i].name[0] ; i++, j++) {
394 - nfsd_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j));
394 + nfsd_proc3_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
395 nfsd_proc3_values[i].present = 1;
396 sum += nfsd_proc3_values[i].value;
397 }
@@ -412,7 +412,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
412 unsigned long long sum = 0;
413 unsigned int i, j;
414 for(i = 0, j = 2; j < words && nfsd_proc4_values[i].name[0] ; i++, j++) {
415 - nfsd_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j));
415 + nfsd_proc4_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
416 nfsd_proc4_values[i].present = 1;
417 sum += nfsd_proc4_values[i].value;
418 }
@@ -433,7 +433,7 @@ int do_proc_net_rpc_nfsd(int update_every, usec_t dt) {
433 unsigned long long sum = 0;
434 unsigned int i, j;
435 for(i = 0, j = 2; j < words && nfsd4_ops_values[i].name[0] ; i++, j++) {
436 - nfsd4_ops_values[i].value = str2ull(procfile_lineword(ff, l, j));
436 + nfsd4_ops_values[i].value = str2ull(procfile_lineword(ff, l, j), NULL);
437 nfsd4_ops_values[i].present = 1;
438 sum += nfsd4_ops_values[i].value;
439 }
collectors/proc.plugin/proc_pagetypeinfo.c
+2 -2
@@ -188,7 +188,7 @@ int do_proc_pagetypeinfo(int update_every, usec_t dt) {
188 pgl->type = typename;
189 pgl->zone = zonename;
190 for (o = 0; o < pageorders_cnt; o++)
191 - pgl->free_pages_size[o] = str2uint64_t(procfile_lineword(ff, l, o+6)) * 1 << o;
191 + pgl->free_pages_size[o] = str2uint64_t(procfile_lineword(ff, l, o + 6), NULL) * 1 << o;
192
193 p++;
194 }
@@ -302,7 +302,7 @@ int do_proc_pagetypeinfo(int update_every, usec_t dt) {
302 systemorders[o].size = 0;
303
304 // Update orders of the current line
305 - pagelines[p].free_pages_size[o] = str2uint64_t(procfile_lineword(ff, l, o+6)) * 1 << o;
305 + pagelines[p].free_pages_size[o] = str2uint64_t(procfile_lineword(ff, l, o + 6), NULL) * 1 << o;
306
307 // Update sum by order
308 systemorders[o].size += pagelines[p].free_pages_size[o];
collectors/proc.plugin/proc_pressure.c
+1 -1
@@ -114,7 +114,7 @@ static void proc_pressure_do_resource(procfile *ff, int res_idx, int some) {
114 pcs->total_time.rdtotal = rrddim_add(pcs->total_time.st, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
115 }
116
117 - pcs->total_time.value_total = str2ull(procfile_lineword(ff, some ? 0 : 1, 8)) / 1000;
117 + pcs->total_time.value_total = str2ull(procfile_lineword(ff, some ? 0 : 1, 8), NULL) / 1000;
118 }
119
120 static void proc_pressure_do_resource_some(procfile *ff, int res_idx) {
collectors/proc.plugin/proc_softirqs.c
+1 -1
@@ -113,7 +113,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
113 int c;
114 for(c = 0; c < cpus ;c++) {
115 if(likely((c + 1) < (int)words))
116 - irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t)(c + 1)));
116 + irr->cpu[c].value = str2ull(procfile_lineword(ff, l, (uint32_t) (c + 1)), NULL);
117 else
118 irr->cpu[c].value = 0;
119
collectors/proc.plugin/proc_stat.c
+19 -19
@@ -182,8 +182,8 @@ static int read_per_core_time_in_state_files(struct cpu_chart *all_cpu_charts, s
182 collector_error("Cannot read time_in_state line. Expected 2 params, read %zu.", words);
183 continue;
184 }
185 - frequency = str2ull(procfile_lineword(tsf->ff, l, 0));
186 - ticks = str2ull(procfile_lineword(tsf->ff, l, 1));
185 + frequency = str2ull(procfile_lineword(tsf->ff, l, 0), NULL);
186 + ticks = str2ull(procfile_lineword(tsf->ff, l, 1), NULL);
187
188 // It is assumed that frequencies are static and sorted
189 ticks_since_last = ticks - tsf->last_ticks[l].ticks;
@@ -330,7 +330,7 @@ static int read_schedstat(char *schedstat_filename, struct per_core_cpuidle_char
330 cpuidle_charts_len = cores_found;
331 }
332
333 - cpuidle_charts[core].active_time = str2ull(procfile_lineword(ff, l, 7)) / 1000;
333 + cpuidle_charts[core].active_time = str2ull(procfile_lineword(ff, l, 7), NULL) / 1000;
334 }
335 }
336
@@ -597,19 +597,19 @@ int do_proc_stat(int update_every, usec_t dt) {
597 unsigned long long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0, guest_nice = 0;
598
599 id = row_key;
600 - user = str2ull(procfile_lineword(ff, l, 1));
601 - nice = str2ull(procfile_lineword(ff, l, 2));
602 - system = str2ull(procfile_lineword(ff, l, 3));
603 - idle = str2ull(procfile_lineword(ff, l, 4));
604 - iowait = str2ull(procfile_lineword(ff, l, 5));
605 - irq = str2ull(procfile_lineword(ff, l, 6));
606 - softirq = str2ull(procfile_lineword(ff, l, 7));
607 - steal = str2ull(procfile_lineword(ff, l, 8));
608 -
609 - guest = str2ull(procfile_lineword(ff, l, 9));
600 + user = str2ull(procfile_lineword(ff, l, 1), NULL);
601 + nice = str2ull(procfile_lineword(ff, l, 2), NULL);
602 + system = str2ull(procfile_lineword(ff, l, 3), NULL);
603 + idle = str2ull(procfile_lineword(ff, l, 4), NULL);
604 + iowait = str2ull(procfile_lineword(ff, l, 5), NULL);
605 + irq = str2ull(procfile_lineword(ff, l, 6), NULL);
606 + softirq = str2ull(procfile_lineword(ff, l, 7), NULL);
607 + steal = str2ull(procfile_lineword(ff, l, 8), NULL);
608 +
609 + guest = str2ull(procfile_lineword(ff, l, 9), NULL);
610 user -= guest;
611
612 - guest_nice = str2ull(procfile_lineword(ff, l, 10));
612 + guest_nice = str2ull(procfile_lineword(ff, l, 10), NULL);
613 nice -= guest_nice;
614
615 char *title, *type, *context, *family;
@@ -739,7 +739,7 @@ int do_proc_stat(int update_every, usec_t dt) {
739 if(likely(do_interrupts)) {
740 static RRDSET *st_intr = NULL;
741 static RRDDIM *rd_interrupts = NULL;
742 - unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
742 + unsigned long long value = str2ull(procfile_lineword(ff, l, 1), NULL);
743
744 if(unlikely(!st_intr)) {
745 st_intr = rrdset_create_localhost(
@@ -770,7 +770,7 @@ int do_proc_stat(int update_every, usec_t dt) {
770 if(likely(do_context)) {
771 static RRDSET *st_ctxt = NULL;
772 static RRDDIM *rd_switches = NULL;
773 - unsigned long long value = str2ull(procfile_lineword(ff, l, 1));
773 + unsigned long long value = str2ull(procfile_lineword(ff, l, 1), NULL);
774
775 if(unlikely(!st_ctxt)) {
776 st_ctxt = rrdset_create_localhost(
@@ -796,13 +796,13 @@ int do_proc_stat(int update_every, usec_t dt) {
796 }
797 }
798 else if(unlikely(hash == hash_processes && !processes && strcmp(row_key, "processes") == 0)) {
799 - processes = str2ull(procfile_lineword(ff, l, 1));
799 + processes = str2ull(procfile_lineword(ff, l, 1), NULL);
800 }
801 else if(unlikely(hash == hash_procs_running && !running && strcmp(row_key, "procs_running") == 0)) {
802 - running = str2ull(procfile_lineword(ff, l, 1));
802 + running = str2ull(procfile_lineword(ff, l, 1), NULL);
803 }
804 else if(unlikely(hash == hash_procs_blocked && !blocked && strcmp(row_key, "procs_blocked") == 0)) {
805 - blocked = str2ull(procfile_lineword(ff, l, 1));
805 + blocked = str2ull(procfile_lineword(ff, l, 1), NULL);
806 }
807 }
808
collectors/proc.plugin/proc_sys_kernel_random_entropy_avail.c
+1 -1
@@ -17,7 +17,7 @@ int do_proc_sys_kernel_random_entropy_avail(int update_every, usec_t dt) {
17 ff = procfile_readall(ff);
18 if(unlikely(!ff)) return 0; // we return 0, so that we will retry to open it next time
19
20 - unsigned long long entropy = str2ull(procfile_lineword(ff, 0, 0));
20 + unsigned long long entropy = str2ull(procfile_lineword(ff, 0, 0), NULL);
21
22 static RRDSET *st = NULL;
23 static RRDDIM *rd = NULL;
collectors/proc.plugin/sys_block_zram.c
+7 -7
@@ -191,13 +191,13 @@ static inline int read_mm_stat(procfile *ff, MM_STAT *stats) {
191 return -1;
192 }
193
194 - stats->orig_data_size = str2ull(procfile_word(ff, 0));
195 - stats->compr_data_size = str2ull(procfile_word(ff, 1));
196 - stats->mem_used_total = str2ull(procfile_word(ff, 2));
197 - stats->mem_limit = str2ull(procfile_word(ff, 3));
198 - stats->mem_used_max = str2ull(procfile_word(ff, 4));
199 - stats->same_pages = str2ull(procfile_word(ff, 5));
200 - stats->pages_compacted = str2ull(procfile_word(ff, 6));
194 + stats->orig_data_size = str2ull(procfile_word(ff, 0), NULL);
195 + stats->compr_data_size = str2ull(procfile_word(ff, 1), NULL);
196 + stats->mem_used_total = str2ull(procfile_word(ff, 2), NULL);
197 + stats->mem_limit = str2ull(procfile_word(ff, 3), NULL);
198 + stats->mem_used_max = str2ull(procfile_word(ff, 4), NULL);
199 + stats->same_pages = str2ull(procfile_word(ff, 5), NULL);
200 + stats->pages_compacted = str2ull(procfile_word(ff, 6), NULL);
201 return 0;
202 }
203
collectors/proc.plugin/sys_class_infiniband.c
+2 -2
@@ -475,8 +475,8 @@ int do_sys_class_infiniband(int update_every, usec_t dt)
475 char *buffer_width = strstr(buffer_rate, "(");
476 buffer_width++;
477 // str2ull will stop on first non-decimal value
478 - p->speed = str2ull(buffer_rate);
479 - p->width = str2ull(buffer_width);
478 + p->speed = str2ull(buffer_rate, NULL);
479 + p->width = str2ull(buffer_width, NULL);
480 }
481
482 if (!p->discovered)
collectors/proc.plugin/sys_class_power_supply.c
+2 -2
@@ -263,7 +263,7 @@ int do_sys_class_power_supply(int update_every, usec_t dt) {
263 }
264 else {
265 buffer[r] = '\0';
266 - ps->capacity->value = str2ull(buffer);
266 + ps->capacity->value = str2ull(buffer, NULL);
267
268 if(unlikely(!keep_fds_open)) {
269 close(ps->capacity->fd);
@@ -307,7 +307,7 @@ int do_sys_class_power_supply(int update_every, usec_t dt) {
307 break;
308 }
309 buffer[r] = '\0';
310 - pd->value = str2ull(buffer);
310 + pd->value = str2ull(buffer, NULL);
311
312 if(unlikely(!keep_fds_open)) {
313 close(pd->fd);
collectors/proc.plugin/sys_devices_system_edac_mc.c
+2 -2
@@ -97,7 +97,7 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
97 if(unlikely(!m->ce_ff || procfile_lines(m->ce_ff) < 1 || procfile_linewords(m->ce_ff, 0) < 1))
98 continue;
99
100 - m->ce_count = str2ull(procfile_lineword(m->ce_ff, 0, 0));
100 + m->ce_count = str2ull(procfile_lineword(m->ce_ff, 0, 0), NULL);
101 ce_sum += m->ce_count;
102 m->ce_updated = 1;
103 }
@@ -119,7 +119,7 @@ int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
119 if(unlikely(!m->ue_ff || procfile_lines(m->ue_ff) < 1 || procfile_linewords(m->ue_ff, 0) < 1))
120 continue;
121
122 - m->ue_count = str2ull(procfile_lineword(m->ue_ff, 0, 0));
122 + m->ue_count = str2ull(procfile_lineword(m->ue_ff, 0, 0), NULL);
123 ue_sum += m->ue_count;
124 m->ue_updated = 1;
125 }
collectors/proc.plugin/sys_kernel_mm_ksm.c
+4 -4
@@ -68,19 +68,19 @@ int do_sys_kernel_mm_ksm(int update_every, usec_t dt) {
68
69 ff_pages_shared = procfile_readall(ff_pages_shared);
70 if(unlikely(!ff_pages_shared)) return 0; // we return 0, so that we will retry to open it next time
71 - pages_shared = str2ull(procfile_lineword(ff_pages_shared, 0, 0));
71 + pages_shared = str2ull(procfile_lineword(ff_pages_shared, 0, 0), NULL);
72
73 ff_pages_sharing = procfile_readall(ff_pages_sharing);
74 if(unlikely(!ff_pages_sharing)) return 0; // we return 0, so that we will retry to open it next time
75 - pages_sharing = str2ull(procfile_lineword(ff_pages_sharing, 0, 0));
75 + pages_sharing = str2ull(procfile_lineword(ff_pages_sharing, 0, 0), NULL);
76
77 ff_pages_unshared = procfile_readall(ff_pages_unshared);
78 if(unlikely(!ff_pages_unshared)) return 0; // we return 0, so that we will retry to open it next time
79 - pages_unshared = str2ull(procfile_lineword(ff_pages_unshared, 0, 0));
79 + pages_unshared = str2ull(procfile_lineword(ff_pages_unshared, 0, 0), NULL);
80
81 ff_pages_volatile = procfile_readall(ff_pages_volatile);
82 if(unlikely(!ff_pages_volatile)) return 0; // we return 0, so that we will retry to open it next time
83 - pages_volatile = str2ull(procfile_lineword(ff_pages_volatile, 0, 0));
83 + pages_volatile = str2ull(procfile_lineword(ff_pages_volatile, 0, 0), NULL);
84
85 //ff_pages_to_scan = procfile_readall(ff_pages_to_scan);
86 //if(unlikely(!ff_pages_to_scan)) return 0; // we return 0, so that we will retry to open it next time
collectors/slabinfo.plugin/slabinfo.c
+13 -13
@@ -171,19 +171,19 @@ struct slabinfo *read_file_slabinfo() {
171 char *name = procfile_lineword(ff, l, 0);
172 struct slabinfo *s = get_slabstruct(name);
173
174 - s->active_objs = str2uint64_t(procfile_lineword(ff, l, 1));
175 - s->num_objs = str2uint64_t(procfile_lineword(ff, l, 2));
176 - s->obj_size = str2uint64_t(procfile_lineword(ff, l, 3));
177 - s->obj_per_slab = str2uint64_t(procfile_lineword(ff, l, 4));
178 - s->pages_per_slab = str2uint64_t(procfile_lineword(ff, l, 5));
179 -
180 - s->tune_limit = str2uint64_t(procfile_lineword(ff, l, 7));
181 - s->tune_batchcnt = str2uint64_t(procfile_lineword(ff, l, 8));
182 - s->tune_shared_factor = str2uint64_t(procfile_lineword(ff, l, 9));
183 -
184 - s->data_active_slabs = str2uint64_t(procfile_lineword(ff, l, 11));
185 - s->data_num_slabs = str2uint64_t(procfile_lineword(ff, l, 12));
186 - s->data_shared_avail = str2uint64_t(procfile_lineword(ff, l, 13));
174 + s->active_objs = str2uint64_t(procfile_lineword(ff, l, 1), NULL);
175 + s->num_objs = str2uint64_t(procfile_lineword(ff, l, 2), NULL);
176 + s->obj_size = str2uint64_t(procfile_lineword(ff, l, 3), NULL);
177 + s->obj_per_slab = str2uint64_t(procfile_lineword(ff, l, 4), NULL);
178 + s->pages_per_slab = str2uint64_t(procfile_lineword(ff, l, 5), NULL);
179 +
180 + s->tune_limit = str2uint64_t(procfile_lineword(ff, l, 7), NULL);
181 + s->tune_batchcnt = str2uint64_t(procfile_lineword(ff, l, 8), NULL);
182 + s->tune_shared_factor = str2uint64_t(procfile_lineword(ff, l, 9), NULL);
183 +
184 + s->data_active_slabs = str2uint64_t(procfile_lineword(ff, l, 11), NULL);
185 + s->data_num_slabs = str2uint64_t(procfile_lineword(ff, l, 12), NULL);
186 + s->data_shared_avail = str2uint64_t(procfile_lineword(ff, l, 13), NULL);
187
188 uint32_t memperslab = s->pages_per_slab * slab_pagesize;
189 // Internal fragmentation: loss per slab, due to objects not being a multiple of pagesize
collectors/tc.plugin/plugin_tc.c
+5 -5
@@ -1065,7 +1065,7 @@ void *tc_main(void *ptr) {
1065
1066 // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
1067 if(likely(words[1] && *words[1])) {
1068 - class->bytes = str2ull(words[1]);
1068 + class->bytes = str2ull(words[1], NULL);
1069 class->updated = true;
1070 }
1071 else {
@@ -1073,10 +1073,10 @@ void *tc_main(void *ptr) {
1073 }
1074
1075 if(likely(words[3] && *words[3]))
1076 - class->packets = str2ull(words[3]);
1076 + class->packets = str2ull(words[3], NULL);
1077
1078 if(likely(words[6] && *words[6]))
1079 - class->dropped = str2ull(words[6]);
1079 + class->dropped = str2ull(words[6], NULL);
1080
1081 //if(likely(words[8] && *words[8]))
1082 // class->overlimits = str2ull(words[8]);
@@ -1102,10 +1102,10 @@ void *tc_main(void *ptr) {
1102
1103 // debug(D_TC_LOOP, "TOKENS line '%s'", words[1]);
1104 if(likely(words[1] && *words[1]))
1105 - class->tokens = str2ull(words[1]);
1105 + class->tokens = str2ull(words[1], NULL);
1106
1107 if(likely(words[3] && *words[3]))
1108 - class->ctokens = str2ull(words[3]);
1108 + class->ctokens = str2ull(words[3], NULL);
1109 }
1110 else if(unlikely(device && first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0)) {
1111 worker_is_busy(WORKER_TC_SETDEVICENAME);
daemon/analytics.c
+43 -45
@@ -140,14 +140,6 @@ void analytics_set_data_str(char **name, char *value)
140 analytics_data.data_length += strlen(*name);
141 }
142
143 -/*
144 - * Get data, used by web api v1
145 - */
146 -void analytics_get_data(char *name, BUFFER *wb)
147 -{
148 - buffer_strcat(wb, name);
149 -}
150 -
143 /*
144 * Log hits on the allmetrics page, with prometheus parameter
145 */
@@ -155,8 +147,8 @@ void analytics_log_prometheus(void)
147 {
148 if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.prometheus_hits < ANALYTICS_MAX_PROMETHEUS_HITS)) {
149 analytics_data.prometheus_hits++;
158 - char b[7];
159 - snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
150 + char b[21];
151 + snprintfz(b, 20, "%zu", analytics_data.prometheus_hits);
152 analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
153 }
154 }
@@ -168,8 +160,8 @@ void analytics_log_shell(void)
160 {
161 if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.shell_hits < ANALYTICS_MAX_SHELL_HITS)) {
162 analytics_data.shell_hits++;
171 - char b[7];
172 - snprintfz(b, 6, "%d", analytics_data.shell_hits);
163 + char b[21];
164 + snprintfz(b, 20, "%zu", analytics_data.shell_hits);
165 analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
166 }
167 }
@@ -181,8 +173,8 @@ void analytics_log_json(void)
173 {
174 if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.json_hits < ANALYTICS_MAX_JSON_HITS)) {
175 analytics_data.json_hits++;
184 - char b[7];
185 - snprintfz(b, 6, "%d", analytics_data.json_hits);
176 + char b[21];
177 + snprintfz(b, 20, "%zu", analytics_data.json_hits);
178 analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
179 }
180 }
@@ -194,8 +186,8 @@ void analytics_log_dashboard(void)
186 {
187 if (netdata_anonymous_statistics_enabled == 1 && likely(analytics_data.dashboard_hits < ANALYTICS_MAX_DASHBOARD_HITS)) {
188 analytics_data.dashboard_hits++;
197 - char b[7];
198 - snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
189 + char b[21];
190 + snprintfz(b, 20, "%zu", analytics_data.dashboard_hits);
191 analytics_set_data(&analytics_data.netdata_dashboard_used, b);
192 }
193 }
@@ -204,18 +196,18 @@ void analytics_log_dashboard(void)
196 * Called when setting the oom score
197 */
198 void analytics_report_oom_score(long long int score){
207 - char b[7];
208 - snprintfz(b, 6, "%d", (int)score);
199 + char b[21];
200 + snprintfz(b, 20, "%lld", score);
201 analytics_set_data(&analytics_data.netdata_config_oom_score, b);
202 }
203
204 void analytics_mirrored_hosts(void)
205 {
206 RRDHOST *host;
215 - int count = 0;
216 - int reachable = 0;
217 - int unreachable = 0;
218 - char b[11];
207 + size_t count = 0;
208 + size_t reachable = 0;
209 + size_t unreachable = 0;
210 + char b[21];
211
212 rrd_rdlock();
213 rrdhost_foreach_read(host)
@@ -229,11 +221,11 @@ void analytics_mirrored_hosts(void)
221 }
222 rrd_unlock();
223
232 - snprintfz(b, 10, "%d", count);
224 + snprintfz(b, 20, "%zu", count);
225 analytics_set_data(&analytics_data.netdata_mirrored_host_count, b);
234 - snprintfz(b, 10, "%d", reachable);
226 + snprintfz(b, 20, "%zu", reachable);
227 analytics_set_data(&analytics_data.netdata_mirrored_hosts_reachable, b);
236 - snprintfz(b, 10, "%d", unreachable);
228 + snprintfz(b, 20, "%zu", unreachable);
229 analytics_set_data(&analytics_data.netdata_mirrored_hosts_unreachable, b);
230 }
231
@@ -303,8 +295,8 @@ void analytics_collectors(void)
295 analytics_set_data(&analytics_data.netdata_collectors, (char *)buffer_tostring(ap.both));
296
297 {
306 - char b[7];
307 - snprintfz(b, 6, "%d", ap.c);
298 + char b[21];
299 + snprintfz(b, 20, "%d", ap.c);
300 analytics_set_data(&analytics_data.netdata_collectors_count, b);
301 }
302
@@ -396,15 +388,16 @@ void analytics_https(void)
388 void analytics_charts(void)
389 {
390 RRDSET *st;
399 - int c = 0;
391 + size_t c = 0;
392
393 rrdset_foreach_read(st, localhost)
394 if(rrdset_is_available_for_viewers(st)) c++;
395 rrdset_foreach_done(st);
396
397 + analytics_data.charts_count = c;
398 {
406 - char b[7];
407 - snprintfz(b, 6, "%d", c);
399 + char b[21];
400 + snprintfz(b, 20, "%zu", c);
401 analytics_set_data(&analytics_data.netdata_charts_count, b);
402 }
403 }
@@ -412,7 +405,7 @@ void analytics_charts(void)
405 void analytics_metrics(void)
406 {
407 RRDSET *st;
415 - long int dimensions = 0;
408 + size_t dimensions = 0;
409 rrdset_foreach_read(st, localhost) {
410 if (rrdset_is_available_for_viewers(st)) {
411 RRDDIM *rd;
@@ -426,17 +419,18 @@ void analytics_metrics(void)
419 }
420 rrdset_foreach_done(st);
421
422 + analytics_data.metrics_count = dimensions;
423 {
430 - char b[7];
431 - snprintfz(b, 6, "%ld", dimensions);
424 + char b[21];
425 + snprintfz(b, 20, "%zu", dimensions);
426 analytics_set_data(&analytics_data.netdata_metrics_count, b);
427 }
428 }
429
430 void analytics_alarms(void)
431 {
438 - int alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
439 - char b[10];
432 + size_t alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
433 + char b[21];
434 RRDCALC *rc;
435 foreach_rrdcalc_in_rrdhost_read(localhost, rc) {
436 if (unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
@@ -455,11 +449,11 @@ void analytics_alarms(void)
449 }
450 foreach_rrdcalc_in_rrdhost_done(rc);
451
458 - snprintfz(b, 9, "%d", alarm_normal);
452 + snprintfz(b, 20, "%zu", alarm_normal);
453 analytics_set_data(&analytics_data.netdata_alarms_normal, b);
460 - snprintfz(b, 9, "%d", alarm_warn);
454 + snprintfz(b, 20, "%zu", alarm_warn);
455 analytics_set_data(&analytics_data.netdata_alarms_warning, b);
462 - snprintfz(b, 9, "%d", alarm_crit);
456 + snprintfz(b, 20, "%zu", alarm_crit);
457 analytics_set_data(&analytics_data.netdata_alarms_critical, b);
458 }
459
@@ -476,7 +470,8 @@ void analytics_misc(void)
470 analytics_set_data_str(&analytics_data.netdata_host_aclk_implementation, "");
471 #endif
472
479 - analytics_set_data(&analytics_data.netdata_config_exporting_enabled, appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, "enabled", CONFIG_BOOLEAN_NO) ? "true" : "false");
473 + analytics_data.exporting_enabled = appconfig_get_boolean(&exporting_config, CONFIG_SECTION_EXPORTING, "enabled", CONFIG_BOOLEAN_NO);
474 + analytics_set_data(&analytics_data.netdata_config_exporting_enabled, analytics_data.exporting_enabled ? "true" : "false");
475
476 analytics_set_data(&analytics_data.netdata_config_is_private_registry, "false");
477 analytics_set_data(&analytics_data.netdata_config_use_private_registry, "false");
@@ -539,20 +534,20 @@ void analytics_gather_mutable_meta_data(void)
534 freez(claim_id);
535
536 {
542 - char b[7];
543 - snprintfz(b, 6, "%d", analytics_data.prometheus_hits);
537 + char b[21];
538 + snprintfz(b, 20, "%zu", analytics_data.prometheus_hits);
539 analytics_set_data(&analytics_data.netdata_allmetrics_prometheus_used, b);
540
546 - snprintfz(b, 6, "%d", analytics_data.shell_hits);
541 + snprintfz(b, 20, "%zu", analytics_data.shell_hits);
542 analytics_set_data(&analytics_data.netdata_allmetrics_shell_used, b);
543
549 - snprintfz(b, 6, "%d", analytics_data.json_hits);
544 + snprintfz(b, 20, "%zu", analytics_data.json_hits);
545 analytics_set_data(&analytics_data.netdata_allmetrics_json_used, b);
546
552 - snprintfz(b, 6, "%d", analytics_data.dashboard_hits);
547 + snprintfz(b, 20, "%zu", analytics_data.dashboard_hits);
548 analytics_set_data(&analytics_data.netdata_dashboard_used, b);
549
555 - snprintfz(b, 6, "%zu", rrdhost_hosts_available());
550 + snprintfz(b, 20, "%zu", rrdhost_hosts_available());
551 analytics_set_data(&analytics_data.netdata_config_hosts_available, b);
552 }
553 }
@@ -894,6 +889,9 @@ void set_global_environment()
889 analytics_data.shell_hits = 0;
890 analytics_data.json_hits = 0;
891 analytics_data.dashboard_hits = 0;
892 + analytics_data.charts_count = 0;
893 + analytics_data.metrics_count = 0;
894 + analytics_data.exporting_enabled = false;
895
896 char *default_port = appconfig_get(&netdata_config, CONFIG_SECTION_WEB, "default port", NULL);
897 int clean = 0;
daemon/analytics.h
+9 -5
@@ -63,13 +63,17 @@ struct analytics_data {
63
64 size_t data_length;
65
66 - uint8_t prometheus_hits;
67 - uint8_t shell_hits;
68 - uint8_t json_hits;
69 - uint8_t dashboard_hits;
66 + size_t prometheus_hits;
67 + size_t shell_hits;
68 + size_t json_hits;
69 + size_t dashboard_hits;
70 +
71 + size_t charts_count;
72 + size_t metrics_count;
73 +
74 + bool exporting_enabled;
75 };
76
72 -void analytics_get_data(char *name, BUFFER *wb);
77 void set_late_global_environment(void);
78 void analytics_free_data(void);
79 void set_global_environment(void);
daemon/main.c
+19 -9
@@ -13,6 +13,7 @@ int netdata_zero_metrics_enabled;
13 int netdata_anonymous_statistics_enabled;
14
15 int libuv_worker_threads = MIN_LIBUV_WORKER_THREADS;
16 +bool ieee754_doubles = false;
17
18 struct netdata_static_thread *static_threads;
19
@@ -1314,6 +1315,7 @@ void post_conf_load(char **user)
1315 prev_msg = msg; \
1316 }
1317
1318 +int buffer_unittest(void);
1319 int pgc_unittest(void);
1320 int mrg_unittest(void);
1321 int julytest(void);
@@ -1447,6 +1449,8 @@ int main(int argc, char **argv) {
1449 return 1;
1450 if (unit_test_str2ld())
1451 return 1;
1452 + if (buffer_unittest())
1453 + return 1;
1454 if (unit_test_bitmap256())
1455 return 1;
1456 // No call to load the config file on this code-path
@@ -1483,15 +1487,6 @@ int main(int argc, char **argv) {
1487 else if(strcmp(optarg, "escapetest") == 0) {
1488 return command_argument_sanitization_tests();
1489 }
1486 -#ifdef ENABLE_DBENGINE
1487 - else if(strcmp(optarg, "mctest") == 0) {
1488 - unittest_running = true;
1489 - return mc_unittest();
1490 - }
1491 - else if(strcmp(optarg, "ctxtest") == 0) {
1492 - unittest_running = true;
1493 - return ctx_unittest();
1494 - }
1490 else if(strcmp(optarg, "dicttest") == 0) {
1491 unittest_running = true;
1492 return dictionary_unittest(10000);
@@ -1508,6 +1503,19 @@ int main(int argc, char **argv) {
1503 unittest_running = true;
1504 return rrdlabels_unittest();
1505 }
1506 + else if(strcmp(optarg, "buffertest") == 0) {
1507 + unittest_running = true;
1508 + return buffer_unittest();
1509 + }
1510 +#ifdef ENABLE_DBENGINE
1511 + else if(strcmp(optarg, "mctest") == 0) {
1512 + unittest_running = true;
1513 + return mc_unittest();
1514 + }
1515 + else if(strcmp(optarg, "ctxtest") == 0) {
1516 + unittest_running = true;
1517 + return ctx_unittest();
1518 + }
1519 else if(strcmp(optarg, "metatest") == 0) {
1520 unittest_running = true;
1521 return metadata_unittest();
@@ -1878,6 +1886,8 @@ int main(int argc, char **argv) {
1886 // initialize the log files
1887 open_all_log_files();
1888
1889 + ieee754_doubles = is_system_ieee754_double();
1890 +
1891 aral_judy_init();
1892
1893 get_system_timezone();
daemon/unit_test.c
+63 -6
@@ -68,17 +68,36 @@ static int check_number_printing(void) {
68 { .n = 0.000000001, .correct = "0" },
69 { .n = 99.99999999999999999, .correct = "100" },
70 { .n = -99.99999999999999999, .correct = "-100" },
71 + { .n = 123.4567899123456789, .correct = "123.4567899" },
72 { .n = 123.4567890123456789, .correct = "123.456789" },
73 + { .n = 123.4567800123456789, .correct = "123.45678" },
74 + { .n = 123.4567000123456789, .correct = "123.4567" },
75 + { .n = 123.4560000123456789, .correct = "123.456" },
76 + { .n = 123.4500000123456789, .correct = "123.45" },
77 + { .n = 123.4000000123456789, .correct = "123.4" },
78 + { .n = 123.0000000123456789, .correct = "123" },
79 + { .n = 123.0000000923456789, .correct = "123.0000001" },
80 + { .n = 4294967295.123456789, .correct = "4294967295.123457" },
81 + { .n = 8294967295.123456789, .correct = "8294967295.123457" },
82 + { .n = 1.000000000000002e+19, .correct = "1.000000000000001998e+19" },
83 + { .n = 9.2233720368547676e+18, .correct = "9.223372036854767584e+18" },
84 + { .n = 18446744073709541376.0, .correct = "1.84467440737095424e+19" },
85 + { .n = 18446744073709551616.0, .correct = "1.844674407370955136e+19" },
86 + { .n = 12318446744073710600192.0, .correct = "1.231844674407371008e+22" },
87 + { .n = 1677721499999999885312.0, .correct = "1.677721499999999872e+21" },
88 + { .n = -1677721499999999885312.0, .correct = "-1.677721499999999872e+21" },
89 + { .n = -1.677721499999999885312e40, .correct = "-1.677721499999999872e+40" },
90 + { .n = -16777214999999997337621690403742592008192.0, .correct = "-1.677721499999999616e+40" },
91 { .n = 9999.9999999, .correct = "9999.9999999" },
92 { .n = -9999.9999999, .correct = "-9999.9999999" },
93 { .n = 0, .correct = NULL },
94 };
95
77 - char netdata[50], system[50];
96 + char netdata[512 + 2], system[512 + 2];
97 int i, failed = 0;
98 for(i = 0; values[i].correct ; i++) {
99 print_netdata_double(netdata, values[i].n);
81 - snprintfz(system, 49, "%0.12" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE)values[i].n);
100 + snprintfz(system, 512, "%0.12" NETDATA_DOUBLE_MODIFIER, (NETDATA_DOUBLE)values[i].n);
101
102 int ok = 1;
103 if(strcmp(netdata, values[i].correct) != 0) {
@@ -86,7 +105,18 @@ static int check_number_printing(void) {
105 failed++;
106 }
107
89 - fprintf(stderr, "'%s' (system) printed as '%s' (netdata): %s\n", system, netdata, ok?"OK":"FAILED");
108 + NETDATA_DOUBLE parsed_netdata = str2ndd(netdata, NULL);
109 + NETDATA_DOUBLE parsed_system = strtondd(netdata, NULL);
110 +
111 + if(parsed_system != parsed_netdata)
112 + failed++;
113 +
114 + fprintf(stderr, "[%d]. '%s' (system) printed as '%s' (netdata): PRINT %s, "
115 + "PARSED %0.12" NETDATA_DOUBLE_MODIFIER " (system), %0.12" NETDATA_DOUBLE_MODIFIER " (netdata): %s\n",
116 + i,
117 + system, netdata, ok?"OK":"FAILED",
118 + parsed_system, parsed_netdata,
119 + parsed_netdata == parsed_system ? "OK" : "FAILED");
120 }
121
122 if(failed) return 1;
@@ -395,9 +425,35 @@ int unit_test_storage() {
425 }
426
427 int unit_test_str2ld() {
428 + is_system_ieee754_double();
429 +
430 char *values[] = {
399 - "1.2345678", "-35.6", "0.00123", "23842384234234.2", ".1", "1.2e-10",
400 - "hello", "1wrong", "nan", "inf", NULL
431 + "1.2345678",
432 + "-35.6",
433 + "0.00123",
434 + "23842384234234.2",
435 + ".1",
436 + "1.2e-10",
437 + "18446744073709551616.0",
438 + "18446744073709551616123456789123456789123456789123456789123456789123456789123456789.0",
439 + "1.8446744073709551616123456789123456789123456789123456789123456789123456789123456789e+300",
440 + "9.",
441 + "9.e2",
442 + "1.2e",
443 + "1.2e+",
444 + "1.2e-",
445 + "1.2e0",
446 + "1.2e-0",
447 + "1.2e+0",
448 + "-1.2e+1",
449 + "-1.2e-1",
450 + "1.2e1",
451 + "1.2e400",
452 + "hello",
453 + "1wrong",
454 + "nan",
455 + "inf",
456 + NULL
457 };
458
459 int i;
@@ -427,7 +483,8 @@ int unit_test_str2ld() {
483 }
484
485 if(e_mine != e_sys) {
430 - fprintf(stderr, "Value '%s' is parsed correctly, but endptr is not right\n", values[i]);
486 + fprintf(stderr, "Value '%s' is parsed correctly, but endptr is not right (netdata returned %d, but system returned %d)\n",
487 + values[i], (int)(e_mine - values[i]), (int)(e_sys - values[i]));
488 return -1;
489 }
490
database/engine/cache.c
+9
@@ -1189,6 +1189,9 @@ premature_exit:
1189 }
1190
1191 static PGC_PAGE *page_add(PGC *cache, PGC_ENTRY *entry, bool *added) {
1192 + internal_fatal(entry->start_time_s < 0 || entry->end_time_s < 0,
1193 + "DBENGINE CACHE: timestamps are negative");
1194 +
1195 __atomic_add_fetch(&cache->stats.workers_add, 1, __ATOMIC_RELAXED);
1196
1197 size_t partition = pgc_indexing_partition(cache, entry->metric_id);
@@ -1199,6 +1202,12 @@ static PGC_PAGE *page_add(PGC *cache, PGC_ENTRY *entry, bool *added) {
1202 PGC_PAGE *page;
1203 size_t spins = 0;
1204
1205 + if(unlikely(entry->start_time_s < 0))
1206 + entry->start_time_s = 0;
1207 +
1208 + if(unlikely(entry->end_time_s < 0))
1209 + entry->end_time_s = 0;
1210 +
1211 do {
1212 if(++spins > 1)
1213 __atomic_add_fetch(&cache->stats.insert_spins, 1, __ATOMIC_RELAXED);
database/engine/metric.c
+41 -13
@@ -105,7 +105,7 @@ static inline size_t uuid_partition(MRG *mrg __maybe_unused, uuid_t *uuid) {
105 }
106
107 static inline bool metric_has_retention_unsafe(MRG *mrg __maybe_unused, METRIC *metric) {
108 - bool has_retention = (metric->first_time_s || metric->latest_time_s_clean || metric->latest_time_s_hot);
108 + bool has_retention = (metric->first_time_s > 0 || metric->latest_time_s_clean > 0 || metric->latest_time_s_hot > 0);
109
110 if(has_retention && !(metric->flags & METRIC_FLAG_HAS_RETENTION)) {
111 metric->flags |= METRIC_FLAG_HAS_RETENTION;
@@ -210,8 +210,8 @@ static METRIC *metric_add_and_acquire(MRG *mrg, MRG_ENTRY *entry, bool *ret) {
210 METRIC *metric = allocation;
211 uuid_copy(metric->uuid, entry->uuid);
212 metric->section = entry->section;
213 - metric->first_time_s = entry->first_time_s;
214 - metric->latest_time_s_clean = entry->last_time_s;
213 + metric->first_time_s = MAX(0, entry->first_time_s);
214 + metric->latest_time_s_clean = MAX(0, entry->last_time_s);
215 metric->latest_time_s_hot = 0;
216 metric->latest_update_every_s = entry->latest_update_every_s;
217 metric->writer = 0;
@@ -388,6 +388,11 @@ Word_t mrg_metric_section(MRG *mrg __maybe_unused, METRIC *metric) {
388 }
389
390 bool mrg_metric_set_first_time_s(MRG *mrg __maybe_unused, METRIC *metric, time_t first_time_s) {
391 + internal_fatal(first_time_s < 0, "DBENGINE METRIC: timestamp is negative");
392 +
393 + if(unlikely(first_time_s < 0))
394 + return false;
395 +
396 netdata_spinlock_lock(&metric->spinlock);
397 metric->first_time_s = first_time_s;
398 metric_has_retention_unsafe(mrg, metric);
@@ -397,12 +402,25 @@ bool mrg_metric_set_first_time_s(MRG *mrg __maybe_unused, METRIC *metric, time_t
402 }
403
404 void mrg_metric_expand_retention(MRG *mrg __maybe_unused, METRIC *metric, time_t first_time_s, time_t last_time_s, time_t update_every_s) {
400 -
405 + internal_fatal(first_time_s < 0 || last_time_s < 0 || update_every_s < 0,
406 + "DBENGINE METRIC: timestamp is negative");
407 internal_fatal(first_time_s > max_acceptable_collected_time(),
408 "DBENGINE METRIC: metric first time is in the future");
409 internal_fatal(last_time_s > max_acceptable_collected_time(),
410 "DBENGINE METRIC: metric last time is in the future");
411
412 + if(unlikely(first_time_s < 0))
413 + first_time_s = 0;
414 +
415 + if(unlikely(last_time_s < 0))
416 + last_time_s = 0;
417 +
418 + if(unlikely(update_every_s < 0))
419 + update_every_s = 0;
420 +
421 + if(unlikely(!first_time_s && !last_time_s && !update_every_s))
422 + return;
423 +
424 netdata_spinlock_lock(&metric->spinlock);
425
426 if(unlikely(first_time_s && (!metric->first_time_s || first_time_s < metric->first_time_s)))
@@ -422,6 +440,8 @@ void mrg_metric_expand_retention(MRG *mrg __maybe_unused, METRIC *metric, time_t
440 }
441
442 bool mrg_metric_set_first_time_s_if_bigger(MRG *mrg __maybe_unused, METRIC *metric, time_t first_time_s) {
443 + internal_fatal(first_time_s < 0, "DBENGINE METRIC: timestamp is negative");
444 +
445 bool ret = false;
446
447 netdata_spinlock_lock(&metric->spinlock);
@@ -474,6 +494,11 @@ void mrg_metric_get_retention(MRG *mrg __maybe_unused, METRIC *metric, time_t *f
494 }
495
496 bool mrg_metric_set_clean_latest_time_s(MRG *mrg __maybe_unused, METRIC *metric, time_t latest_time_s) {
497 + internal_fatal(latest_time_s < 0, "DBENGINE METRIC: timestamp is negative");
498 +
499 + if(unlikely(latest_time_s < 0))
500 + return false;
501 +
502 netdata_spinlock_lock(&metric->spinlock);
503
504 // internal_fatal(latest_time_s > max_acceptable_collected_time(),
@@ -487,9 +512,6 @@ bool mrg_metric_set_clean_latest_time_s(MRG *mrg __maybe_unused, METRIC *metric,
512 if(unlikely(!metric->first_time_s))
513 metric->first_time_s = latest_time_s;
514
490 -// if(unlikely(metric->first_time_s > latest_time_s))
491 -// metric->first_time_s = latest_time_s;
492 -
515 metric_has_retention_unsafe(mrg, metric);
516 netdata_spinlock_unlock(&metric->spinlock);
517 return true;
@@ -517,7 +539,7 @@ bool mrg_metric_zero_disk_retention(MRG *mrg __maybe_unused, METRIC *metric) {
539 page_first_time_s = pgc_page_start_time_s(page);
540 page_end_time_s = pgc_page_end_time_s(page);
541
520 - if ((is_hot || is_dirty) && page_first_time_s < min_first_time_s)
542 + if ((is_hot || is_dirty) && page_first_time_s > 0 && page_first_time_s < min_first_time_s)
543 min_first_time_s = page_first_time_s;
544
545 if (is_dirty && page_end_time_s > max_end_time_s)
@@ -548,18 +570,20 @@ bool mrg_metric_zero_disk_retention(MRG *mrg __maybe_unused, METRIC *metric) {
570 }
571
572 bool mrg_metric_set_hot_latest_time_s(MRG *mrg __maybe_unused, METRIC *metric, time_t latest_time_s) {
573 + internal_fatal(latest_time_s < 0, "DBENGINE METRIC: timestamp is negative");
574 +
575 // internal_fatal(latest_time_s > max_acceptable_collected_time(),
576 // "DBENGINE METRIC: metric latest time is in the future");
577
578 + if(unlikely(latest_time_s < 0))
579 + return false;
580 +
581 netdata_spinlock_lock(&metric->spinlock);
582 metric->latest_time_s_hot = latest_time_s;
583
584 if(unlikely(!metric->first_time_s))
585 metric->first_time_s = latest_time_s;
586
560 -// if(unlikely(metric->first_time_s > latest_time_s))
561 -// metric->first_time_s = latest_time_s;
562 -
587 metric_has_retention_unsafe(mrg, metric);
588 netdata_spinlock_unlock(&metric->spinlock);
589 return true;
@@ -574,7 +598,9 @@ time_t mrg_metric_get_latest_time_s(MRG *mrg __maybe_unused, METRIC *metric) {
598 }
599
600 bool mrg_metric_set_update_every(MRG *mrg __maybe_unused, METRIC *metric, time_t update_every_s) {
577 - if(!update_every_s)
601 + internal_fatal(update_every_s < 0, "DBENGINE METRIC: timestamp is negative");
602 +
603 + if(update_every_s <= 0)
604 return false;
605
606 netdata_spinlock_lock(&metric->spinlock);
@@ -585,7 +611,9 @@ bool mrg_metric_set_update_every(MRG *mrg __maybe_unused, METRIC *metric, time_t
611 }
612
613 bool mrg_metric_set_update_every_s_if_zero(MRG *mrg __maybe_unused, METRIC *metric, time_t update_every_s) {
588 - if(!update_every_s)
614 + internal_fatal(update_every_s < 0, "DBENGINE METRIC: timestamp is negative");
615 +
616 + if(update_every_s <= 0)
617 return false;
618
619 netdata_spinlock_lock(&metric->spinlock);
database/engine/pagecache.c
+9 -5
@@ -785,10 +785,10 @@ void rrdeng_prep_query(PDC *pdc) {
785 if (pages_to_load && pdc->page_list_JudyL) {
786 pdc_acquire(pdc); // we get 1 for the 1st worker in the chain: do_read_page_list_work()
787 usec_t start_ut = now_monotonic_usec();
788 -// if(likely(priority == STORAGE_PRIORITY_BEST_EFFORT))
789 -// dbengine_load_page_list_directly(ctx, handle->pdc);
790 -// else
791 - pdc_route_asynchronously(pdc->ctx, pdc);
788 + if(likely(pdc->priority == STORAGE_PRIORITY_SYNCHRONOUS))
789 + pdc_route_synchronously(pdc->ctx, pdc);
790 + else
791 + pdc_route_asynchronously(pdc->ctx, pdc);
792 __atomic_add_fetch(&rrdeng_cache_efficiency_stats.prep_time_to_route, now_monotonic_usec() - start_ut, __ATOMIC_RELAXED);
793 }
794 else
@@ -827,7 +827,11 @@ void pg_cache_preload(struct rrdeng_query_handle *handle) {
827
828 if(ctx_is_available_for_queries(handle->ctx)) {
829 handle->pdc->refcount++; // we get 1 for the query thread and 1 for the prep thread
830 - rrdeng_enq_cmd(handle->ctx, RRDENG_OPCODE_QUERY, handle->pdc, NULL, handle->priority, NULL, NULL);
830 +
831 + if(unlikely(handle->pdc->priority == STORAGE_PRIORITY_SYNCHRONOUS))
832 + rrdeng_prep_query(handle->pdc);
833 + else
834 + rrdeng_enq_cmd(handle->ctx, RRDENG_OPCODE_QUERY, handle->pdc, NULL, handle->priority, NULL, NULL);
835 }
836 else {
837 completion_mark_complete(&handle->pdc->prep_completion);
database/engine/pdc.c
+3 -2
@@ -692,8 +692,9 @@ VALIDATED_PAGE_DESCRIPTOR validate_page(
692 vd.page_length > RRDENG_BLOCK_SIZE ||
693 vd.start_time_s > vd.end_time_s ||
694 (now_s && vd.end_time_s > now_s) ||
695 - vd.start_time_s == 0 ||
696 - vd.end_time_s == 0 ||
695 + vd.start_time_s <= 0 ||
696 + vd.end_time_s <= 0 ||
697 + vd.update_every_s < 0 ||
698 (vd.start_time_s == vd.end_time_s && vd.entries > 1) ||
699 (vd.update_every_s == 0 && vd.entries > 1)
700 )
database/engine/rrdengine.c
+1 -1
@@ -468,7 +468,7 @@ static inline bool rrdeng_cmd_has_waiting_opcodes_in_lower_priorities(STORAGE_PR
468 static inline struct rrdeng_cmd rrdeng_deq_cmd(void) {
469 struct rrdeng_cmd *cmd = NULL;
470
471 - STORAGE_PRIORITY max_priority = work_request_full() ? STORAGE_PRIORITY_INTERNAL_DBENGINE : STORAGE_PRIORITY_BEST_EFFORT;
471 + STORAGE_PRIORITY max_priority = work_request_full() ? STORAGE_PRIORITY_INTERNAL_DBENGINE : STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE - 1;
472
473 // find an opcode to execute from the queue
474 netdata_spinlock_lock(&rrdeng_main.cmd_queue.unsafe.spinlock);
database/engine/rrdengineapi.c
+3 -3
@@ -741,10 +741,10 @@ void rrdeng_load_metric_init(STORAGE_METRIC_HANDLE *db_metric_handle,
741 handle = rrdeng_query_handle_get();
742 register_query_handle(handle);
743
744 - if(unlikely(priority < STORAGE_PRIORITY_HIGH))
744 + if (unlikely(priority < STORAGE_PRIORITY_HIGH))
745 priority = STORAGE_PRIORITY_HIGH;
746 - else if(unlikely(priority > STORAGE_PRIORITY_BEST_EFFORT))
747 - priority = STORAGE_PRIORITY_BEST_EFFORT;
746 + else if (unlikely(priority >= STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE))
747 + priority = STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE - 1;
748
749 handle->ctx = ctx;
750 handle->metric = metric;
database/rrd.h
+6
@@ -54,6 +54,9 @@ typedef enum __attribute__ ((__packed__)) storage_priority {
54 STORAGE_PRIORITY_LOW,
55 STORAGE_PRIORITY_BEST_EFFORT,
56
57 + // synchronous query, not to be dispatched to workers or queued
58 + STORAGE_PRIORITY_SYNCHRONOUS,
59 +
60 STORAGE_PRIORITY_INTERNAL_MAX_DONT_USE,
61 } STORAGE_PRIORITY;
62
@@ -167,6 +170,7 @@ extern time_t rrdset_free_obsolete_time_s;
170 #endif
171
172 extern int libuv_worker_threads;
173 +extern bool ieee754_doubles;
174
175 #define RRD_ID_LENGTH_MAX 200
176
@@ -279,6 +283,7 @@ void rrdlabels_destroy(DICTIONARY *labels_dict);
283 void rrdlabels_add(DICTIONARY *dict, const char *name, const char *value, RRDLABEL_SRC ls);
284 void rrdlabels_add_pair(DICTIONARY *dict, const char *string, RRDLABEL_SRC ls);
285 void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const char *key, const char *quote, const char *null);
286 +void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key);
287 void rrdlabels_get_value_strdup_or_null(DICTIONARY *labels, char **value, const char *key);
288 void rrdlabels_flush(DICTIONARY *labels_dict);
289
@@ -292,6 +297,7 @@ void rrdlabels_log_to_buffer(DICTIONARY *labels, BUFFER *wb);
297 bool rrdlabels_match_simple_pattern(DICTIONARY *labels, const char *simple_pattern_txt);
298 bool rrdlabels_match_simple_pattern_parsed(DICTIONARY *labels, SIMPLE_PATTERN *pattern, char equal);
299 int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each, const char *equal, const char *quote, const char *between_them, bool (*filter_callback)(const char *name, const char *value, RRDLABEL_SRC ls, void *data), void *filter_data, void (*name_sanitizer)(char *dst, const char *src, size_t dst_size), void (*value_sanitizer)(char *dst, const char *src, size_t dst_size));
300 +void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb);
301
302 void rrdlabels_migrate_to_these(DICTIONARY *dst, DICTIONARY *src);
303 void rrdlabels_copy(DICTIONARY *dst, DICTIONARY *src);
database/rrdcalc.h
+1 -1
@@ -77,7 +77,7 @@ struct rrdcalc {
77 STRING *dimensions; // the chart dimensions
78 STRING *foreach_dimension; // the group of dimensions that the `foreach` will be applied.
79 SIMPLE_PATTERN *foreach_dimension_pattern; // used if and only if there is a simple pattern for the chart.
80 - RRDR_GROUPING group; // grouping method: average, max, etc.
80 + RRDR_TIME_GROUPING group; // grouping method: average, max, etc.
81 int before; // ending point in time-series
82 int after; // starting point in time-series
83 RRDCALC_OPTIONS options; // configuration options
database/rrdcalctemplate.h
+1 -1
@@ -50,7 +50,7 @@ struct rrdcalctemplate {
50 STRING *dimensions; // the chart dimensions
51 STRING *foreach_dimension; // the group of dimensions that the lookup will be applied.
52 SIMPLE_PATTERN *foreach_dimension_pattern; // used if and only if there is a simple pattern for the chart.
53 - RRDR_GROUPING group; // grouping method: average, max, etc.
53 + RRDR_TIME_GROUPING group; // grouping method: average, max, etc.
54 int before; // ending point in time-series
55 int after; // starting point in time-series
56 RRDCALC_OPTIONS options; // configuration options
database/rrdcontext.c
+112 -178
@@ -426,41 +426,39 @@ static void rrdcontext_trigger_updates(RRDCONTEXT *rc, const char *function);
426 // ----------------------------------------------------------------------------
427 // visualizing flags
428
429 -static void rrd_flags_to_buffer(RRD_FLAGS flags, BUFFER *wb) {
429 +static void rrd_flags_to_buffer_json_array_items(RRD_FLAGS flags, BUFFER *wb) {
430 if(flags & RRD_FLAG_QUEUED_FOR_HUB)
431 - buffer_strcat(wb, "QUEUED ");
431 + buffer_json_add_array_item_string(wb, "QUEUED");
432
433 if(flags & RRD_FLAG_DELETED)
434 - buffer_strcat(wb, "DELETED ");
434 + buffer_json_add_array_item_string(wb, "DELETED");
435
436 if(flags & RRD_FLAG_COLLECTED)
437 - buffer_strcat(wb, "COLLECTED ");
437 + buffer_json_add_array_item_string(wb, "COLLECTED");
438
439 if(flags & RRD_FLAG_UPDATED)
440 - buffer_strcat(wb, "UPDATED ");
440 + buffer_json_add_array_item_string(wb, "UPDATED");
441
442 if(flags & RRD_FLAG_ARCHIVED)
443 - buffer_strcat(wb, "ARCHIVED ");
443 + buffer_json_add_array_item_string(wb, "ARCHIVED");
444
445 if(flags & RRD_FLAG_OWN_LABELS)
446 - buffer_strcat(wb, "OWN_LABELS ");
446 + buffer_json_add_array_item_string(wb, "OWN_LABELS");
447
448 if(flags & RRD_FLAG_LIVE_RETENTION)
449 - buffer_strcat(wb, "LIVE_RETENTION ");
449 + buffer_json_add_array_item_string(wb, "LIVE_RETENTION");
450
451 if(flags & RRD_FLAG_HIDDEN)
452 - buffer_strcat(wb, "HIDDEN ");
452 + buffer_json_add_array_item_string(wb, "HIDDEN");
453
454 if(flags & RRD_FLAG_QUEUED_FOR_PP)
455 - buffer_strcat(wb, "PENDING_UPDATES ");
455 + buffer_json_add_array_item_string(wb, "PENDING_UPDATES");
456 }
457
458 -static void rrd_reasons_to_buffer(RRD_FLAGS flags, BUFFER *wb) {
458 +static void rrd_reasons_to_buffer_json_array_items(RRD_FLAGS flags, BUFFER *wb) {
459 for(int i = 0, added = 0; rrdcontext_reasons[i].name ; i++) {
460 if (flags & rrdcontext_reasons[i].flag) {
461 - if (added)
462 - buffer_strcat(wb, ", ");
463 - buffer_strcat(wb, rrdcontext_reasons[i].name);
461 + buffer_json_add_array_item_string(wb, rrdcontext_reasons[i].name);
462 added++;
463 }
464 }
@@ -1769,51 +1767,39 @@ static inline int rrdmetric_to_json_callback(const DICTIONARY_ITEM *item, void *
1767 return 0;
1768
1769 if(t->written) {
1772 - buffer_strcat(wb, ",\n");
1770 t->combined_first_time_s = MIN(t->combined_first_time_s, rm->first_time_s);
1771 t->combined_last_time_s = MAX(t->combined_last_time_s, rm->last_time_s);
1772 t->combined_flags |= rrd_flags_get(rm);
1773 }
1774 else {
1778 - buffer_strcat(wb, "\n");
1775 t->combined_first_time_s = rm->first_time_s;
1776 t->combined_last_time_s = rm->last_time_s;
1777 t->combined_flags = rrd_flags_get(rm);
1778 }
1779
1784 - buffer_sprintf(wb, "\t\t\t\t\t\t\"%s\": {", id);
1780 + buffer_json_member_add_object(wb, id);
1781
1782 if(options & RRDCONTEXT_OPTION_SHOW_UUIDS) {
1783 char uuid[UUID_STR_LEN];
1784 uuid_unparse(rm->uuid, uuid);
1789 - buffer_sprintf(wb, "\n\t\t\t\t\t\t\t\"uuid\":\"%s\",", uuid);
1790 - }
1791 -
1792 - buffer_sprintf(wb,
1793 - "\n\t\t\t\t\t\t\t\"name\":\"%s\""
1794 - ",\n\t\t\t\t\t\t\t\"first_time_t\":%lld"
1795 - ",\n\t\t\t\t\t\t\t\"last_time_t\":%lld"
1796 - ",\n\t\t\t\t\t\t\t\"collected\":%s"
1797 - , string2str(rm->name)
1798 - , (long long)rm->first_time_s
1799 - , rrd_flag_is_collected(rm) ? (long long)t->now : (long long)rm->last_time_s
1800 - , rrd_flag_is_collected(rm) ? "true" : "false"
1801 - );
1802 -
1803 - if(options & RRDCONTEXT_OPTION_SHOW_DELETED) {
1804 - buffer_sprintf(wb,
1805 - ",\n\t\t\t\t\t\t\t\"deleted\":%s"
1806 - , rrd_flag_is_deleted(rm) ? "true" : "false"
1807 - );
1785 + buffer_json_member_add_string(wb, "uuid", uuid);
1786 }
1787
1788 + buffer_json_member_add_string(wb, "name", string2str(rm->name));
1789 + buffer_json_member_add_time_t(wb, "first_time_t", rm->first_time_s);
1790 + buffer_json_member_add_time_t(wb, "last_time_t", rrd_flag_is_collected(rm) ? (long long)t->now : (long long)rm->last_time_s);
1791 + buffer_json_member_add_boolean(wb, "collected", rrd_flag_is_collected(rm));
1792 +
1793 + if(options & RRDCONTEXT_OPTION_SHOW_DELETED)
1794 + buffer_json_member_add_boolean(wb, "deleted", rrd_flag_is_deleted(rm));
1795 +
1796 if(options & RRDCONTEXT_OPTION_SHOW_FLAGS) {
1811 - buffer_strcat(wb, ",\n\t\t\t\t\t\t\t\"flags\":\"");
1812 - rrd_flags_to_buffer(rrd_flags_get(rm), wb);
1813 - buffer_strcat(wb, "\"");
1797 + buffer_json_member_add_array(wb, "flags");
1798 + rrd_flags_to_buffer_json_array_items(rrd_flags_get(rm), wb);
1799 + buffer_json_array_close(wb);
1800 }
1801
1816 - buffer_strcat(wb, "\n\t\t\t\t\t\t}");
1802 + buffer_json_object_close(wb);
1803 t->written++;
1804 return 1;
1805 }
@@ -1852,6 +1838,7 @@ static inline int rrdinstance_to_json_callback(const DICTIONARY_ITEM *item, void
1838 if(options & RRDCONTEXT_OPTION_SHOW_METRICS || t_parent->chart_dimensions) {
1839
1840 wb_metrics = buffer_create(4096, &netdata_buffers_statistics.buffers_api);
1841 + buffer_json_initialize(wb_metrics, "\"", "\"", wb->json.depth + 2, false);
1842
1843 struct rrdcontext_to_json t_metrics = {
1844 .wb = wb_metrics,
@@ -1877,79 +1864,60 @@ static inline int rrdinstance_to_json_callback(const DICTIONARY_ITEM *item, void
1864 }
1865
1866 if(t_parent->written) {
1880 - buffer_strcat(wb, ",\n");
1867 t_parent->combined_first_time_s = MIN(t_parent->combined_first_time_s, first_time_s);
1868 t_parent->combined_last_time_s = MAX(t_parent->combined_last_time_s, last_time_s);
1869 t_parent->combined_flags |= flags;
1870 }
1871 else {
1886 - buffer_strcat(wb, "\n");
1872 t_parent->combined_first_time_s = first_time_s;
1873 t_parent->combined_last_time_s = last_time_s;
1874 t_parent->combined_flags = flags;
1875 }
1876
1892 - buffer_sprintf(wb, "\t\t\t\t\"%s\": {", id);
1877 + buffer_json_member_add_object(wb, id);
1878
1879 if(options & RRDCONTEXT_OPTION_SHOW_UUIDS) {
1880 char uuid[UUID_STR_LEN];
1881 uuid_unparse(ri->uuid, uuid);
1897 - buffer_sprintf(wb,"\n\t\t\t\t\t\"uuid\":\"%s\",", uuid);
1898 - }
1899 -
1900 - buffer_sprintf(wb,
1901 - "\n\t\t\t\t\t\"name\":\"%s\""
1902 - ",\n\t\t\t\t\t\"context\":\"%s\""
1903 - ",\n\t\t\t\t\t\"title\":\"%s\""
1904 - ",\n\t\t\t\t\t\"units\":\"%s\""
1905 - ",\n\t\t\t\t\t\"family\":\"%s\""
1906 - ",\n\t\t\t\t\t\"chart_type\":\"%s\""
1907 - ",\n\t\t\t\t\t\"priority\":%u"
1908 - ",\n\t\t\t\t\t\"update_every\":%ld"
1909 - ",\n\t\t\t\t\t\"first_time_t\":%lld"
1910 - ",\n\t\t\t\t\t\"last_time_t\":%lld"
1911 - ",\n\t\t\t\t\t\"collected\":%s"
1912 - , string2str(ri->name)
1913 - , string2str(ri->rc->id)
1914 - , string2str(ri->title)
1915 - , string2str(ri->units)
1916 - , string2str(ri->family)
1917 - , rrdset_type_name(ri->chart_type)
1918 - , ri->priority
1919 - , ri->update_every_s
1920 - , (long long)first_time_s
1921 - , (flags & RRD_FLAG_COLLECTED) ? (long long)t_parent->now : (long long)last_time_s
1922 - , (flags & RRD_FLAG_COLLECTED) ? "true" : "false"
1923 - );
1924 -
1925 - if(options & RRDCONTEXT_OPTION_SHOW_DELETED) {
1926 - buffer_sprintf(wb,
1927 - ",\n\t\t\t\t\t\"deleted\":%s"
1928 - , rrd_flag_is_deleted(ri) ? "true" : "false"
1929 - );
1882 + buffer_json_member_add_string(wb, "uuid", uuid);
1883 }
1884
1885 + buffer_json_member_add_string(wb, "name", string2str(ri->name));
1886 + buffer_json_member_add_string(wb, "context", string2str(ri->rc->id));
1887 + buffer_json_member_add_string(wb, "title", string2str(ri->title));
1888 + buffer_json_member_add_string(wb, "units", string2str(ri->units));
1889 + buffer_json_member_add_string(wb, "family", string2str(ri->family));
1890 + buffer_json_member_add_string(wb, "chart_type", rrdset_type_name(ri->chart_type));
1891 + buffer_json_member_add_uint64(wb, "priority", ri->priority);
1892 + buffer_json_member_add_time_t(wb, "update_every", ri->update_every_s);
1893 + buffer_json_member_add_time_t(wb, "first_time_t", first_time_s);
1894 + buffer_json_member_add_time_t(wb, "last_time_t", (flags & RRD_FLAG_COLLECTED) ? (long long)t_parent->now : (long long)last_time_s);
1895 + buffer_json_member_add_boolean(wb, "collected", flags & RRD_FLAG_COLLECTED);
1896 +
1897 + if(options & RRDCONTEXT_OPTION_SHOW_DELETED)
1898 + buffer_json_member_add_boolean(wb, "deleted", rrd_flag_is_deleted(ri));
1899 +
1900 if(options & RRDCONTEXT_OPTION_SHOW_FLAGS) {
1933 - buffer_strcat(wb, ",\n\t\t\t\t\t\"flags\":\"");
1934 - rrd_flags_to_buffer(rrd_flags_get(ri), wb);
1935 - buffer_strcat(wb, "\"");
1901 + buffer_json_member_add_array(wb, "flags");
1902 + rrd_flags_to_buffer_json_array_items(rrd_flags_get(ri), wb);
1903 + buffer_json_array_close(wb);
1904 }
1905
1906 if(options & RRDCONTEXT_OPTION_SHOW_LABELS && ri->rrdlabels && dictionary_entries(ri->rrdlabels)) {
1939 - buffer_sprintf(wb, ",\n\t\t\t\t\t\"labels\": {\n");
1940 - rrdlabels_to_buffer(ri->rrdlabels, wb, "\t\t\t\t\t\t", ":", "\"", ",\n", NULL, NULL, NULL, NULL);
1941 - buffer_strcat(wb, "\n\t\t\t\t\t}");
1907 + buffer_json_member_add_object(wb, "labels");
1908 + rrdlabels_to_buffer_json_members(ri->rrdlabels, wb);
1909 + buffer_json_object_close(wb);
1910 }
1911
1912 if(wb_metrics) {
1945 - buffer_sprintf(wb, ",\n\t\t\t\t\t\"dimensions\": {");
1913 + buffer_json_member_add_object(wb, "dimensions");
1914 buffer_fast_strcat(wb, buffer_tostring(wb_metrics), buffer_strlen(wb_metrics));
1947 - buffer_strcat(wb, "\n\t\t\t\t\t}");
1915 + buffer_json_object_close(wb);
1916
1917 buffer_free(wb_metrics);
1918 }
1919
1952 - buffer_strcat(wb, "\n\t\t\t\t}");
1920 + buffer_json_object_close(wb);
1921 t_parent->written++;
1922 return 1;
1923 }
@@ -1990,6 +1958,7 @@ static inline int rrdcontext_to_json_callback(const DICTIONARY_ITEM *item, void
1958 || t_parent->chart_dimensions) {
1959
1960 wb_instances = buffer_create(4096, &netdata_buffers_statistics.buffers_api);
1961 + buffer_json_initialize(wb_instances, "\"", "\"", wb->json.depth + 2, false);
1962
1963 struct rrdcontext_to_json t_instances = {
1964 .wb = wb_instances,
@@ -2014,95 +1983,63 @@ static inline int rrdcontext_to_json_callback(const DICTIONARY_ITEM *item, void
1983 flags = t_instances.combined_flags;
1984 }
1985
2017 - if(t_parent->written)
2018 - buffer_strcat(wb, ",\n");
2019 - else
2020 - buffer_strcat(wb, "\n");
2021 -
2022 - if(options & RRDCONTEXT_OPTION_SKIP_ID)
2023 - buffer_sprintf(wb, "\t\t\{");
2024 - else
2025 - buffer_sprintf(wb, "\t\t\"%s\": {", id);
1986 + if(!(options & RRDCONTEXT_OPTION_SKIP_ID))
1987 + buffer_json_member_add_object(wb, id);
1988
1989 rrdcontext_lock(rc);
1990
2029 - buffer_sprintf(wb,
2030 - "\n\t\t\t\"title\":\"%s\""
2031 - ",\n\t\t\t\"units\":\"%s\""
2032 - ",\n\t\t\t\"family\":\"%s\""
2033 - ",\n\t\t\t\"chart_type\":\"%s\""
2034 - ",\n\t\t\t\"priority\":%u"
2035 - ",\n\t\t\t\"first_time_t\":%lld"
2036 - ",\n\t\t\t\"last_time_t\":%lld"
2037 - ",\n\t\t\t\"collected\":%s"
2038 - , string2str(rc->title)
2039 - , string2str(rc->units)
2040 - , string2str(rc->family)
2041 - , rrdset_type_name(rc->chart_type)
2042 - , rc->priority
2043 - , (long long)first_time_s
2044 - , (flags & RRD_FLAG_COLLECTED) ? (long long)t_parent->now : (long long)last_time_s
2045 - , (flags & RRD_FLAG_COLLECTED) ? "true" : "false"
2046 - );
2047 -
2048 - if(options & RRDCONTEXT_OPTION_SHOW_DELETED) {
2049 - buffer_sprintf(wb,
2050 - ",\n\t\t\t\"deleted\":%s"
2051 - , rrd_flag_is_deleted(rc) ? "true" : "false"
2052 - );
2053 - }
1991 + buffer_json_member_add_string(wb, "title", string2str(rc->title));
1992 + buffer_json_member_add_string(wb, "units", string2str(rc->units));
1993 + buffer_json_member_add_string(wb, "family", string2str(rc->family));
1994 + buffer_json_member_add_string(wb, "chart_type", rrdset_type_name(rc->chart_type));
1995 + buffer_json_member_add_uint64(wb, "priority", rc->priority);
1996 + buffer_json_member_add_time_t(wb, "first_time_t", first_time_s);
1997 + buffer_json_member_add_time_t(wb, "last_time_t", (flags & RRD_FLAG_COLLECTED) ? (long long)t_parent->now : (long long)last_time_s);
1998 + buffer_json_member_add_boolean(wb, "collected", (flags & RRD_FLAG_COLLECTED));
1999 +
2000 + if(options & RRDCONTEXT_OPTION_SHOW_DELETED)
2001 + buffer_json_member_add_boolean(wb, "deleted", rrd_flag_is_deleted(rc));
2002
2003 if(options & RRDCONTEXT_OPTION_SHOW_FLAGS) {
2056 - buffer_strcat(wb, ",\n\t\t\t\"flags\":\"");
2057 - rrd_flags_to_buffer(rrd_flags_get(rc), wb);
2058 - buffer_strcat(wb, "\"");
2004 + buffer_json_member_add_array(wb, "flags");
2005 + rrd_flags_to_buffer_json_array_items(rrd_flags_get(rc), wb);
2006 + buffer_json_array_close(wb);
2007 }
2008
2009 if(options & RRDCONTEXT_OPTION_SHOW_QUEUED) {
2062 - buffer_strcat(wb, ",\n\t\t\t\"queued_reasons\":\"");
2063 - rrd_reasons_to_buffer(rc->queue.queued_flags, wb);
2064 - buffer_strcat(wb, "\"");
2065 -
2066 - buffer_sprintf(wb,
2067 - ",\n\t\t\t\"last_queued\":%llu"
2068 - ",\n\t\t\t\"scheduled_dispatch\":%llu"
2069 - ",\n\t\t\t\"last_dequeued\":%llu"
2070 - ",\n\t\t\t\"dispatches\":%zu"
2071 - ",\n\t\t\t\"hub_version\":%"PRIu64""
2072 - ",\n\t\t\t\"version\":%"PRIu64""
2073 - , rc->queue.queued_ut / USEC_PER_SEC
2074 - , rc->queue.scheduled_dispatch_ut / USEC_PER_SEC
2075 - , rc->queue.dequeued_ut / USEC_PER_SEC
2076 - , rc->queue.dispatches
2077 - , rc->hub.version
2078 - , rc->version
2079 - );
2010 + buffer_json_member_add_array(wb, "queued_reasons");
2011 + rrd_reasons_to_buffer_json_array_items(rc->queue.queued_flags, wb);
2012 + buffer_json_array_close(wb);
2013
2081 - buffer_strcat(wb, ",\n\t\t\t\"pp_reasons\":\"");
2082 - rrd_reasons_to_buffer(rc->pp.queued_flags, wb);
2083 - buffer_strcat(wb, "\"");
2084 -
2085 - buffer_sprintf(wb,
2086 - ",\n\t\t\t\"pp_last_queued\":%llu"
2087 - ",\n\t\t\t\"pp_last_dequeued\":%llu"
2088 - ",\n\t\t\t\"pp_executed\":%zu"
2089 - , rc->pp.queued_ut / USEC_PER_SEC
2090 - , rc->pp.dequeued_ut / USEC_PER_SEC
2091 - , rc->pp.executions
2092 - );
2014 + buffer_json_member_add_time_t(wb, "last_queued", (time_t)(rc->queue.queued_ut / USEC_PER_SEC));
2015 + buffer_json_member_add_time_t(wb, "scheduled_dispatch", (time_t)(rc->queue.scheduled_dispatch_ut / USEC_PER_SEC));
2016 + buffer_json_member_add_time_t(wb, "last_dequeued", (time_t)(rc->queue.dequeued_ut / USEC_PER_SEC));
2017 + buffer_json_member_add_uint64(wb, "dispatches", rc->queue.dispatches);
2018 + buffer_json_member_add_uint64(wb, "hub_version", rc->hub.version);
2019 + buffer_json_member_add_uint64(wb, "version", rc->version);
2020 +
2021 + buffer_json_member_add_array(wb, "pp_reasons");
2022 + rrd_reasons_to_buffer_json_array_items(rc->pp.queued_flags, wb);
2023 + buffer_json_array_close(wb);
2024 +
2025 + buffer_json_member_add_time_t(wb, "pp_last_queued", (time_t)(rc->pp.queued_ut / USEC_PER_SEC));
2026 + buffer_json_member_add_time_t(wb, "pp_last_dequeued", (time_t)(rc->pp.dequeued_ut / USEC_PER_SEC));
2027 + buffer_json_member_add_uint64(wb, "pp_executed", rc->pp.executions);
2028 }
2029
2030 rrdcontext_unlock(rc);
2031
2032 if(wb_instances) {
2098 - buffer_sprintf(wb, ",\n\t\t\t\"charts\": {");
2033 + buffer_json_member_add_object(wb, "charts");
2034 buffer_fast_strcat(wb, buffer_tostring(wb_instances), buffer_strlen(wb_instances));
2100 - buffer_strcat(wb, "\n\t\t\t}");
2035 + buffer_json_object_close(wb);
2036
2037 buffer_free(wb_instances);
2038 }
2039
2105 - buffer_strcat(wb, "\n\t\t}");
2040 + if(!(options & RRDCONTEXT_OPTION_SKIP_ID))
2041 + buffer_json_object_close(wb);
2042 +
2043 t_parent->written++;
2044 return 1;
2045 }
@@ -2121,6 +2058,7 @@ int rrdcontext_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before, R
2058 if(after != 0 && before != 0)
2059 rrdr_relative_window_to_absolute(&after, &before);
2060
2061 + buffer_json_initialize(wb, "\"", "\"", 0, true);
2062 struct rrdcontext_to_json t_contexts = {
2063 .wb = wb,
2064 .options = options|RRDCONTEXT_OPTION_SKIP_ID,
@@ -2133,6 +2071,7 @@ int rrdcontext_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before, R
2071 .now = now_realtime_sec(),
2072 };
2073 rrdcontext_to_json_callback((DICTIONARY_ITEM *)rca, rc, &t_contexts);
2074 + buffer_json_finalize(wb);
2075
2076 rrdcontext_release(rca);
2077
@@ -2156,24 +2095,19 @@ int rrdcontexts_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before,
2095 if(after != 0 && before != 0)
2096 rrdr_relative_window_to_absolute(&after, &before);
2097
2159 - buffer_sprintf(wb, "{\n"
2160 - "\t\"hostname\": \"%s\""
2161 - ",\n\t\"machine_guid\": \"%s\""
2162 - ",\n\t\"node_id\": \"%s\""
2163 - ",\n\t\"claim_id\": \"%s\""
2164 - , rrdhost_hostname(host)
2165 - , host->machine_guid
2166 - , node_uuid
2167 - , host->aclk_state.claimed_id ? host->aclk_state.claimed_id : ""
2168 - );
2098 + buffer_json_initialize(wb, "\"", "\"", 0, true);
2099 + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(host));
2100 + buffer_json_member_add_string(wb, "machine_guid", host->machine_guid);
2101 + buffer_json_member_add_string(wb, "node_id", node_uuid);
2102 + buffer_json_member_add_string(wb, "claim_id", host->aclk_state.claimed_id ? host->aclk_state.claimed_id : "");
2103
2104 if(options & RRDCONTEXT_OPTION_SHOW_LABELS) {
2171 - buffer_sprintf(wb, ",\n\t\"host_labels\": {\n");
2172 - rrdlabels_to_buffer(host->rrdlabels, wb, "\t\t", ":", "\"", ",\n", NULL, NULL, NULL, NULL);
2173 - buffer_strcat(wb, "\n\t}");
2105 + buffer_json_member_add_object(wb, "host_labels");
2106 + rrdlabels_to_buffer_json_members(host->rrdlabels, wb);
2107 + buffer_json_object_close(wb);
2108 }
2109
2176 - buffer_sprintf(wb, ",\n\t\"contexts\": {");
2110 + buffer_json_member_add_object(wb, "contexts");
2111 struct rrdcontext_to_json t_contexts = {
2112 .wb = wb,
2113 .options = options,
@@ -2186,9 +2120,9 @@ int rrdcontexts_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before,
2120 .now = now_realtime_sec(),
2121 };
2122 dictionary_walkthrough_read((DICTIONARY *)host->rrdctx, rrdcontext_to_json_callback, &t_contexts);
2123 + buffer_json_object_close(wb);
2124
2190 - // close contexts, close main
2191 - buffer_strcat(wb, "\n\t}\n}");
2125 + buffer_json_finalize(wb);
2126
2127 return HTTP_RESP_OK;
2128 }
@@ -2209,7 +2143,7 @@ static void metric_entry_delete_callback(const DICTIONARY_ITEM *item __maybe_unu
2143 rrdmetric_release(t->rma);
2144 }
2145 static bool metric_entry_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused, void *old_value __maybe_unused, void *new_value __maybe_unused, void *data __maybe_unused) {
2212 - fatal("RRDCONTEXT: %s() detected a conflict on a metric pointer!", __FUNCTION__);
2146 + internal_fatal("RRDCONTEXT: %s() detected a conflict on a metric pointer!", __FUNCTION__);
2147 return false;
2148 }
2149
@@ -2768,8 +2702,8 @@ void query_target_generate_name(QUERY_TARGET *qt) {
2702 , (long long)qt->request.after
2703 , (long long)qt->request.before
2704 , qt->request.points
2771 - , web_client_api_request_v1_data_group_to_string(qt->request.group_method)
2772 - , qt->request.group_options?qt->request.group_options:""
2705 + , time_grouping_tostring(qt->request.time_group_method)
2706 + , qt->request.time_group_options ? qt->request.time_group_options : ""
2707 , options_buffer
2708 , resampling_buffer
2709 , tier_buffer
@@ -2783,8 +2717,8 @@ void query_target_generate_name(QUERY_TARGET *qt) {
2717 , (long long)qt->request.after
2718 , (long long)qt->request.before
2719 , qt->request.points
2786 - , web_client_api_request_v1_data_group_to_string(qt->request.group_method)
2787 - , qt->request.group_options?qt->request.group_options:""
2720 + , time_grouping_tostring(qt->request.time_group_method)
2721 + , qt->request.time_group_options ? qt->request.time_group_options : ""
2722 , options_buffer
2723 , resampling_buffer
2724 , tier_buffer
@@ -2798,8 +2732,8 @@ void query_target_generate_name(QUERY_TARGET *qt) {
2732 , (long long)qt->request.after
2733 , (long long)qt->request.before
2734 , qt->request.points
2801 - , web_client_api_request_v1_data_group_to_string(qt->request.group_method)
2802 - , qt->request.group_options?qt->request.group_options:""
2735 + , time_grouping_tostring(qt->request.time_group_method)
2736 + , qt->request.time_group_options ? qt->request.time_group_options : ""
2737 , options_buffer
2738 , resampling_buffer
2739 , tier_buffer
database/rrdcontext.h
+20 -6
@@ -172,6 +172,7 @@ typedef struct query_metric {
172 #define MAX_QUERY_TARGET_ID_LENGTH 255
173
174 typedef struct query_target_request {
175 + // selecting / filtering metrics to be queried
176 RRDHOST *host; // the host to be queried (can be NULL, hosts will be used)
177 RRDCONTEXT_ACQUIRED *rca; // the context to be queried (can be NULL)
178 RRDINSTANCE_ACQUIRED *ria; // the instance to be queried (can be NULL)
@@ -183,18 +184,31 @@ typedef struct query_target_request {
184 const char *dimensions; // dimensions simple pattern
185 const char *chart_label_key; // select only the chart having this label key
186 const char *charts_labels_filter; // select only the charts having this combo of label key:value
187 +
188 time_t after; // the requested timeframe
189 time_t before; // the requested timeframe
188 - size_t points; // the requested number of points
189 - time_t timeout; // the timeout of the query in seconds
190 + size_t points; // the requested number of points to be returned
191 +
192 uint32_t format; // DATASOURCE_FORMAT
193 RRDR_OPTIONS options;
192 - RRDR_GROUPING group_method;
193 - const char *group_options;
194 - time_t resampling_time;
194 + time_t timeout; // the timeout of the query in seconds
195 +
196 size_t tier;
197 QUERY_SOURCE query_source;
198 STORAGE_PRIORITY priority;
199 +
200 + // resampling metric values across time
201 + time_t resampling_time;
202 +
203 + // grouping metric values across time
204 + RRDR_TIME_GROUPING time_group_method;
205 + const char *time_group_options;
206 +
207 + // group by across multiple time-series
208 + RRDR_GROUP_BY group_by;
209 + const char *group_by_key;
210 + RRDR_GROUP_BY_FUNCTION group_by_function;
211 +
212 } QUERY_TARGET_REQUEST;
213
214 typedef struct query_target {
@@ -212,7 +226,7 @@ typedef struct query_target {
226 time_t query_granularity;
227 size_t points; // the number of points the query will return (maybe different from the request)
228 size_t group;
215 - RRDR_GROUPING group_method;
229 + RRDR_TIME_GROUPING group_method;
230 const char *group_options;
231 size_t resampling_group;
232 NETDATA_DOUBLE resampling_divisor;
database/rrdfunctions.c
+25 -10
@@ -496,7 +496,7 @@ static void rrd_function_call_wait_free(struct rrd_function_call_wait *tmp) {
496
497 struct {
498 const char *format;
499 - uint8_t content_type;
499 + HTTP_CONTENT_TYPE content_type;
500 } function_formats[] = {
501 { .format = "application/json", CT_APPLICATION_JSON },
502 { .format = "text/plain", CT_TEXT_PLAIN },
@@ -523,7 +523,7 @@ uint8_t functions_format_to_content_type(const char *format) {
523 return CT_TEXT_PLAIN;
524 }
525
526 -const char *functions_content_type_to_format(uint8_t content_type) {
526 +const char *functions_content_type_to_format(HTTP_CONTENT_TYPE content_type) {
527 for (int i = 0; function_formats[i].format; i++)
528 if (function_formats[i].content_type == content_type)
529 return function_formats[i].format;
@@ -537,7 +537,7 @@ int rrd_call_function_error(BUFFER *wb, const char *msg, int code) {
537
538 buffer_flush(wb);
539 buffer_sprintf(wb, "{\"status\":%d,\"error_message\":\"%s\"}", code, buffer);
540 - wb->contenttype = CT_APPLICATION_JSON;
540 + wb->content_type = CT_APPLICATION_JSON;
541 buffer_no_cacheable(wb);
542 return code;
543 }
@@ -632,7 +632,7 @@ int rrd_call_function_and_wait(RRDHOST *host, BUFFER *wb, int timeout, const cha
632
633 bool we_should_free = true;
634 BUFFER *temp_wb = buffer_create(PLUGINSD_LINE_MAX + 1, &netdata_buffers_statistics.buffers_functions); // we need it because we may give up on it
635 - temp_wb->contenttype = wb->contenttype;
635 + temp_wb->content_type = wb->content_type;
636 code = rdcf->function(temp_wb, timeout, key, rdcf->collector_data, rrd_call_function_signal_when_ready, tmp);
637 if (code == HTTP_RESP_OK) {
638 netdata_mutex_lock(&tmp->mutex);
@@ -647,7 +647,7 @@ int rrd_call_function_and_wait(RRDHOST *host, BUFFER *wb, int timeout, const cha
647 if (tmp->data_are_ready) {
648 // we have a response
649 buffer_fast_strcat(wb, buffer_tostring(temp_wb), buffer_strlen(temp_wb));
650 - wb->contenttype = temp_wb->contenttype;
650 + wb->content_type = temp_wb->content_type;
651 wb->expires = temp_wb->expires;
652
653 if(wb->expires)
@@ -738,14 +738,29 @@ void chart_functions2json(RRDSET *st, BUFFER *wb, int tabs, const char *kq, cons
738 functions2json(st->functions_view, wb, ident, kq, sq);
739 }
740
741 -void host_functions2json(RRDHOST *host, BUFFER *wb, int tabs, const char *kq, const char *sq) {
741 +void host_functions2json(RRDHOST *host, BUFFER *wb) {
742 if(!host || !host->functions) return;
743
744 - char ident[tabs + 1];
745 - ident[tabs] = '\0';
746 - while(tabs) ident[--tabs] = '\t';
744 + buffer_json_member_add_object(wb, "functions");
745 +
746 + struct rrd_collector_function *t;
747 + dfe_start_read(host->functions, t) {
748 + if(!t->collector->running) continue;
749 +
750 + buffer_json_member_add_object(wb, t_dfe.name);
751 + buffer_json_member_add_string(wb, "help", string2str(t->help));
752 + buffer_json_member_add_int64(wb, "timeout", t->timeout);
753 + buffer_json_member_add_array(wb, "options");
754 + if(t->options & RRD_FUNCTION_GLOBAL)
755 + buffer_json_add_array_item_string(wb, "GLOBAL");
756 + if(t->options & RRD_FUNCTION_LOCAL)
757 + buffer_json_add_array_item_string(wb, "LOCAL");
758 + buffer_json_array_close(wb);
759 + buffer_json_object_close(wb);
760 + }
761 + dfe_done(t);
762
748 - functions2json(host->functions, wb, ident, kq, sq);
763 + buffer_json_object_close(wb);
764 }
765
766 void chart_functions_to_dict(DICTIONARY *rrdset_functions_view, DICTIONARY *dst) {
database/rrdfunctions.h
+2 -2
@@ -26,10 +26,10 @@ void rrd_functions_expose_rrdpush(RRDSET *st, BUFFER *wb);
26
27 void chart_functions2json(RRDSET *st, BUFFER *wb, int tabs, const char *kq, const char *sq);
28 void chart_functions_to_dict(DICTIONARY *rrdset_functions_view, DICTIONARY *dst);
29 -void host_functions2json(RRDHOST *host, BUFFER *wb, int tabs, const char *kq, const char *sq);
29 +void host_functions2json(RRDHOST *host, BUFFER *wb);
30
31 uint8_t functions_format_to_content_type(const char *format);
32 -const char *functions_content_type_to_format(uint8_t content_type);
32 +const char *functions_content_type_to_format(HTTP_CONTENT_TYPE content_type);
33 int rrd_call_function_error(BUFFER *wb, const char *msg, int code);
34
35 #endif // NETDATA_RRDFUNCTIONS_H
database/rrdhost.c
+1 -1
@@ -1071,7 +1071,7 @@ static void rrdhost_streaming_sender_structures_init(RRDHOST *host)
1071
1072 host->sender->host = host;
1073 host->sender->buffer = cbuffer_new(CBUFFER_INITIAL_SIZE, 1024 * 1024, &netdata_buffers_statistics.cbuffers_streaming);
1074 - host->sender->capabilities = STREAM_OUR_CAPABILITIES;
1074 + host->sender->capabilities = stream_our_capabilities();
1075
1076 host->sender->rrdpush_sender_pipe[PIPE_READ] = -1;
1077 host->sender->rrdpush_sender_pipe[PIPE_WRITE] = -1;
database/rrdlabels.c
+22
@@ -651,6 +651,20 @@ void rrdlabels_get_value_to_buffer_or_null(DICTIONARY *labels, BUFFER *wb, const
651 dictionary_acquired_item_release(labels, acquired_item);
652 }
653
654 +void rrdlabels_value_to_buffer_array_item_or_null(DICTIONARY *labels, BUFFER *wb, const char *key) {
655 + if(!labels) return;
656 +
657 + const DICTIONARY_ITEM *acquired_item = dictionary_get_and_acquire_item(labels, key);
658 + RRDLABEL *lb = dictionary_acquired_item_value(acquired_item);
659 +
660 + if(lb && lb->label_value)
661 + buffer_json_add_array_item_string(wb, string2str(lb->label_value));
662 + else
663 + buffer_json_add_array_item_string(wb, NULL);
664 +
665 + dictionary_acquired_item_release(labels, acquired_item);
666 +}
667 +
668 // ----------------------------------------------------------------------------
669 // rrdlabels_get_value_to_char_or_null()
670
@@ -959,6 +973,14 @@ int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each,
973 return dictionary_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
974 }
975
976 +void rrdlabels_to_buffer_json_members(DICTIONARY *labels, BUFFER *wb) {
977 + RRDLABEL *lb;
978 + dfe_start_read(labels, lb) {
979 + buffer_json_member_add_string(wb, lb_dfe.name, string2str(lb->label_value));
980 + }
981 + dfe_done(lb);
982 +}
983 +
984 void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels) {
985 if(!st->rrdlabels)
986 st->rrdlabels = rrdlabels_create();
database/sqlite/sqlite_aclk.c
+1 -1
@@ -368,7 +368,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
368 , (const char *) argv[IDX_OS]
369 , (const char *) argv[IDX_TIMEZONE]
370 , (const char *) argv[IDX_ABBREV_TIMEZONE]
371 - , argv[IDX_UTC_OFFSET] ? str2uint32_t(argv[IDX_UTC_OFFSET]) : 0
371 + , argv[IDX_UTC_OFFSET] ? str2uint32_t(argv[IDX_UTC_OFFSET], NULL) : 0
372 , (const char *) argv[IDX_TAGS]
373 , (const char *) (argv[IDX_PROGRAM_NAME] ? argv[IDX_PROGRAM_NAME] : "unknown")
374 , (const char *) (argv[IDX_PROGRAM_VERSION] ? argv[IDX_PROGRAM_VERSION] : "unknown")
database/sqlite/sqlite_aclk_node.c
+1 -1
@@ -91,7 +91,7 @@ void sql_build_node_info(struct aclk_database_worker_config *wc, struct aclk_dat
91 node_info.data.kernel_name = host->system_info->kernel_name;
92 node_info.data.kernel_version = host->system_info->kernel_version;
93 node_info.data.architecture = host->system_info->architecture;
94 - node_info.data.cpus = host->system_info->host_cores ? str2uint32_t(host->system_info->host_cores) : 0;
94 + node_info.data.cpus = host->system_info->host_cores ? str2uint32_t(host->system_info->host_cores, NULL) : 0;
95 node_info.data.cpu_frequency = host->system_info->host_cpu_freq ? host->system_info->host_cpu_freq : "0";
96 node_info.data.memory = host->system_info->host_ram_total ? host->system_info->host_ram_total : "0";
97 node_info.data.disk_space = host->system_info->host_disk_space ? host->system_info->host_disk_space : "0";
database/sqlite/sqlite_db_migration.c
+1 -1
@@ -7,7 +7,7 @@ static int return_int_cb(void *data, int argc, char **argv, char **column)
7 int *status = data;
8 UNUSED(argc);
9 UNUSED(column);
10 - *status = str2uint32_t(argv[0]);
10 + *status = str2uint32_t(argv[0], NULL);
11 return 0;
12 }
13
health/health_config.c
+4 -4
@@ -260,7 +260,7 @@ static SIMPLE_PATTERN *health_pattern_from_foreach(const char *s) {
260
261 static inline int health_parse_db_lookup(
262 size_t line, const char *filename, char *string,
263 - RRDR_GROUPING *group_method, int *after, int *before, int *every,
263 + RRDR_TIME_GROUPING *group_method, int *after, int *before, int *every,
264 RRDCALC_OPTIONS *options, STRING **dimensions, STRING **foreachdim
265 ) {
266 debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s: %s", line, filename, string);
@@ -286,7 +286,7 @@ static inline int health_parse_db_lookup(
286 return 0;
287 }
288
289 - if((*group_method = web_client_api_request_v1_data_group(key, RRDR_GROUPING_UNDEFINED)) == RRDR_GROUPING_UNDEFINED) {
289 + if((*group_method = time_grouping_parse(key, RRDR_GROUPING_UNDEFINED)) == RRDR_GROUPING_UNDEFINED) {
290 error("Health configuration at line %zu of file '%s': invalid group method '%s'",
291 line, filename, key);
292 return 0;
@@ -773,7 +773,7 @@ static int health_readfile(const char *filename, void *data) {
773 if (rc->dimensions)
774 alert_cfg->p_db_lookup_dimensions = string_dup(rc->dimensions);
775 if (rc->group)
776 - alert_cfg->p_db_lookup_method = string_strdupz(group_method2string(rc->group));
776 + alert_cfg->p_db_lookup_method = string_strdupz(time_grouping_method2string(rc->group));
777 alert_cfg->p_db_lookup_options = rc->options;
778 alert_cfg->p_db_lookup_after = rc->after;
779 alert_cfg->p_db_lookup_before = rc->before;
@@ -1037,7 +1037,7 @@ static int health_readfile(const char *filename, void *data) {
1037 alert_cfg->p_db_lookup_dimensions = string_dup(rt->dimensions);
1038
1039 if (rt->group)
1040 - alert_cfg->p_db_lookup_method = string_strdupz(group_method2string(rt->group));
1040 + alert_cfg->p_db_lookup_method = string_strdupz(time_grouping_method2string(rt->group));
1041
1042 alert_cfg->p_db_lookup_options = rt->options;
1043 alert_cfg->p_db_lookup_after = rt->after;
health/health_json.c
+11 -11
@@ -103,11 +103,11 @@ void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host)
103 }
104
105 buffer_strcat(wb, "\t\t\"value\":");
106 - buffer_rrd_value(wb, ae->new_value);
106 + buffer_print_netdata_double(wb, ae->new_value);
107 buffer_strcat(wb, ",\n");
108
109 buffer_strcat(wb, "\t\t\"old_value\":");
110 - buffer_rrd_value(wb, ae->old_value);
110 + buffer_print_netdata_double(wb, ae->old_value);
111 buffer_strcat(wb, "\n");
112
113 buffer_strcat(wb, "\t}");
@@ -152,7 +152,7 @@ static inline void health_rrdcalc_values2json_nolock(RRDHOST *host, BUFFER *wb,
152 , (unsigned long)rc->id);
153
154 buffer_strcat(wb, "\t\t\t\"value\":");
155 - buffer_rrd_value(wb, rc->value);
155 + buffer_print_netdata_double(wb, rc->value);
156 buffer_strcat(wb, ",\n");
157
158 buffer_strcat(wb, "\t\t\t\"last_updated\":");
@@ -257,11 +257,11 @@ static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC
257 "\t\t\t\"lookup_after\": %d,\n"
258 "\t\t\t\"lookup_before\": %d,\n"
259 "\t\t\t\"lookup_options\": \"",
260 - (unsigned long) rc->db_after,
261 - (unsigned long) rc->db_before,
262 - group_method2string(rc->group),
263 - rc->after,
264 - rc->before
260 + (unsigned long) rc->db_after,
261 + (unsigned long) rc->db_before,
262 + time_grouping_method2string(rc->group),
263 + rc->after,
264 + rc->before
265 );
266 buffer_data_options2string(wb, rc->options);
267 buffer_strcat(wb, "\",\n");
@@ -283,15 +283,15 @@ static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC
283 }
284
285 buffer_strcat(wb, "\t\t\t\"green\":");
286 - buffer_rrd_value(wb, rc->green);
286 + buffer_print_netdata_double(wb, rc->green);
287 buffer_strcat(wb, ",\n");
288
289 buffer_strcat(wb, "\t\t\t\"red\":");
290 - buffer_rrd_value(wb, rc->red);
290 + buffer_print_netdata_double(wb, rc->red);
291 buffer_strcat(wb, ",\n");
292
293 buffer_strcat(wb, "\t\t\t\"value\":");
294 - buffer_rrd_value(wb, rc->value);
294 + buffer_print_netdata_double(wb, rc->value);
295 buffer_strcat(wb, "\n");
296
297 buffer_strcat(wb, "\t\t}");
libnetdata/adaptive_resortable_list/adaptive_resortable_list.c
+1 -1
@@ -9,7 +9,7 @@ inline void arl_callback_str2ull(const char *name, uint32_t hash, const char *va
9 (void)hash;
10
11 register unsigned long long *d = dst;
12 - *d = str2ull(value);
12 + *d = str2ull(value, NULL);
13 // fprintf(stderr, "name '%s' with hash %u and value '%s' is %llu\n", name, hash, value, *d);
14 }
15
libnetdata/buffer/buffer.c
+201 -288
@@ -2,39 +2,16 @@
2
3 #include "../libnetdata.h"
4
5 -#define BUFFER_OVERFLOW_EOF "EOF"
6 -
5 static inline void buffer_overflow_init(BUFFER *b)
6 {
7 b->buffer[b->size] = '\0';
8 strcpy(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF);
9 }
10
13 -#ifdef NETDATA_INTERNAL_CHECKS
14 -#define buffer_overflow_check(b) _buffer_overflow_check(b, __FILE__, __FUNCTION__, __LINE__)
15 -#else
16 -#define buffer_overflow_check(b)
17 -#endif
18 -
19 -static inline void _buffer_overflow_check(BUFFER *b, const char *file, const char *function, const unsigned long line)
20 -{
21 - if(b->len > b->size) {
22 - error("BUFFER: length %zu is above size %zu, at line %lu, at function %s() of file '%s'.", b->len, b->size, line, function, file);
23 - b->len = b->size;
24 - }
25 -
26 - if(b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0) {
27 - error("BUFFER: detected overflow at line %lu, at function %s() of file '%s'.", line, function, file);
28 - buffer_overflow_init(b);
29 - }
30 -}
31 -
32 -
33 -void buffer_reset(BUFFER *wb)
34 -{
11 +void buffer_reset(BUFFER *wb) {
12 buffer_flush(wb);
13
37 - wb->contenttype = CT_TEXT_PLAIN;
14 + wb->content_type = CT_TEXT_PLAIN;
15 wb->options = 0;
16 wb->date = 0;
17 wb->expires = 0;
@@ -52,8 +29,7 @@ const char *buffer_tostring(BUFFER *wb)
29 return(wb->buffer);
30 }
31
55 -void buffer_char_replace(BUFFER *wb, char from, char to)
56 -{
32 +void buffer_char_replace(BUFFER *wb, char from, char to) {
33 char *s = wb->buffer, *end = &wb->buffer[wb->len];
34
35 while(s != end) {
@@ -64,189 +40,6 @@ void buffer_char_replace(BUFFER *wb, char from, char to)
40 buffer_overflow_check(wb);
41 }
42
67 -// This trick seems to give an 80% speed increase in 32bit systems
68 -// print_number_llu_r() will just print the digits up to the
69 -// point the remaining value fits in 32 bits, and then calls
70 -// print_number_lu_r() to print the rest with 32 bit arithmetic.
71 -
72 -inline char *print_number_lu_r(char *str, unsigned long uvalue) {
73 - char *wstr = str;
74 -
75 - // print each digit
76 - do *wstr++ = (char)('0' + (uvalue % 10)); while(uvalue /= 10);
77 - return wstr;
78 -}
79 -
80 -inline char *print_number_llu_r(char *str, unsigned long long uvalue) {
81 - char *wstr = str;
82 -
83 - // print each digit
84 - do *wstr++ = (char)('0' + (uvalue % 10)); while((uvalue /= 10) && uvalue > (unsigned long long)0xffffffff);
85 - if(uvalue) return print_number_lu_r(wstr, uvalue);
86 - return wstr;
87 -}
88 -
89 -inline char *print_number_llu_r_smart(char *str, unsigned long long uvalue) {
90 - switch (sizeof(void *)) {
91 - case 4:
92 - str = (uvalue > (unsigned long long) 0xffffffff) ? print_number_llu_r(str, uvalue) :
93 - print_number_lu_r(str, uvalue);
94 - break;
95 - case 8:
96 - do {
97 - *str++ = (char) ('0' + (uvalue % 10));
98 - } while (uvalue /= 10);
99 - break;
100 - default:
101 - fatal("Netdata supports only 32-bit & 64-bit systems.");
102 - }
103 -
104 - return str;
105 -}
106 -
107 -void buffer_print_llu(BUFFER *wb, unsigned long long uvalue)
108 -{
109 - buffer_need_bytes(wb, 50);
110 -
111 - switch(uvalue) {
112 - case 0:
113 - buffer_fast_strcat(wb, "0", 1);
114 - return;
115 -
116 - case 1:
117 - buffer_fast_strcat(wb, "1", 1);
118 - return;
119 -
120 - case 5:
121 - buffer_fast_strcat(wb, "5", 1);
122 - return;
123 -
124 - case 10:
125 - buffer_fast_strcat(wb, "10", 2);
126 - return;
127 -
128 - default:
129 - break;
130 - }
131 -
132 - char *str = &wb->buffer[wb->len];
133 - char *wstr = str;
134 -
135 - switch (sizeof(void *)) {
136 - case 8:
137 - do {
138 - *wstr++ = (char) ('0' + (uvalue % 10));
139 - } while (uvalue /= 10);
140 - break;
141 -
142 - case 4:
143 - wstr = (uvalue > (unsigned long long) 0xffffffff) ? print_number_llu_r(wstr, uvalue) :
144 - print_number_lu_r(wstr, uvalue);
145 - break;
146 -
147 - default:
148 - fatal("Netdata supports only 32-bit & 64-bit systems.");
149 - }
150 -
151 - // terminate it
152 - *wstr = '\0';
153 -
154 - // reverse it
155 - char *begin = str, *end = wstr - 1, aux;
156 - while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
157 -
158 - size_t len = wstr - str;
159 - // return the buffer length
160 - wb->len += len;
161 -}
162 -
163 -void buffer_print_ll(BUFFER *wb, long long value)
164 -{
165 - buffer_need_bytes(wb, 50);
166 -
167 - if(value < 0) {
168 - buffer_fast_strcat(wb, "-", 1);
169 - value = -value;
170 - }
171 -
172 - buffer_print_llu(wb, value);
173 -}
174 -
175 -static unsigned char bits03_to_hex[16] = {
176 - [0] = '0',
177 - [1] = '1',
178 - [2] = '2',
179 - [3] = '3',
180 - [4] = '4',
181 - [5] = '5',
182 - [6] = '6',
183 - [7] = '7',
184 - [8] = '8',
185 - [9] = '9',
186 - [10] = 'A',
187 - [11] = 'B',
188 - [12] = 'C',
189 - [13] = 'D',
190 - [14] = 'E',
191 - [15] = 'F'
192 -};
193 -
194 -inline void buffer_print_llu_hex(BUFFER *wb, unsigned long long value)
195 -{
196 - unsigned char buffer[sizeof(unsigned long long) * 2 + 2 + 1]; // 8 bytes * 2 + '0x' + '\0'
197 - unsigned char *e = &buffer[sizeof(unsigned long long) * 2 + 2];
198 - unsigned char *p = e;
199 -
200 - *p-- = '\0';
201 - *p-- = bits03_to_hex[value & 0xF];
202 - value >>= 4;
203 - if(value) {
204 - *p-- = bits03_to_hex[value & 0xF];
205 - value >>= 4;
206 -
207 - while(value) {
208 - *p-- = bits03_to_hex[value & 0xF];
209 - value >>= 4;
210 -
211 - if(value) {
212 - *p-- = bits03_to_hex[value & 0xF];
213 - value >>= 4;
214 - }
215 - }
216 - }
217 - *p-- = 'x';
218 - *p = '0';
219 -
220 - buffer_fast_strcat(wb, (char *)p, e - p);
221 -}
222 -
223 -void buffer_print_ll_hex(BUFFER *wb, long long value) {
224 - if(value < 0) {
225 - buffer_fast_strcat(wb, "-", 1);
226 - value = -value;
227 - }
228 -
229 - buffer_print_llu_hex(wb, value);
230 -}
231 -
232 -inline void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) {
233 - if(unlikely(!txt || !*txt)) return;
234 -
235 - buffer_need_bytes(wb, len + 1);
236 -
237 - char *s = &wb->buffer[wb->len];
238 - const char *end = &txt[len + 1];
239 -
240 - while(txt != end)
241 - *s++ = *txt++;
242 -
243 - wb->len += len;
244 -
245 - // keep it NULL terminating
246 - // not counting it at wb->len
247 - wb->buffer[wb->len] = '\0';
248 -}
249 -
43 void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit) {
44 if(unlikely(flags == SN_EMPTY_SLOT)) {
45 buffer_fast_strcat(wb, "E", 1);
@@ -268,64 +61,6 @@ void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit) {
61 buffer_fast_strcat(wb, "''", 2);
62 }
63
271 -void buffer_strcat(BUFFER *wb, const char *txt)
272 -{
273 - // buffer_sprintf(wb, "%s", txt);
274 -
275 - if(unlikely(!txt || !*txt)) return;
276 -
277 - buffer_need_bytes(wb, 1);
278 -
279 - char *s = &wb->buffer[wb->len], *start, *end = &wb->buffer[wb->size];
280 - size_t len = wb->len;
281 -
282 - start = s;
283 - while(*txt && s != end)
284 - *s++ = *txt++;
285 -
286 - len += s - start;
287 -
288 - wb->len = len;
289 - buffer_overflow_check(wb);
290 -
291 - if(unlikely(*txt)) {
292 - debug(D_WEB_BUFFER, "strcat(): increasing web_buffer at position %zu, size = %zu\n", wb->len, wb->size);
293 - len = strlen(txt);
294 - buffer_fast_strcat(wb, txt, len);
295 - }
296 - else {
297 - // terminate the string
298 - // without increasing the length
299 - buffer_need_bytes(wb, 1);
300 - wb->buffer[wb->len] = '\0';
301 - }
302 -}
303 -
304 -void buffer_strcat_jsonescape(BUFFER *wb, const char *txt)
305 -{
306 - while(*txt) {
307 - switch(*txt) {
308 - case '\\':
309 - buffer_need_bytes(wb, 2);
310 - wb->buffer[wb->len++] = '\\';
311 - wb->buffer[wb->len++] = '\\';
312 - break;
313 - case '"':
314 - buffer_need_bytes(wb, 2);
315 - wb->buffer[wb->len++] = '\\';
316 - wb->buffer[wb->len++] = '"';
317 - break;
318 - default: {
319 - buffer_need_bytes(wb, 1);
320 - wb->buffer[wb->len++] = *txt;
321 - }
322 - }
323 - txt++;
324 - }
325 -
326 - buffer_overflow_check(wb);
327 -}
328 -
64 void buffer_strcat_htmlescape(BUFFER *wb, const char *txt)
65 {
66 while(*txt) {
@@ -412,25 +147,6 @@ void buffer_sprintf(BUFFER *wb, const char *fmt, ...)
147 // the buffer is \0 terminated by vsnprintf
148 }
149
415 -
416 -void buffer_rrd_value(BUFFER *wb, NETDATA_DOUBLE value)
417 -{
418 - buffer_need_bytes(wb, 512);
419 -
420 - if(isnan(value) || isinf(value)) {
421 - buffer_strcat(wb, "null");
422 - return;
423 - }
424 - else
425 - wb->len += print_netdata_double(&wb->buffer[wb->len], value);
426 -
427 - // terminate it
428 - buffer_need_bytes(wb, 1);
429 - wb->buffer[wb->len] = '\0';
430 -
431 - buffer_overflow_check(wb);
432 -}
433 -
150 // generate a javascript date, the fastest possible way...
151 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds)
152 {
@@ -536,7 +252,7 @@ BUFFER *buffer_create(size_t size, size_t *statistics)
252 b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
253 b->buffer[0] = '\0';
254 b->size = size;
539 - b->contenttype = CT_TEXT_PLAIN;
255 + b->content_type = CT_TEXT_PLAIN;
256 b->statistics = statistics;
257 buffer_overflow_init(b);
258 buffer_overflow_check(b);
@@ -585,3 +301,200 @@ void buffer_increase(BUFFER *b, size_t free_size_required) {
301 buffer_overflow_init(b);
302 buffer_overflow_check(b);
303 }
304 +
305 +// ----------------------------------------------------------------------------
306 +
307 +void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth, bool add_anonymous_object) {
308 + strncpyz(wb->json.key_quote, key_quote, BUFFER_QUOTE_MAX_SIZE);
309 + strncpyz(wb->json.value_quote, value_quote, BUFFER_QUOTE_MAX_SIZE);
310 +
311 + wb->json.depth = depth - 1;
312 + _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
313 +
314 + if(add_anonymous_object)
315 + buffer_fast_strcat(wb, "{", 1);
316 +}
317 +
318 +void buffer_json_finalize(BUFFER *wb) {
319 + while(wb->json.depth >= 0) {
320 + switch(wb->json.stack[wb->json.depth].type) {
321 + case BUFFER_JSON_OBJECT:
322 + buffer_json_object_close(wb);
323 + break;
324 +
325 + case BUFFER_JSON_ARRAY:
326 + buffer_json_array_close(wb);
327 + break;
328 +
329 + default:
330 + internal_fatal(true, "BUFFER: unknown json member type in stack");
331 + break;
332 + }
333 + }
334 + buffer_fast_strcat(wb, "\n", 1);
335 +}
336 +
337 +// ----------------------------------------------------------------------------
338 +
339 +const char hex_digits[16] = "0123456789ABCDEF";
340 +const char base64_digits[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
341 +unsigned char hex_value_from_ascii[256];
342 +unsigned char base64_value_from_ascii[256];
343 +
344 +__attribute__((constructor)) void initialize_ascii_maps(void) {
345 + for(size_t i = 0 ; i < 256 ; i++) {
346 + hex_value_from_ascii[i] = 255;
347 + base64_value_from_ascii[i] = 255;
348 + }
349 +
350 + for(size_t i = 0; i < 16 ; i++)
351 + hex_value_from_ascii[(int)hex_digits[i]] = i;
352 +
353 + for(size_t i = 0; i < 64 ; i++)
354 + base64_value_from_ascii[(int)base64_digits[i]] = i;
355 +}
356 +
357 +// ----------------------------------------------------------------------------
358 +// unit test
359 +
360 +static int buffer_expect(BUFFER *wb, const char *expected) {
361 + const char *generated = buffer_tostring(wb);
362 +
363 + if(strcmp(generated, expected) != 0) {
364 + error("BUFFER: mismatch.\nGenerated:\n%s\nExpected:\n%s\n",
365 + generated, expected);
366 + return 1;
367 + }
368 +
369 + return 0;
370 +}
371 +
372 +static int buffer_uint64_roundtrip(BUFFER *wb, NUMBER_ENCODING encoding, uint64_t value, const char *expected) {
373 + int errors = 0;
374 + buffer_flush(wb);
375 + buffer_print_uint64_encoded(wb, encoding, value);
376 +
377 + if(expected)
378 + errors += buffer_expect(wb, expected);
379 +
380 + uint64_t v = str2ull_encoded(buffer_tostring(wb));
381 + if(v != value) {
382 + error("BUFFER: string '%s' does resolves to %llu, expected %llu",
383 + buffer_tostring(wb), (unsigned long long)v, (unsigned long long)value);
384 + errors++;
385 + }
386 + buffer_flush(wb);
387 + return errors;
388 +}
389 +
390 +static int buffer_int64_roundtrip(BUFFER *wb, NUMBER_ENCODING encoding, int64_t value, const char *expected) {
391 + int errors = 0;
392 + buffer_flush(wb);
393 + buffer_print_int64_encoded(wb, encoding, value);
394 +
395 + if(expected)
396 + errors += buffer_expect(wb, expected);
397 +
398 + int64_t v = str2ll_encoded(buffer_tostring(wb));
399 + if(v != value) {
400 + error("BUFFER: string '%s' does resolves to %lld, expected %lld",
401 + buffer_tostring(wb), (long long)v, (long long)value);
402 + errors++;
403 + }
404 + buffer_flush(wb);
405 + return errors;
406 +}
407 +
408 +static int buffer_double_roundtrip(BUFFER *wb, NUMBER_ENCODING encoding, NETDATA_DOUBLE value, const char *expected) {
409 + int errors = 0;
410 + buffer_flush(wb);
411 + buffer_print_netdata_double_encoded(wb, encoding, value);
412 +
413 + if(expected)
414 + errors += buffer_expect(wb, expected);
415 +
416 + NETDATA_DOUBLE v = str2ndd_encoded(buffer_tostring(wb), NULL);
417 + if(v != value) {
418 + error("BUFFER: string '%s' does resolves to %.12f, expected %.12f",
419 + buffer_tostring(wb), v, value);
420 + errors++;
421 + }
422 + buffer_flush(wb);
423 + return errors;
424 +}
425 +
426 +int buffer_unittest(void) {
427 + int errors = 0;
428 + BUFFER *wb = buffer_create(0, NULL);
429 +
430 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 0, "0");
431 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_HEX, 0, "0x0");
432 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_BASE64, 0, "#A");
433 +
434 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 1676071986, "1676071986");
435 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_HEX, 1676071986, "0x63E6D432");
436 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_BASE64, 1676071986, "#Bj5tQy");
437 +
438 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 18446744073709551615ULL, "18446744073709551615");
439 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_HEX, 18446744073709551615ULL, "0xFFFFFFFFFFFFFFFF");
440 + buffer_uint64_roundtrip(wb, NUMBER_ENCODING_BASE64, 18446744073709551615ULL, "#P//////////");
441 +
442 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 0, "0");
443 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_HEX, 0, "0x0");
444 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_BASE64, 0, "#A");
445 +
446 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, -1676071986, "-1676071986");
447 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_HEX, -1676071986, "-0x63E6D432");
448 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_BASE64, -1676071986, "-#Bj5tQy");
449 +
450 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_DECIMAL, (int64_t)-9223372036854775807ULL, "-9223372036854775807");
451 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_HEX, (int64_t)-9223372036854775807ULL, "-0x7FFFFFFFFFFFFFFF");
452 + buffer_int64_roundtrip(wb, NUMBER_ENCODING_BASE64, (int64_t)-9223372036854775807ULL, "-#H//////////");
453 +
454 + buffer_double_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 0, "0");
455 + buffer_double_roundtrip(wb, NUMBER_ENCODING_HEX, 0, "%0");
456 + buffer_double_roundtrip(wb, NUMBER_ENCODING_BASE64, 0, "@A");
457 +
458 + buffer_double_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 1.5, "1.5");
459 + buffer_double_roundtrip(wb, NUMBER_ENCODING_HEX, 1.5, "%3FF8000000000000");
460 + buffer_double_roundtrip(wb, NUMBER_ENCODING_BASE64, 1.5, "@D/4AAAAAAAA");
461 +
462 + buffer_double_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 1.23e+14, "123000000000000");
463 + buffer_double_roundtrip(wb, NUMBER_ENCODING_HEX, 1.23e+14, "%42DBF78AD3AC0000");
464 + buffer_double_roundtrip(wb, NUMBER_ENCODING_BASE64, 1.23e+14, "@ELb94rTrAAA");
465 +
466 + buffer_double_roundtrip(wb, NUMBER_ENCODING_DECIMAL, 9.12345678901234567890123456789e+45, "9.123456789012346128e+45");
467 + buffer_double_roundtrip(wb, NUMBER_ENCODING_HEX, 9.12345678901234567890123456789e+45, "%497991C25C9E4309");
468 + buffer_double_roundtrip(wb, NUMBER_ENCODING_BASE64, 9.12345678901234567890123456789e+45, "@El5kcJcnkMJ");
469 +
470 + buffer_flush(wb);
471 +
472 + {
473 + char buf[1024 + 1];
474 + for(size_t i = 0; i < 1024 ;i++)
475 + buf[i] = (char)(i % 26) + 'A';
476 + buf[1024] = '\0';
477 +
478 + buffer_strcat(wb, buf);
479 + errors += buffer_expect(wb, buf);
480 + }
481 +
482 + buffer_flush(wb);
483 +
484 + buffer_json_initialize(wb, "\"", "\"", 0, true);
485 + buffer_json_finalize(wb);
486 + errors += buffer_expect(wb, "{\n}\n");
487 +
488 + buffer_flush(wb);
489 +
490 + buffer_json_initialize(wb, "\"", "\"", 0, true);
491 + buffer_json_member_add_string(wb, "hello", "world");
492 + buffer_json_member_add_string(wb, "alpha", "this: \" is a double quote");
493 + buffer_json_member_add_object(wb, "object1");
494 + buffer_json_member_add_string(wb, "hello", "world");
495 + buffer_json_finalize(wb);
496 + errors += buffer_expect(wb, "{\n \"hello\":\"world\",\n \"alpha\":\"this: \\\" is a double quote\",\n \"object1\":{\n \"hello\":\"world\"\n }\n}\n");
497 +
498 + return errors;
499 +}
500 +
libnetdata/buffer/buffer.h
+733 -51
@@ -7,44 +7,74 @@
7
8 #define WEB_DATA_LENGTH_INCREASE_STEP 1024
9
10 +#define BUFFER_JSON_MAX_DEPTH 32
11 +
12 +extern const char hex_digits[16];
13 +extern const char base64_digits[64];
14 +extern unsigned char hex_value_from_ascii[256];
15 +extern unsigned char base64_value_from_ascii[256];
16 +
17 +typedef enum __attribute__ ((__packed__)) {
18 + BUFFER_JSON_EMPTY = 0,
19 + BUFFER_JSON_OBJECT,
20 + BUFFER_JSON_ARRAY,
21 +} BUFFER_JSON_NODE_TYPE;
22 +
23 +typedef struct web_buffer_json_node {
24 + BUFFER_JSON_NODE_TYPE type;
25 + uint32_t count:24;
26 +} BUFFER_JSON_NODE;
27 +
28 +#define BUFFER_QUOTE_MAX_SIZE 7
29 +
30 +typedef enum __attribute__ ((__packed__)) {
31 + WB_CONTENT_CACHEABLE = (1 << 0),
32 + WB_CONTENT_NO_CACHEABLE = (1 << 1),
33 +} BUFFER_OPTIONS;
34 +
35 +typedef enum __attribute__ ((__packed__)) {
36 + CT_NONE = 0,
37 + CT_APPLICATION_JSON,
38 + CT_TEXT_PLAIN,
39 + CT_TEXT_HTML,
40 + CT_APPLICATION_X_JAVASCRIPT,
41 + CT_TEXT_CSS,
42 + CT_TEXT_XML,
43 + CT_APPLICATION_XML,
44 + CT_TEXT_XSL,
45 + CT_APPLICATION_OCTET_STREAM,
46 + CT_APPLICATION_X_FONT_TRUETYPE,
47 + CT_APPLICATION_X_FONT_OPENTYPE,
48 + CT_APPLICATION_FONT_WOFF,
49 + CT_APPLICATION_FONT_WOFF2,
50 + CT_APPLICATION_VND_MS_FONTOBJ,
51 + CT_IMAGE_SVG_XML,
52 + CT_IMAGE_PNG,
53 + CT_IMAGE_JPG,
54 + CT_IMAGE_GIF,
55 + CT_IMAGE_XICON,
56 + CT_IMAGE_ICNS,
57 + CT_IMAGE_BMP,
58 + CT_PROMETHEUS,
59 +} HTTP_CONTENT_TYPE;
60 +
61 typedef struct web_buffer {
11 - size_t size; // allocation size of buffer, in bytes
12 - size_t len; // current data length in buffer, in bytes
13 - char *buffer; // the buffer itself
14 - uint8_t contenttype; // the content type of the data in the buffer
15 - uint8_t options; // options related to the content
16 - time_t date; // the timestamp this content has been generated
17 - time_t expires; // the timestamp this content expires
62 + size_t size; // allocation size of buffer, in bytes
63 + size_t len; // current data length in buffer, in bytes
64 + char *buffer; // the buffer itself
65 + HTTP_CONTENT_TYPE content_type; // the content type of the data in the buffer
66 + BUFFER_OPTIONS options; // options related to the content
67 + time_t date; // the timestamp this content has been generated
68 + time_t expires; // the timestamp this content expires
69 size_t *statistics;
19 -} BUFFER;
70
21 -// options
22 -#define WB_CONTENT_CACHEABLE 1
23 -#define WB_CONTENT_NO_CACHEABLE 2
24 -
25 -// content-types
26 -#define CT_APPLICATION_JSON 1
27 -#define CT_TEXT_PLAIN 2
28 -#define CT_TEXT_HTML 3
29 -#define CT_APPLICATION_X_JAVASCRIPT 4
30 -#define CT_TEXT_CSS 5
31 -#define CT_TEXT_XML 6
32 -#define CT_APPLICATION_XML 7
33 -#define CT_TEXT_XSL 8
34 -#define CT_APPLICATION_OCTET_STREAM 9
35 -#define CT_APPLICATION_X_FONT_TRUETYPE 10
36 -#define CT_APPLICATION_X_FONT_OPENTYPE 11
37 -#define CT_APPLICATION_FONT_WOFF 12
38 -#define CT_APPLICATION_FONT_WOFF2 13
39 -#define CT_APPLICATION_VND_MS_FONTOBJ 14
40 -#define CT_IMAGE_SVG_XML 15
41 -#define CT_IMAGE_PNG 16
42 -#define CT_IMAGE_JPG 17
43 -#define CT_IMAGE_GIF 18
44 -#define CT_IMAGE_XICON 19
45 -#define CT_IMAGE_ICNS 20
46 -#define CT_IMAGE_BMP 21
47 -#define CT_PROMETHEUS 22
71 + struct {
72 + char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
73 + char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
74 + int depth;
75 + BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
76 + } json;
77 +} BUFFER;
78
79 #define buffer_cacheable(wb) do { (wb)->options |= WB_CONTENT_CACHEABLE; if((wb)->options & WB_CONTENT_NO_CACHEABLE) (wb)->options &= ~WB_CONTENT_NO_CACHEABLE; } while(0)
80 #define buffer_no_cacheable(wb) do { (wb)->options |= WB_CONTENT_NO_CACHEABLE; if((wb)->options & WB_CONTENT_CACHEABLE) (wb)->options &= ~WB_CONTENT_CACHEABLE; (wb)->expires = 0; } while(0)
@@ -52,12 +82,34 @@ typedef struct web_buffer {
82 #define buffer_strlen(wb) ((wb)->len)
83 const char *buffer_tostring(BUFFER *wb);
84
55 -#define buffer_flush(wb) wb->buffer[(wb)->len = 0] = '\0'
56 -void buffer_reset(BUFFER *wb);
85 +#define BUFFER_OVERFLOW_EOF "EOF"
86 +
87 +#ifdef NETDATA_INTERNAL_CHECKS
88 +#define buffer_overflow_check(b) _buffer_overflow_check(b)
89 +#else
90 +#define buffer_overflow_check(b)
91 +#endif
92 +
93 +static inline void _buffer_overflow_check(BUFFER *b) {
94 + assert(b->len <= b->size &&
95 + "BUFFER: length is above buffer size.");
96 +
97 + assert(!(b->buffer && (b->buffer[b->size] != '\0' || strcmp(&b->buffer[b->size + 1], BUFFER_OVERFLOW_EOF) != 0)) &&
98 + "BUFFER: detected overflow.");
99 +}
100
58 -void buffer_strcat(BUFFER *wb, const char *txt);
59 -void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len);
60 -void buffer_rrd_value(BUFFER *wb, NETDATA_DOUBLE value);
101 +static inline void buffer_flush(BUFFER *wb) {
102 + wb->len = 0;
103 +
104 + wb->json.depth = 0;
105 + wb->json.stack[0].type = BUFFER_JSON_EMPTY;
106 + wb->json.stack[0].count = 0;
107 +
108 + if(wb->buffer)
109 + wb->buffer[0] = '\0';
110 +}
111 +
112 +void buffer_reset(BUFFER *wb);
113
114 void buffer_date(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
115 void buffer_jsdate(BUFFER *wb, int year, int month, int day, int hours, int minutes, int seconds);
@@ -69,25 +121,655 @@ void buffer_increase(BUFFER *b, size_t free_size_required);
121 void buffer_snprintf(BUFFER *wb, size_t len, const char *fmt, ...) PRINTFLIKE(3, 4);
122 void buffer_vsprintf(BUFFER *wb, const char *fmt, va_list args);
123 void buffer_sprintf(BUFFER *wb, const char *fmt, ...) PRINTFLIKE(2,3);
72 -void buffer_strcat_jsonescape(BUFFER *wb, const char *txt);
124 void buffer_strcat_htmlescape(BUFFER *wb, const char *txt);
125
126 void buffer_char_replace(BUFFER *wb, char from, char to);
127
128 void buffer_print_sn_flags(BUFFER *wb, SN_FLAGS flags, bool send_anomaly_bit);
129
79 -char *print_number_lu_r(char *str, unsigned long uvalue);
80 -char *print_number_llu_r(char *str, unsigned long long uvalue);
81 -char *print_number_llu_r_smart(char *str, unsigned long long uvalue);
130 +static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
131 + if(unlikely(buffer->len + needed_free_size >= buffer->size))
132 + buffer_increase(buffer, needed_free_size + 1);
133 +}
134
83 -void buffer_print_llu(BUFFER *wb, unsigned long long uvalue);
84 -void buffer_print_ll(BUFFER *wb, long long value);
85 -void buffer_print_llu_hex(BUFFER *wb, unsigned long long value);
86 -void buffer_print_ll_hex(BUFFER *wb, long long value);
135 +void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth, bool add_anonymous_object);
136 +void buffer_json_finalize(BUFFER *wb);
137
88 -static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
89 - if(unlikely(buffer->size - buffer->len < needed_free_size))
90 - buffer_increase(buffer, needed_free_size);
138 +static inline void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE type) {
139 +#ifdef NETDATA_INTERNAL_CHECKS
140 + assert(wb->json.depth <= BUFFER_JSON_MAX_DEPTH && "BUFFER JSON: max nesting reached");
141 +#endif
142 + wb->json.depth++;
143 + wb->json.stack[wb->json.depth].count = 0;
144 + wb->json.stack[wb->json.depth].type = type;
145 +}
146 +
147 +static inline void _buffer_json_depth_pop(BUFFER *wb) {
148 + wb->json.depth--;
149 +}
150 +
151 +static inline void buffer_fast_strcat(BUFFER *wb, const char *txt, size_t len) {
152 + if(unlikely(!txt || !*txt || !len)) return;
153 +
154 + buffer_need_bytes(wb, len + 1);
155 +
156 + const char *t = txt;
157 + const char *e = &txt[len];
158 +
159 + char *d = &wb->buffer[wb->len];
160 +
161 + while(t != e
162 +#ifdef NETDATA_INTERNAL_CHECKS
163 + && *t
164 +#endif
165 + )
166 + *d++ = *t++;
167 +
168 +#ifdef NETDATA_INTERNAL_CHECKS
169 + assert(!(t != e && !*t) && "BUFFER: source string is shorter than the length given.");
170 +#endif
171 +
172 + wb->len += len;
173 + wb->buffer[wb->len] = '\0';
174 +
175 + buffer_overflow_check(wb);
176 +}
177 +
178 +static inline void buffer_strcat(BUFFER *wb, const char *txt) {
179 + if(unlikely(!txt || !*txt)) return;
180 +
181 + const char *t = txt;
182 + while(*t) {
183 + buffer_need_bytes(wb, 100);
184 + char *s = &wb->buffer[wb->len];
185 + char *d = s;
186 + const char *e = &wb->buffer[wb->size];
187 +
188 + while(*t && d < e)
189 + *d++ = *t++;
190 +
191 + wb->len += d - s;
192 + }
193 +
194 + buffer_need_bytes(wb, 1);
195 + wb->buffer[wb->len] = '\0';
196 +
197 + buffer_overflow_check(wb);
198 +}
199 +
200 +static inline void buffer_json_strcat(BUFFER *wb, const char *txt) {
201 + if(unlikely(!txt || !*txt)) return;
202 +
203 + const char *t = txt;
204 + while(*t) {
205 + buffer_need_bytes(wb, 100);
206 + char *s = &wb->buffer[wb->len];
207 + char *d = s;
208 + const char *e = &wb->buffer[wb->size - 1]; // remove 1 to make room for the escape character
209 +
210 + while(*t && d < e) {
211 + if(unlikely(*t == '\\' || *t == '\"'))
212 + *d++ = '\\';
213 +
214 + *d++ = *t++;
215 + }
216 +
217 + wb->len += d - s;
218 + }
219 +
220 + buffer_need_bytes(wb, 1);
221 + wb->buffer[wb->len] = '\0';
222 +
223 + buffer_overflow_check(wb);
224 +}
225 +
226 +static inline void buffer_json_quoted_strcat(BUFFER *wb, const char *txt) {
227 + if(unlikely(!txt || !*txt)) return;
228 +
229 + if(*txt == '"')
230 + txt++;
231 +
232 + const char *t = txt;
233 + while(*t) {
234 + buffer_need_bytes(wb, 100);
235 + char *s = &wb->buffer[wb->len];
236 + char *d = s;
237 + const char *e = &wb->buffer[wb->size - 1]; // remove 1 to make room for the escape character
238 +
239 + while(*t && d < e) {
240 + if(unlikely(*t == '"' && !t[1])) {
241 + t++;
242 + continue;
243 + }
244 +
245 + if(unlikely(*t == '\\' || *t == '"'))
246 + *d++ = '\\';
247 +
248 + *d++ = *t++;
249 + }
250 +
251 + wb->len += d - s;
252 + }
253 +
254 + buffer_need_bytes(wb, 1);
255 + wb->buffer[wb->len] = '\0';
256 +
257 + buffer_overflow_check(wb);
258 +}
259 +
260 +// This trick seems to give an 80% speed increase in 32bit systems
261 +// print_number_llu_r() will just print the digits up to the
262 +// point the remaining value fits in 32 bits, and then calls
263 +// print_number_lu_r() to print the rest with 32 bit arithmetic.
264 +
265 +static inline char *print_uint32_reversed(char *dst, uint32_t value) {
266 + char *d = dst;
267 + do *d++ = (char)('0' + (value % 10)); while((value /= 10));
268 + return d;
269 +}
270 +
271 +static inline char *print_uint64_reversed(char *dst, uint64_t value) {
272 +#ifdef ENV32BIT
273 + if(value <= (uint64_t)0xffffffff)
274 + return print_uint32_reversed(dst, value);
275 +
276 + char *d = dst;
277 + do *d++ = (char)('0' + (value % 10)); while((value /= 10) && value > (uint64_t)0xffffffff);
278 + if(value) return print_uint32_reversed(d, value);
279 + return d;
280 +#else
281 + char *d = dst;
282 + do *d++ = (char)('0' + (value % 10)); while((value /= 10));
283 + return d;
284 +#endif
285 +}
286 +
287 +static inline char *print_uint32_hex_reversed(char *dst, uint32_t value) {
288 + static const char *digits = "0123456789ABCDEF";
289 + char *d = dst;
290 + do *d++ = digits[value & 0xf]; while((value >>= 4));
291 + return d;
292 +}
293 +
294 +static inline char *print_uint64_hex_reversed(char *dst, uint64_t value) {
295 +#ifdef ENV32BIT
296 + if(value <= (uint64_t)0xffffffff)
297 + return print_uint32_hex_reversed(dst, value);
298 +
299 + char *d = dst;
300 + do *d++ = hex_digits[value & 0xf]; while((value >>= 4) && value > (uint64_t)0xffffffff);
301 + if(value) return print_uint32_hex_reversed(d, value);
302 + return d;
303 +#else
304 + char *d = dst;
305 + do *d++ = hex_digits[value & 0xf]; while((value >>= 4));
306 + return d;
307 +#endif
308 +}
309 +
310 +static inline char *print_uint64_base64_reversed(char *dst, uint64_t value) {
311 + char *d = dst;
312 + do *d++ = base64_digits[value & 63]; while ((value >>= 6));
313 + return d;
314 +}
315 +
316 +static inline void char_array_reverse(char *from, char *to) {
317 + // from and to are inclusive
318 + char *begin = from, *end = to, aux;
319 + while (end > begin) aux = *end, *end-- = *begin, *begin++ = aux;
320 +}
321 +
322 +static inline int print_netdata_double(char *dst, NETDATA_DOUBLE value) {
323 + char *s = dst;
324 +
325 + if(unlikely(value < 0)) {
326 + *s++ = '-';
327 + value = fabsndd(value);
328 + }
329 +
330 + uint64_t fractional_precision = 10000000ULL; // fractional part 7 digits
331 + int fractional_wanted_digits = 7;
332 + int exponent = 0;
333 + if(unlikely(value >= (NETDATA_DOUBLE)(UINT64_MAX / 10))) {
334 + // the number is too big to print using 64bit numbers
335 + // so, let's convert it to exponential notation
336 + exponent = (int)(floorndd(log10ndd(value)));
337 + value /= powndd(10, exponent);
338 +
339 + // the max precision we can support is 18 digits
340 + // (UINT64_MAX is 20, but the first is 1)
341 + fractional_precision = 1000000000000000000ULL; // fractional part 18 digits
342 + fractional_wanted_digits = 18;
343 + }
344 +
345 + char *d = s;
346 + NETDATA_DOUBLE integral_d, fractional_d;
347 + fractional_d = modfndd(value, &integral_d);
348 +
349 + // get the integral and the fractional parts as 64-bit integers
350 + uint64_t integral = (uint64_t)integral_d;
351 + uint64_t fractional = (uint64_t)llrintndd(fractional_d * (NETDATA_DOUBLE)fractional_precision);
352 + if(unlikely(fractional >= fractional_precision)) {
353 + integral++;
354 + fractional -= fractional_precision;
355 + }
356 +
357 + // convert the integral part to string (reversed)
358 + d = print_uint64_reversed(d, integral);
359 + char_array_reverse(s, d - 1); // copy reversed the integral string
360 +
361 + if(likely(fractional != 0)) {
362 + *d++ = '.'; // add the dot
363 +
364 + // convert the fractional part to string (reversed)
365 + d = print_uint64_reversed(s = d, fractional);
366 +
367 + while(d - s < fractional_wanted_digits) *d++ = '0'; // prepend zeros to reach precision
368 + char_array_reverse(s, d - 1); // copy reversed the fractional string
369 +
370 + // remove trailing zeros from the fractional part
371 + while(*(d - 1) == '0') d--;
372 + }
373 +
374 + if(unlikely(exponent != 0)) {
375 + *d++ = 'e';
376 + *d++ = '+';
377 + d = print_uint32_reversed(s = d, exponent);
378 + char_array_reverse(s, d - 1);
379 + }
380 +
381 + *d = '\0';
382 + return (int)(d - dst);
383 +}
384 +
385 +static inline void buffer_print_uint64(BUFFER *wb, uint64_t value) {
386 + buffer_need_bytes(wb, 50);
387 +
388 + char *s = &wb->buffer[wb->len];
389 + char *d = print_uint64_reversed(s, value);
390 + char_array_reverse(s, d - 1);
391 + *d = '\0';
392 + wb->len += d - s;
393 +
394 + buffer_overflow_check(wb);
395 +}
396 +
397 +static inline void buffer_print_int64(BUFFER *wb, int64_t value) {
398 + buffer_need_bytes(wb, 50);
399 +
400 + if(value < 0) {
401 + buffer_fast_strcat(wb, "-", 1);
402 + value = -value;
403 + }
404 +
405 + buffer_print_uint64(wb, (uint64_t)value);
406 +
407 + buffer_overflow_check(wb);
408 +}
409 +
410 +static inline void buffer_print_uint64_hex(BUFFER *wb, uint64_t value) {
411 + buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
412 +
413 + buffer_fast_strcat(wb, HEX_PREFIX, sizeof(HEX_PREFIX) - 1);
414 +
415 + char *s = &wb->buffer[wb->len];
416 + char *d = print_uint64_hex_reversed(s, value);
417 + char_array_reverse(s, d - 1);
418 + *d = '\0';
419 + wb->len += d - s;
420 +
421 + buffer_overflow_check(wb);
422 +}
423 +
424 +static inline void buffer_print_uint64_base64(BUFFER *wb, uint64_t value) {
425 + buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1);
426 +
427 + buffer_fast_strcat(wb, IEEE754_UINT64_B64_PREFIX, sizeof(IEEE754_UINT64_B64_PREFIX) - 1);
428 +
429 + char *s = &wb->buffer[wb->len];
430 + char *d = print_uint64_base64_reversed(s, value);
431 + char_array_reverse(s, d - 1);
432 + *d = '\0';
433 + wb->len += d - s;
434 +
435 + buffer_overflow_check(wb);
436 +}
437 +
438 +static inline void buffer_print_int64_hex(BUFFER *wb, int64_t value) {
439 + buffer_need_bytes(wb, 2);
440 +
441 + if(value < 0) {
442 + buffer_fast_strcat(wb, "-", 1);
443 + value = -value;
444 + }
445 +
446 + buffer_print_uint64_hex(wb, (uint64_t)value);
447 +
448 + buffer_overflow_check(wb);
449 +}
450 +
451 +static inline void buffer_print_int64_base64(BUFFER *wb, int64_t value) {
452 + buffer_need_bytes(wb, 2);
453 +
454 + if(value < 0) {
455 + buffer_fast_strcat(wb, "-", 1);
456 + value = -value;
457 + }
458 +
459 + buffer_print_uint64_base64(wb, (uint64_t)value);
460 +
461 + buffer_overflow_check(wb);
462 +}
463 +
464 +static inline void buffer_print_netdata_double(BUFFER *wb, NETDATA_DOUBLE value) {
465 + buffer_need_bytes(wb, 512 + 2);
466 +
467 + if(isnan(value) || isinf(value)) {
468 + buffer_fast_strcat(wb, "null", 4);
469 + return;
470 + }
471 + else
472 + wb->len += print_netdata_double(&wb->buffer[wb->len], value);
473 +
474 + // terminate it
475 + buffer_need_bytes(wb, 1);
476 + wb->buffer[wb->len] = '\0';
477 +
478 + buffer_overflow_check(wb);
479 +}
480 +
481 +static inline void buffer_print_netdata_double_hex(BUFFER *wb, NETDATA_DOUBLE value) {
482 + buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
483 +
484 + uint64_t *ptr = (uint64_t *) (&value);
485 + buffer_fast_strcat(wb, IEEE754_DOUBLE_HEX_PREFIX, sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1);
486 +
487 + char *s = &wb->buffer[wb->len];
488 + char *d = print_uint64_hex_reversed(s, *ptr);
489 + char_array_reverse(s, d - 1);
490 + *d = '\0';
491 + wb->len += d - s;
492 +
493 + buffer_overflow_check(wb);
494 +}
495 +
496 +static inline void buffer_print_netdata_double_base64(BUFFER *wb, NETDATA_DOUBLE value) {
497 + buffer_need_bytes(wb, sizeof(uint64_t) * 2 + 2 + 1 + 1);
498 +
499 + uint64_t *ptr = (uint64_t *) (&value);
500 + buffer_fast_strcat(wb, IEEE754_DOUBLE_B64_PREFIX, sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1);
501 +
502 + char *s = &wb->buffer[wb->len];
503 + char *d = print_uint64_base64_reversed(s, *ptr);
504 + char_array_reverse(s, d - 1);
505 + *d = '\0';
506 + wb->len += d - s;
507 +
508 + buffer_overflow_check(wb);
509 +}
510 +
511 +typedef enum {
512 + NUMBER_ENCODING_DECIMAL,
513 + NUMBER_ENCODING_HEX,
514 + NUMBER_ENCODING_BASE64,
515 +} NUMBER_ENCODING;
516 +
517 +static inline void buffer_print_int64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, int64_t value) {
518 + if(encoding == NUMBER_ENCODING_BASE64)
519 + return buffer_print_int64_base64(wb, value);
520 +
521 + if(encoding == NUMBER_ENCODING_HEX)
522 + return buffer_print_int64_hex(wb, value);
523 +
524 + return buffer_print_int64(wb, value);
525 +}
526 +
527 +static inline void buffer_print_uint64_encoded(BUFFER *wb, NUMBER_ENCODING encoding, uint64_t value) {
528 + if(encoding == NUMBER_ENCODING_BASE64)
529 + return buffer_print_uint64_base64(wb, value);
530 +
531 + if(encoding == NUMBER_ENCODING_HEX)
532 + return buffer_print_uint64_hex(wb, value);
533 +
534 + return buffer_print_uint64(wb, value);
535 +}
536 +
537 +static inline void buffer_print_netdata_double_encoded(BUFFER *wb, NUMBER_ENCODING encoding, NETDATA_DOUBLE value) {
538 + if(encoding == NUMBER_ENCODING_BASE64)
539 + return buffer_print_netdata_double_base64(wb, value);
540 +
541 + if(encoding == NUMBER_ENCODING_HEX)
542 + return buffer_print_netdata_double_hex(wb, value);
543 +
544 + return buffer_print_netdata_double(wb, value);
545 +}
546 +
547 +static inline void buffer_print_spaces(BUFFER *wb, size_t spaces) {
548 + buffer_need_bytes(wb, spaces * 4 + 1);
549 +
550 + char *d = &wb->buffer[wb->len];
551 + for(size_t i = 0; i < spaces; i++) {
552 + *d++ = ' ';
553 + *d++ = ' ';
554 + *d++ = ' ';
555 + *d++ = ' ';
556 + }
557 +
558 + *d = '\0';
559 + wb->len += spaces * 4;
560 +
561 + buffer_overflow_check(wb);
562 +}
563 +
564 +static inline void buffer_print_json_comma_newline_spacing(BUFFER *wb) {
565 + if(wb->json.stack[wb->json.depth].count)
566 + buffer_fast_strcat(wb, ",\n", 2);
567 + else
568 + buffer_fast_strcat(wb, "\n", 1);
569 +
570 + buffer_print_spaces(wb, wb->json.depth + 1);
571 +}
572 +
573 +static inline void buffer_print_json_key(BUFFER *wb, const char *key) {
574 + buffer_strcat(wb, wb->json.key_quote);
575 + buffer_json_strcat(wb, key);
576 + buffer_strcat(wb, wb->json.key_quote);
577 +}
578 +
579 +static inline void buffer_json_add_string_value(BUFFER *wb, const char *value) {
580 + if(value) {
581 + buffer_strcat(wb, wb->json.value_quote);
582 + buffer_json_strcat(wb, value);
583 + buffer_strcat(wb, wb->json.value_quote);
584 + }
585 + else
586 + buffer_fast_strcat(wb, "null", 4);
587 +}
588 +
589 +static inline void buffer_json_add_quoted_string_value(BUFFER *wb, const char *value) {
590 + if(value) {
591 + buffer_strcat(wb, wb->json.value_quote);
592 + buffer_json_quoted_strcat(wb, value);
593 + buffer_strcat(wb, wb->json.value_quote);
594 + }
595 + else
596 + buffer_fast_strcat(wb, "null", 4);
597 +}
598 +
599 +static inline void buffer_json_member_add_object(BUFFER *wb, const char *key) {
600 + buffer_print_json_comma_newline_spacing(wb);
601 + buffer_print_json_key(wb, key);
602 + buffer_fast_strcat(wb, ":{", 2);
603 + wb->json.stack[wb->json.depth].count++;
604 +
605 + _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
606 +}
607 +
608 +static inline void buffer_json_object_close(BUFFER *wb) {
609 +#ifdef NETDATA_INTERNAL_CHECKS
610 + assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
611 + assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_OBJECT && "BUFFER JSON: an object is not open to close it");
612 +#endif
613 + buffer_fast_strcat(wb, "\n", 1);
614 + buffer_print_spaces(wb, wb->json.depth);
615 + buffer_fast_strcat(wb, "}", 1);
616 + _buffer_json_depth_pop(wb);
617 +}
618 +
619 +static inline void buffer_json_member_add_string(BUFFER *wb, const char *key, const char *value) {
620 + buffer_print_json_comma_newline_spacing(wb);
621 + buffer_print_json_key(wb, key);
622 + buffer_fast_strcat(wb, ":", 1);
623 + buffer_json_add_string_value(wb, value);
624 +
625 + wb->json.stack[wb->json.depth].count++;
626 +}
627 +
628 +static inline void buffer_json_member_add_string_or_omit(BUFFER *wb, const char *key, const char *value) {
629 + if(value && *value)
630 + buffer_json_member_add_string(wb, key, value);
631 +}
632 +
633 +static inline void buffer_json_member_add_string_or_empty(BUFFER *wb, const char *key, const char *value) {
634 + if(!value)
635 + value = "";
636 +
637 + buffer_json_member_add_string(wb, key, value);
638 +}
639 +
640 +static inline void buffer_json_member_add_quoted_string(BUFFER *wb, const char *key, const char *value) {
641 + buffer_print_json_comma_newline_spacing(wb);
642 + buffer_print_json_key(wb, key);
643 + buffer_fast_strcat(wb, ":", 1);
644 +
645 + if(!value || strcmp(value, "null") == 0)
646 + buffer_fast_strcat(wb, "null", 4);
647 + else
648 + buffer_json_add_quoted_string_value(wb, value);
649 +
650 + wb->json.stack[wb->json.depth].count++;
651 +}
652 +
653 +static inline void buffer_json_member_add_uuid(BUFFER *wb, const char *key, uuid_t *value) {
654 + buffer_print_json_comma_newline_spacing(wb);
655 + buffer_print_json_key(wb, key);
656 + buffer_fast_strcat(wb, ":", 1);
657 +
658 + if(value) {
659 + char uuid[GUID_LEN + 1];
660 + uuid_unparse_lower(*value, uuid);
661 + buffer_json_add_string_value(wb, uuid);
662 + }
663 + else
664 + buffer_json_add_string_value(wb, NULL);
665 +
666 + wb->json.stack[wb->json.depth].count++;
667 +}
668 +
669 +static inline void buffer_json_member_add_boolean(BUFFER *wb, const char *key, bool value) {
670 + buffer_print_json_comma_newline_spacing(wb);
671 + buffer_print_json_key(wb, key);
672 + buffer_fast_strcat(wb, ":", 1);
673 + buffer_strcat(wb, value?"true":"false");
674 +
675 + wb->json.stack[wb->json.depth].count++;
676 +}
677 +
678 +static inline void buffer_json_member_add_array(BUFFER *wb, const char *key) {
679 + buffer_print_json_comma_newline_spacing(wb);
680 + buffer_print_json_key(wb, key);
681 + buffer_fast_strcat(wb, ":[", 2);
682 + wb->json.stack[wb->json.depth].count++;
683 +
684 + _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
685 +}
686 +
687 +static inline void buffer_json_add_array_item_array(BUFFER *wb) {
688 + buffer_print_json_comma_newline_spacing(wb);
689 +
690 + buffer_fast_strcat(wb, "[", 1);
691 + wb->json.stack[wb->json.depth].count++;
692 +
693 + _buffer_json_depth_push(wb, BUFFER_JSON_ARRAY);
694 +}
695 +
696 +static inline void buffer_json_add_array_item_string(BUFFER *wb, const char *value) {
697 + if(wb->json.stack[wb->json.depth].count)
698 + buffer_fast_strcat(wb, ",", 1);
699 +
700 + buffer_json_add_string_value(wb, value);
701 + wb->json.stack[wb->json.depth].count++;
702 +}
703 +
704 +static inline void buffer_json_add_array_item_double(BUFFER *wb, NETDATA_DOUBLE value) {
705 + if(wb->json.stack[wb->json.depth].count)
706 + buffer_fast_strcat(wb, ",", 1);
707 +
708 + buffer_print_netdata_double(wb, value);
709 + wb->json.stack[wb->json.depth].count++;
710 +}
711 +
712 +static inline void buffer_json_add_array_item_uint64(BUFFER *wb, uint64_t value) {
713 + if(wb->json.stack[wb->json.depth].count)
714 + buffer_fast_strcat(wb, ",", 1);
715 +
716 + buffer_print_uint64(wb, value);
717 + wb->json.stack[wb->json.depth].count++;
718 +}
719 +
720 +static inline void buffer_json_add_array_item_object(BUFFER *wb) {
721 + if(wb->json.stack[wb->json.depth].count)
722 + buffer_fast_strcat(wb, ",", 1);
723 +
724 + buffer_fast_strcat(wb, "{", 1);
725 + wb->json.stack[wb->json.depth].count++;
726 +
727 + _buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
728 +}
729 +
730 +static inline void buffer_json_member_add_time_t(BUFFER *wb, const char *key, time_t value) {
731 + buffer_print_json_comma_newline_spacing(wb);
732 + buffer_print_json_key(wb, key);
733 + buffer_fast_strcat(wb, ":", 1);
734 + buffer_print_int64(wb, value);
735 +
736 + wb->json.stack[wb->json.depth].count++;
737 +}
738 +
739 +static inline void buffer_json_member_add_uint64(BUFFER *wb, const char *key, uint64_t value) {
740 + buffer_print_json_comma_newline_spacing(wb);
741 + buffer_print_json_key(wb, key);
742 + buffer_fast_strcat(wb, ":", 1);
743 + buffer_print_uint64(wb, value);
744 +
745 + wb->json.stack[wb->json.depth].count++;
746 +}
747 +
748 +static inline void buffer_json_member_add_int64(BUFFER *wb, const char *key, int64_t value) {
749 + buffer_print_json_comma_newline_spacing(wb);
750 + buffer_print_json_key(wb, key);
751 + buffer_fast_strcat(wb, ":", 1);
752 + buffer_print_int64(wb, value);
753 +
754 + wb->json.stack[wb->json.depth].count++;
755 +}
756 +
757 +static inline void buffer_json_member_add_double(BUFFER *wb, const char *key, NETDATA_DOUBLE value) {
758 + buffer_print_json_comma_newline_spacing(wb);
759 + buffer_print_json_key(wb, key);
760 + buffer_fast_strcat(wb, ":", 1);
761 + buffer_print_netdata_double(wb, value);
762 +
763 + wb->json.stack[wb->json.depth].count++;
764 +}
765 +
766 +static inline void buffer_json_array_close(BUFFER *wb) {
767 +#ifdef NETDATA_INTERNAL_CHECKS
768 + assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
769 + assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_ARRAY && "BUFFER JSON: an array is not open to close it");
770 +#endif
771 + buffer_fast_strcat(wb, "]", 1);
772 + _buffer_json_depth_pop(wb);
773 }
774
775 #endif /* NETDATA_WEB_BUFFER_H */
libnetdata/dictionary/dictionary.h
+1 -1
@@ -112,7 +112,7 @@ struct dictionary_stats {
112 #define dictionary_create_advanced(options, stats, fixed_size) dictionary_create_advanced_with_trace(options, stats, fixed_size, __FUNCTION__, __LINE__, __FILE__)
113 DICTIONARY *dictionary_create_advanced_with_trace(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size, const char *function, size_t line, const char *file);
114 #else
115 -#define dictionary_create(options) dictionary_create_advanced(options, NULL, 0);
115 +#define dictionary_create(options) dictionary_create_advanced(options, NULL, 0)
116 DICTIONARY *dictionary_create_advanced(DICT_OPTIONS options, struct dictionary_stats *stats, size_t fixed_size);
117 #endif
118
libnetdata/inlined.h
+229 -109
@@ -7,15 +7,15 @@
7
8 #ifdef KERNEL_32BIT
9 typedef uint32_t kernel_uint_t;
10 -#define str2kernel_uint_t(string) str2uint32_t(string)
10 +#define str2kernel_uint_t(string) str2uint32_t(string, NULL)
11 #define KERNEL_UINT_FORMAT "%u"
12 #else
13 typedef uint64_t kernel_uint_t;
14 -#define str2kernel_uint_t(string) str2uint64_t(string)
14 +#define str2kernel_uint_t(string) str2uint64_t(string, NULL)
15 #define KERNEL_UINT_FORMAT "%" PRIu64
16 #endif
17
18 -#define str2pid_t(string) str2uint32_t(string)
18 +#define str2pid_t(string) str2uint32_t(string, NULL)
19
20
21 // for faster execution, allow the compiler to inline
@@ -84,24 +84,6 @@ static inline uint32_t fnv1a_uhash32(const char *name) {
84 #define simple_hash(s) fnv1a_hash32(s)
85 #define simple_uhash(s) fnv1a_uhash32(s)
86
87 -static inline size_t indexing_partition_old(Word_t ptr, Word_t modulo) {
88 - size_t total = 0;
89 -
90 - total += (ptr & 0xff) >> 0;
91 - total += (ptr & 0xff00) >> 8;
92 - total += (ptr & 0xff0000) >> 16;
93 - total += (ptr & 0xff000000) >> 24;
94 -
95 - if(sizeof(Word_t) > 4) {
96 - total += (ptr & 0xff00000000) >> 32;
97 - total += (ptr & 0xff0000000000) >> 40;
98 - total += (ptr & 0xff000000000000) >> 48;
99 - total += (ptr & 0xff00000000000000) >> 56;
100 - }
101 -
102 - return (total % modulo);
103 -}
104 -
87 static uint32_t murmur32(uint32_t k) __attribute__((const));
88 static inline uint32_t murmur32(uint32_t k) {
89 k ^= k >> 16;
@@ -135,143 +117,281 @@ static inline size_t indexing_partition(Word_t ptr, Word_t modulo) {
117 #endif
118 }
119
138 -static inline int str2i(const char *s) {
139 - int n = 0;
140 - char c, negative = (char)(*s == '-');
141 - const char *e = s + 30; // max number of character to iterate
142 -
143 - for(c = (char)((negative)?*(++s):*s); c >= '0' && c <= '9' && s < e ; c = *(++s)) {
144 - n *= 10;
145 - n += c - '0';
146 - }
120 +static inline unsigned int str2u(const char *s) {
121 + unsigned int n = 0;
122
148 - if(unlikely(negative))
149 - return -n;
123 + while(*s >= '0' && *s <= '9')
124 + n = n * 10 + (*s++ - '0');
125
126 return n;
127 }
128
154 -static inline long str2l(const char *s) {
155 - long n = 0;
156 - char c, negative = (*s == '-');
157 - const char *e = &s[30]; // max number of character to iterate
158 -
159 - for(c = (negative)?*(++s):*s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
160 - n *= 10;
161 - n += c - '0';
129 +static inline int str2i(const char *s) {
130 + if(unlikely(*s == '-')) {
131 + s++;
132 + return -(int) str2u(s);
133 + }
134 + else {
135 + if(unlikely(*s == '+')) s++;
136 + return (int) str2u(s);
137 }
138 +}
139 +
140 +static inline unsigned long str2ul(const char *s) {
141 + unsigned long n = 0;
142
164 - if(unlikely(negative))
165 - return -n;
143 + while(*s >= '0' && *s <= '9')
144 + n = n * 10 + (*s++ - '0');
145
146 return n;
147 }
148
170 -static inline uint32_t str2uint32_t(const char *s) {
149 +static inline long str2l(const char *s) {
150 + if(unlikely(*s == '-')) {
151 + s++;
152 + return -(long) str2ul(s);
153 + }
154 + else {
155 + if(unlikely(*s == '+')) s++;
156 + return (long) str2ul(s);
157 + }
158 +}
159 +
160 +static inline uint32_t str2uint32_t(const char *s, char **endptr) {
161 uint32_t n = 0;
172 - char c;
173 - const char *e = &s[30]; // max number of character to iterate
162
175 - for(c = *s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
176 - n *= 10;
177 - n += c - '0';
178 - }
163 + while(*s >= '0' && *s <= '9')
164 + n = n * 10 + (*s++ - '0');
165 +
166 + if(unlikely(endptr))
167 + *endptr = (char *)s;
168 +
169 return n;
170 }
171
182 -static inline uint64_t str2uint64_t(const char *s) {
172 +static inline uint64_t str2uint64_t(const char *s, char **endptr) {
173 uint64_t n = 0;
184 - char c;
185 - const char *e = &s[30]; // max number of character to iterate
174
187 - for(c = *s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
188 - n *= 10;
189 - n += c - '0';
190 - }
175 +#ifdef ENV32BIT
176 + unsigned long n32 = 0;
177 + while (*s >= '0' && *s <= '9' && n32 < (ULONG_MAX / 10))
178 + n32 = n32 * 10 + (*s++ - '0');
179 +
180 + n = n32;
181 +#endif
182 +
183 + while(*s >= '0' && *s <= '9')
184 + n = n * 10 + (*s++ - '0');
185 +
186 + if(unlikely(endptr))
187 + *endptr = (char *)s;
188 +
189 return n;
190 }
191
194 -static inline unsigned long str2ul(const char *s) {
195 - unsigned long n = 0;
196 - char c;
197 - const char *e = &s[30]; // max number of character to iterate
192 +static inline unsigned long long int str2ull(const char *s, char **endptr) {
193 + return str2uint64_t(s, endptr);
194 +}
195
199 - for(c = *s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
200 - n *= 10;
201 - n += c - '0';
196 +static inline long long str2ll(const char *s, char **endptr) {
197 + if(unlikely(*s == '-')) {
198 + s++;
199 + return -(long long) str2uint64_t(s, endptr);
200 + }
201 + else {
202 + if(unlikely(*s == '+')) s++;
203 + return (long long) str2uint64_t(s, endptr);
204 }
203 - return n;
205 }
206
206 -static inline unsigned long long str2ull(const char *s) {
207 - unsigned long long n = 0;
208 - char c;
209 - const char *e = &s[30]; // max number of character to iterate
207 +static inline uint64_t str2uint64_hex(const char *src, char **endptr) {
208 + uint64_t num = 0;
209 + const unsigned char *s = (const unsigned char *)src;
210 + unsigned char c;
211
211 - for(c = *s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
212 - n *= 10;
213 - n += c - '0';
212 + while ((c = hex_value_from_ascii[*s]) != 255) {
213 + num = (num << 4) | c;
214 + s++;
215 }
215 - return n;
216 +
217 + if(endptr)
218 + *endptr = (char *)s;
219 +
220 + return num;
221 }
222
218 -static inline unsigned long long str2ull_hex_or_dec(const char *s) {
219 - unsigned long long n = 0;
220 - char c;
223 +static inline uint64_t str2uint64_base64(const char *src, char **endptr) {
224 + uint64_t num = 0;
225 + const unsigned char *s = (const unsigned char *)src;
226 + unsigned char c;
227 +
228 + while ((c = base64_value_from_ascii[*s]) != 255) {
229 + num = (num << 6) | c;
230 + s++;
231 + }
232 +
233 + if(endptr)
234 + *endptr = (char *)s;
235
222 - if(likely(s[0] == '0' && s[1] == 'x')) {
223 - const char *e = &s[sizeof(unsigned long long) * 2 + 2 + 1]; // max number of character to iterate: 8 bytes * 2 + '0x' + '\0'
236 + return num;
237 +}
238
225 - // skip 0x
226 - s += 2;
239 +static inline NETDATA_DOUBLE str2ndd_parse_double_decimal_digits_internal(const char *src, int *digits) {
240 + const char *s = src;
241 + NETDATA_DOUBLE n = 0.0;
242
228 - for (c = *s; ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) && s < e; c = *(++s)) {
229 - n = n << 4;
243 + while(*s >= '0' && *s <= '9') {
244
231 - if (c <= '9')
232 - n += c - '0';
233 - else
234 - n += c - 'A' + 10;
245 + // this works for both 32-bit and 64-bit systems
246 + unsigned long ni = 0;
247 + unsigned exponent = 0;
248 + while (*s >= '0' && *s <= '9' && ni < (ULONG_MAX / 10)) {
249 + ni = (ni * 10) + (*s++ - '0');
250 + exponent++;
251 }
236 - return n;
252 +
253 + n = n * powndd(10.0, exponent) + (NETDATA_DOUBLE)ni;
254 }
238 - else
239 - return str2ull(s);
240 -}
255
242 -static inline long long str2ll_hex_or_dec(const char *s) {
243 - if(*s == '-')
244 - return -(long long)str2ull_hex_or_dec(&s[1]);
245 - else
246 - return (long long)str2ull_hex_or_dec(s);
256 + *digits = (int)(s - src);
257 + return n;
258 }
259
249 -static inline long long str2ll(const char *s, char **endptr) {
250 - int negative = 0;
260 +static inline NETDATA_DOUBLE str2ndd(const char *src, char **endptr) {
261 + const char *s = src;
262 +
263 + NETDATA_DOUBLE sign = 1.0;
264 + NETDATA_DOUBLE result;
265 + int integral_digits = 0;
266 +
267 + NETDATA_DOUBLE fractional = 0.0;
268 + int fractional_digits = 0;
269 +
270 + NETDATA_DOUBLE exponent = 0.0;
271 + int exponent_digits = 0;
272 +
273 + switch(*s) {
274 + case '-':
275 + s++;
276 + sign = -1.0;
277 + break;
278 +
279 + case '+':
280 + s++;
281 + break;
282 +
283 + case 'n':
284 + if(s[1] == 'a' && s[2] == 'n') {
285 + if(endptr) *endptr = (char *)&s[3];
286 + return NAN;
287 + }
288 + if(s[1] == 'u' && s[2] == 'l' && s[3] == 'l') {
289 + if(endptr) *endptr = (char *)&s[3];
290 + return NAN;
291 + }
292 + break;
293 +
294 + case 'i':
295 + if(s[1] == 'n' && s[2] == 'f') {
296 + if(endptr) *endptr = (char *)&s[3];
297 + return INFINITY;
298 + }
299 + break;
300 +
301 + default:
302 + break;
303 + }
304
252 - if(unlikely(*s == '-')) {
305 + result = str2ndd_parse_double_decimal_digits_internal(s, &integral_digits);
306 + s += integral_digits;
307 +
308 + if(unlikely(*s == '.')) {
309 s++;
254 - negative = 1;
310 + fractional = str2ndd_parse_double_decimal_digits_internal(s, &fractional_digits);
311 + s += fractional_digits;
312 }
256 - else if(unlikely(*s == '+'))
313 +
314 + if (unlikely(*s == 'e' || *s == 'E')) {
315 + const char *e_ptr = s;
316 s++;
317
259 - long long n = 0;
260 - char c;
261 - const char *e = &s[30]; // max number of character to iterate
318 + int exponent_sign = 1;
319 + if (*s == '-') {
320 + exponent_sign = -1;
321 + s++;
322 + }
323 + else if(*s == '+')
324 + s++;
325
263 - for(c = *s; c >= '0' && c <= '9' && s < e ; c = *(++s)) {
264 - n *= 10;
265 - n += c - '0';
326 + exponent = str2ndd_parse_double_decimal_digits_internal(s, &exponent_digits);
327 + if(unlikely(!exponent_digits)) {
328 + exponent = 0;
329 + s = e_ptr;
330 + }
331 + else {
332 + s += exponent_digits;
333 + exponent *= exponent_sign;
334 + }
335 }
336
337 if(unlikely(endptr))
338 *endptr = (char *)s;
339
271 - if(unlikely(negative))
272 - return -n;
340 + if (unlikely(exponent_digits))
341 + result *= powndd(10.0, exponent);
342 +
343 + if (unlikely(fractional_digits))
344 + result += fractional / powndd(10.0, fractional_digits) * (exponent_digits ? powndd(10.0, exponent) : 1.0);
345 +
346 + return sign * result;
347 +}
348 +
349 +static inline unsigned long long str2ull_encoded(const char *s) {
350 + if(*s == IEEE754_UINT64_B64_PREFIX[0])
351 + return str2uint64_base64(s + sizeof(IEEE754_UINT64_B64_PREFIX) - 1, NULL);
352 +
353 + if(s[0] == HEX_PREFIX[0] && s[1] == HEX_PREFIX[1])
354 + return str2uint64_hex(s + 2, NULL);
355 +
356 + return str2uint64_t(s, NULL);
357 +}
358 +
359 +static inline long long str2ll_encoded(const char *s) {
360 + if(*s == '-')
361 + return -(long long) str2ull_encoded(&s[1]);
362 else
274 - return n;
363 + return (long long) str2ull_encoded(s);
364 +}
365 +
366 +static inline NETDATA_DOUBLE str2ndd_encoded(const char *src, char **endptr) {
367 + if (*src == IEEE754_DOUBLE_B64_PREFIX[0]) {
368 + // double parsing from base64
369 + uint64_t n = str2uint64_base64(src + sizeof(IEEE754_DOUBLE_B64_PREFIX) - 1, endptr);
370 + NETDATA_DOUBLE *ptr = (NETDATA_DOUBLE *) (&n);
371 + return *ptr;
372 + }
373 +
374 + if (*src == IEEE754_DOUBLE_HEX_PREFIX[0]) {
375 + // double parsing from hex
376 + uint64_t n = str2uint64_hex(src + sizeof(IEEE754_DOUBLE_HEX_PREFIX) - 1, endptr);
377 + NETDATA_DOUBLE *ptr = (NETDATA_DOUBLE *) (&n);
378 + return *ptr;
379 + }
380 +
381 + double sign = 1.0;
382 +
383 + if(*src == '-') {
384 + sign = -1.0;
385 + src++;
386 + }
387 +
388 + if(unlikely(*src == IEEE754_UINT64_B64_PREFIX[0]))
389 + return (NETDATA_DOUBLE) str2uint64_base64(src + sizeof(IEEE754_UINT64_B64_PREFIX) - 1, endptr) * sign;
390 +
391 + if(unlikely(*src == HEX_PREFIX[0] && src[1] == HEX_PREFIX[1]))
392 + return (NETDATA_DOUBLE) str2uint64_hex(src + sizeof(HEX_PREFIX) - 1, endptr) * sign;
393 +
394 + return str2ndd(src, endptr) * sign;
395 }
396
397 static inline char *strncpyz(char *dst, const char *src, size_t n) {
@@ -372,7 +492,7 @@ static inline int read_single_number_file(const char *filename, unsigned long lo
492 }
493
494 buffer[30] = '\0';
375 - *result = str2ull(buffer);
495 + *result = str2ull(buffer, NULL);
496 return 0;
497 }
498
libnetdata/storage_number/storage_number.c
+72 -70
@@ -2,6 +2,78 @@
2
3 #include "../libnetdata.h"
4
5 +bool is_system_ieee754_double(void) {
6 + static bool logged = false;
7 +
8 + struct {
9 + NETDATA_DOUBLE original;
10 +
11 + union {
12 + uint64_t i;
13 + NETDATA_DOUBLE d;
14 + };
15 + } tests[] = {
16 + { .original = 1.25, .i = 0x3FF4000000000000 },
17 + { .original = 1.0, .i = 0x3FF0000000000000 },
18 + { .original = 2.0, .i = 0x4000000000000000 },
19 + { .original = 4.0, .i = 0x4010000000000000 },
20 + { .original = 8.8, .i = 0x402199999999999A },
21 + { .original = 16.16, .i = 0x403028F5C28F5C29 },
22 + { .original = 32.32, .i = 0x404028F5C28F5C29 },
23 + { .original = 64.64, .i = 0x405028F5C28F5C29 },
24 + { .original = 128.128, .i = 0x406004189374BC6A },
25 + { .original = 32768.32768, .i = 0x40E0000A7C5AC472 },
26 + { .original = 65536.65536, .i = 0x40F0000A7C5AC472 },
27 + { .original = -65536.65536, .i = 0xC0F0000A7C5AC472 },
28 + { .original = 65535.65535, .i = 0x40EFFFF4F8A0902E },
29 + { .original = -65535.65535, .i = 0xC0EFFFF4F8A0902E },
30 + { .original = 4.503599627e15, .i = 0x432FFFFFFFF4B180 },
31 + { .original = -4.503599627e15, .i = 0xC32FFFFFFFF4B180 },
32 + { .original = 1.25e25, .i = 0x4524ADF4B7320335 },
33 + { .original = 1.25e307, .i = 0x7FB1CCF385EBC8A0 },
34 + { .original = 1.25e-25, .i = 0x3AC357C299A88EA7 },
35 + { .original = 1.25e-100, .i = 0x2B317F7D4ED8C33E },
36 + { .original = NAN, .i = 0x7FF8000000000000 },
37 + { .original = -INFINITY, .i = 0xFFF0000000000000 },
38 + { .original = INFINITY, .i = 0x7FF0000000000000 },
39 + { .original = 1.25e-132, .i = 0x248C6463225AB7EC },
40 + { .original = 0.0, .i = 0x0000000000000000 },
41 + { .original = -0.0, .i = 0x8000000000000000 },
42 + { .original = DBL_MIN, .i = 0x0010000000000000 },
43 + { .original = DBL_MAX, .i = 0x7FEFFFFFFFFFFFFF },
44 + { .original = -DBL_MIN, .i = 0x8010000000000000 },
45 + { .original = -DBL_MAX, .i = 0xFFEFFFFFFFFFFFFF },
46 + };
47 +
48 + size_t errors = 0;
49 + size_t elements = sizeof(tests) / sizeof(tests[0]);
50 + for(size_t i = 0; i < elements ; i++) {
51 + uint64_t *ptr = (uint64_t *)&tests[i].original;
52 +
53 + if(*ptr != tests[i].i && (tests[i].original == tests[i].d || (isnan(tests[i].original) && isnan(tests[i].d)))) {
54 + if(!logged)
55 + info("IEEE754: test #%zu, value " NETDATA_DOUBLE_FORMAT_G " is represented in this system as %lX, but it was expected as %lX",
56 + i+1, tests[i].original, *ptr, tests[i].i);
57 + errors++;
58 + }
59 + }
60 +
61 + if(!errors && sizeof(NETDATA_DOUBLE) == sizeof(uint64_t)) {
62 + if(!logged)
63 + info("IEEE754: system is using IEEE754 DOUBLE PRECISION values");
64 +
65 + logged = true;
66 + return true;
67 + }
68 + else {
69 + if(!logged)
70 + info("IEEE754: system is NOT compatible with IEEE754 DOUBLE PRECISION values");
71 +
72 + logged = true;
73 + return false;
74 + }
75 +}
76 +
77 storage_number pack_storage_number(NETDATA_DOUBLE value, SN_FLAGS flags) {
78 // bit 32 = sign 0:positive, 1:negative
79 // bit 31 = 0:divide, 1:multiply
@@ -159,73 +231,3 @@ int print_netdata_double(char *str, NETDATA_DOUBLE value)
231 return (int) ((wstr - str) + 2 + decimal );
232 }
233 */
162 -
163 -int print_netdata_double(char *str, NETDATA_DOUBLE value) {
164 - // info("printing number " NETDATA_DOUBLE_FORMAT, value);
165 - char integral_str[50], fractional_str[50];
166 -
167 - char *wstr = str;
168 -
169 - if(unlikely(value < 0)) {
170 - *wstr++ = '-';
171 - value = -value;
172 - }
173 -
174 - NETDATA_DOUBLE integral, fractional;
175 -
176 -#ifdef STORAGE_WITH_MATH
177 - fractional = modfndd(value, &integral) * 10000000.0;
178 -#else
179 - integral = (NETDATA_DOUBLE)((unsigned long long)(value * 10000000ULL) / 10000000ULL);
180 - fractional = (NETDATA_DOUBLE)((unsigned long long)(value * 10000000ULL) % 10000000ULL);
181 -#endif
182 -
183 - unsigned long long integral_int = (unsigned long long)integral;
184 - unsigned long long fractional_int = (unsigned long long)llrintndd(fractional);
185 - if(unlikely(fractional_int >= 10000000)) {
186 - integral_int += 1;
187 - fractional_int -= 10000000;
188 - }
189 -
190 - // info("integral " NETDATA_DOUBLE_FORMAT " (%llu), fractional " NETDATA_DOUBLE_FORMAT " (%llu)", integral, integral_int, fractional, fractional_int);
191 -
192 - char *istre;
193 - if(unlikely(integral_int == 0)) {
194 - integral_str[0] = '0';
195 - istre = &integral_str[1];
196 - }
197 - else
198 - // convert the integral part to string (reversed)
199 - istre = print_number_llu_r_smart(integral_str, integral_int);
200 -
201 - // copy reversed the integral string
202 - istre--;
203 - while( istre >= integral_str ) *wstr++ = *istre--;
204 -
205 - if(likely(fractional_int != 0)) {
206 - // add a dot
207 - *wstr++ = '.';
208 -
209 - // convert the fractional part to string (reversed)
210 - char *fstre = print_number_llu_r_smart(fractional_str, fractional_int);
211 -
212 - // prepend zeros to reach 7 digits length
213 - int decimal = 7;
214 - int len = (int)(fstre - fractional_str);
215 - while(len < decimal) {
216 - *wstr++ = '0';
217 - len++;
218 - }
219 -
220 - char *begin = fractional_str;
221 - while(begin < fstre && *begin == '0') begin++;
222 -
223 - // copy reversed the fractional string
224 - fstre--;
225 - while( fstre >= begin ) *wstr++ = *fstre--;
226 - }
227 -
228 - *wstr = '\0';
229 - // info("printed number '%s'", str);
230 - return (int)(wstr - str);
231 -}
libnetdata/storage_number/storage_number.h
+15 -76
@@ -13,6 +13,7 @@ typedef long double NETDATA_DOUBLE;
13 #define NETDATA_DOUBLE_FORMAT_ZERO "%0.0Lf"
14 #define NETDATA_DOUBLE_FORMAT_AUTO "%Lf"
15 #define NETDATA_DOUBLE_MODIFIER "Lf"
16 +#define NETDATA_DOUBLE_FORMAT_G "%0.19Le"
17
18 #define NETDATA_DOUBLE_MAX LDBL_MAX
19
@@ -24,6 +25,9 @@ typedef long double NETDATA_DOUBLE;
25 #define copysignndd(x, y) copysignl(x, y)
26 #define modfndd(x, y) modfl(x, y)
27 #define fabsndd(x) fabsl(x)
28 +#define floorndd(x) floorl(x)
29 +#define ceilndd(x) ceill(x)
30 +#define log10ndd(x) log10l(x)
31
32 #else // NETDATA_WITH_LONG_DOUBLE
33
@@ -32,6 +36,7 @@ typedef double NETDATA_DOUBLE;
36 #define NETDATA_DOUBLE_FORMAT_ZERO "%0.0f"
37 #define NETDATA_DOUBLE_FORMAT_AUTO "%f"
38 #define NETDATA_DOUBLE_MODIFIER "f"
39 +#define NETDATA_DOUBLE_FORMAT_G "%0.19e"
40
41 #define NETDATA_DOUBLE_MAX DBL_MAX
42
@@ -43,6 +48,9 @@ typedef double NETDATA_DOUBLE;
48 #define copysignndd(x, y) copysign(x, y)
49 #define modfndd(x, y) modf(x, y)
50 #define fabsndd(x) fabs(x)
51 +#define floorndd(x) floor(x)
52 +#define ceilndd(x) ceil(x)
53 +#define log10ndd(x) log10(x)
54
55 #endif // NETDATA_WITH_LONG_DOUBLE
56
@@ -104,8 +112,6 @@ typedef enum {
112 storage_number pack_storage_number(NETDATA_DOUBLE value, SN_FLAGS flags) __attribute__((const));
113 static inline NETDATA_DOUBLE unpack_storage_number(storage_number value) __attribute__((const));
114
107 -int print_netdata_double(char *str, NETDATA_DOUBLE value);
108 -
115 // sign div/mul <--- multiplier / divider ---> 10/100 RESET EXISTS VALUE
116 #define STORAGE_NUMBER_POSITIVE_MAX_RAW (storage_number)( (0 << 31) | (1 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (1 << 26) | (0 << 25) | (1 << 24) | 0x00ffffff )
117 #define STORAGE_NUMBER_POSITIVE_MIN_RAW (storage_number)( (0 << 31) | (0 << 30) | (1 << 29) | (1 << 28) | (1 << 27) | (0 << 26) | (0 << 25) | (1 << 24) | 0x00000001 )
@@ -158,79 +164,12 @@ static inline NETDATA_DOUBLE unpack_storage_number(storage_number value) {
164 return sign * unpack_storage_number_lut10x[(factor * 16) + (exp * 8) + mul] * n;
165 }
166
161 -static inline NETDATA_DOUBLE str2ndd(const char *s, char **endptr) {
162 - int negative = 0;
163 - const char *start = s;
164 - unsigned long long integer_part = 0;
165 - unsigned long decimal_part = 0;
166 - size_t decimal_digits = 0;
167 -
168 - switch(*s) {
169 - case '-':
170 - s++;
171 - negative = 1;
172 - break;
173 -
174 - case '+':
175 - s++;
176 - break;
177 -
178 - case 'n':
179 - if(s[1] == 'a' && s[2] == 'n') {
180 - if(endptr) *endptr = (char *)&s[3];
181 - return NAN;
182 - }
183 - if(s[1] == 'u' && s[2] == 'l' && s[3] == 'l') {
184 - if(endptr) *endptr = (char *)&s[3];
185 - return NAN;
186 - }
187 - break;
188 -
189 - case 'i':
190 - if(s[1] == 'n' && s[2] == 'f') {
191 - if(endptr) *endptr = (char *)&s[3];
192 - return INFINITY;
193 - }
194 - break;
195 -
196 - default:
197 - break;
198 - }
199 -
200 - while (*s >= '0' && *s <= '9') {
201 - integer_part = (integer_part * 10) + (*s - '0');
202 - s++;
203 - }
204 -
205 - if(unlikely(*s == '.')) {
206 - decimal_part = 0;
207 - s++;
208 -
209 - while (*s >= '0' && *s <= '9') {
210 - decimal_part = (decimal_part * 10) + (*s - '0');
211 - s++;
212 - decimal_digits++;
213 - }
214 - }
215 -
216 - if(unlikely(*s == 'e' || *s == 'E'))
217 - return strtondd(start, endptr);
218 -
219 - if(unlikely(endptr))
220 - *endptr = (char *)s;
221 -
222 - if(unlikely(negative)) {
223 - if(unlikely(decimal_digits))
224 - return -((NETDATA_DOUBLE)integer_part + (NETDATA_DOUBLE)decimal_part / powndd(10.0, decimal_digits));
225 - else
226 - return -((NETDATA_DOUBLE)integer_part);
227 - }
228 - else {
229 - if(unlikely(decimal_digits))
230 - return (NETDATA_DOUBLE)integer_part + (NETDATA_DOUBLE)decimal_part / powndd(10.0, decimal_digits);
231 - else
232 - return (NETDATA_DOUBLE)integer_part;
233 - }
234 -}
167 +// all these prefixes should use characters that are not allowed in the numbers they represent
168 +#define HEX_PREFIX "0x" // we check 2 characters when parsing
169 +#define IEEE754_UINT64_B64_PREFIX "#" // we check the 1st character during parsing
170 +#define IEEE754_DOUBLE_B64_PREFIX "@" // we check the 1st character during parsing
171 +#define IEEE754_DOUBLE_HEX_PREFIX "%" // we check the 1st character during parsing
172 +
173 +bool is_system_ieee754_double(void);
174
175 #endif /* NETDATA_STORAGE_NUMBER_H */
ml/Config.cc
+2 -1
@@ -99,7 +99,8 @@ void Config::readMLConfig(void) {
99 Cfg.DimensionAnomalyScoreThreshold = DimensionAnomalyScoreThreshold;
100
101 Cfg.HostAnomalyRateThreshold = HostAnomalyRateThreshold;
102 - Cfg.AnomalyDetectionGroupingMethod = web_client_api_request_v1_data_group(AnomalyDetectionGroupingMethod.c_str(), RRDR_GROUPING_AVERAGE);
102 + Cfg.AnomalyDetectionGroupingMethod = time_grouping_parse(
103 + AnomalyDetectionGroupingMethod.c_str(), RRDR_GROUPING_AVERAGE);
104 Cfg.AnomalyDetectionQueryDuration = AnomalyDetectionQueryDuration;
105
106 Cfg.HostsToSkip = config_get(ConfigSectionML, "hosts to skip from training", "!*");
ml/Config.h
+1 -1
@@ -29,7 +29,7 @@ public:
29 double DimensionAnomalyScoreThreshold;
30
31 double HostAnomalyRateThreshold;
32 - RRDR_GROUPING AnomalyDetectionGroupingMethod;
32 + RRDR_TIME_GROUPING AnomalyDetectionGroupingMethod;
33 time_t AnomalyDetectionQueryDuration;
34
35 bool StreamADCharts;
ml/Host.cc
+17 -17
@@ -19,30 +19,30 @@ void Host::removeChart(Chart *C) {
19 Charts.erase(C->getRS());
20 }
21
22 -void Host::getConfigAsJson(nlohmann::json &Json) const {
23 - Json["version"] = 1;
22 +void Host::getConfigAsJson(BUFFER *wb) const {
23 + buffer_json_member_add_uint64(wb, "version", 1);
24
25 - Json["enabled"] = Cfg.EnableAnomalyDetection;
25 + buffer_json_member_add_boolean(wb, "enabled", Cfg.EnableAnomalyDetection);
26
27 - Json["min-train-samples"] = Cfg.MinTrainSamples;
28 - Json["max-train-samples"] = Cfg.MaxTrainSamples;
29 - Json["train-every"] = Cfg.TrainEvery;
27 + buffer_json_member_add_uint64(wb, "min-train-samples", Cfg.MinTrainSamples);
28 + buffer_json_member_add_uint64(wb, "max-train-samples", Cfg.MaxTrainSamples);
29 + buffer_json_member_add_uint64(wb, "train-every", Cfg.TrainEvery);
30
31 - Json["diff-n"] = Cfg.DiffN;
32 - Json["smooth-n"] = Cfg.SmoothN;
33 - Json["lag-n"] = Cfg.LagN;
31 + buffer_json_member_add_uint64(wb, "diff-n", Cfg.DiffN);
32 + buffer_json_member_add_uint64(wb, "smooth-n", Cfg.SmoothN);
33 + buffer_json_member_add_uint64(wb, "lag-n", Cfg.LagN);
34
35 - Json["random-sampling-ratio"] = Cfg.RandomSamplingRatio;
36 - Json["max-kmeans-iters"] = Cfg.MaxKMeansIters;
35 + buffer_json_member_add_double(wb, "random-sampling-ratio", Cfg.RandomSamplingRatio);
36 + buffer_json_member_add_uint64(wb, "max-kmeans-iters", Cfg.MaxKMeansIters);
37
38 - Json["dimension-anomaly-score-threshold"] = Cfg.DimensionAnomalyScoreThreshold;
38 + buffer_json_member_add_double(wb, "dimension-anomaly-score-threshold", Cfg.DimensionAnomalyScoreThreshold);
39
40 - Json["host-anomaly-rate-threshold"] = Cfg.HostAnomalyRateThreshold;
41 - Json["anomaly-detection-grouping-method"] = group_method2string(Cfg.AnomalyDetectionGroupingMethod);
42 - Json["anomaly-detection-query-duration"] = Cfg.AnomalyDetectionQueryDuration;
40 + buffer_json_member_add_double(wb, "host-anomaly-rate-threshold", Cfg.HostAnomalyRateThreshold);
41 + buffer_json_member_add_string(wb, "anomaly-detection-grouping-method", time_grouping_method2string(Cfg.AnomalyDetectionGroupingMethod));
42 + buffer_json_member_add_time_t(wb, "anomaly-detection-query-duration", Cfg.AnomalyDetectionQueryDuration);
43
44 - Json["hosts-to-skip"] = Cfg.HostsToSkip;
45 - Json["charts-to-skip"] = Cfg.ChartsToSkip;
44 + buffer_json_member_add_string(wb, "hosts-to-skip", Cfg.HostsToSkip.c_str());
45 + buffer_json_member_add_string(wb, "charts-to-skip", Cfg.ChartsToSkip.c_str());
46 }
47
48 void Host::getModelsAsJson(nlohmann::json &Json) {
ml/Host.h
+1 -1
@@ -34,7 +34,7 @@ public:
34 void addChart(Chart *C);
35 void removeChart(Chart *C);
36
37 - void getConfigAsJson(nlohmann::json &Json) const;
37 + void getConfigAsJson(BUFFER *wb) const;
38 void getModelsAsJson(nlohmann::json &Json);
39 void getDetectionInfoAsJson(nlohmann::json &Json) const;
40
ml/ml-dummy.c
+2 -2
@@ -47,9 +47,9 @@ void ml_stop_anomaly_detection_threads(RRDHOST *RH) {
47 UNUSED(RH);
48 }
49
50 -char *ml_get_host_info(RRDHOST *RH) {
50 +void ml_get_host_info(RRDHOST *RH, BUFFER *wb) {
51 (void) RH;
52 - return NULL;
52 + (void) wb;
53 }
54
55 char *ml_get_host_runtime_info(RRDHOST *RH) {
ml/ml.cc
+3 -7
@@ -108,17 +108,13 @@ void ml_dimension_delete(RRDDIM *RD) {
108 RD->ml_dimension = nullptr;
109 }
110
111 -char *ml_get_host_info(RRDHOST *RH) {
112 - nlohmann::json ConfigJson;
113 -
111 +void ml_get_host_info(RRDHOST *RH, BUFFER *wb) {
112 if (RH && RH->ml_host) {
113 Host *H = reinterpret_cast<Host *>(RH->ml_host);
116 - H->getConfigAsJson(ConfigJson);
114 + H->getConfigAsJson(wb);
115 } else {
118 - ConfigJson["enabled"] = false;
116 + buffer_json_member_add_boolean(wb, "enabled", false);
117 }
120 -
121 - return strdupz(ConfigJson.dump(2, '\t').c_str());
118 }
119
120 char *ml_get_host_runtime_info(RRDHOST *RH) {
ml/ml.h
+1 -1
@@ -33,7 +33,7 @@ void ml_start_anomaly_detection_threads(RRDHOST *RH);
33 void ml_stop_anomaly_detection_threads(RRDHOST *RH);
34 void ml_cancel_anomaly_detection_threads(RRDHOST *RH);
35
36 -char *ml_get_host_info(RRDHOST *RH);
36 +void ml_get_host_info(RRDHOST *RH, BUFFER *wb);
37 char *ml_get_host_runtime_info(RRDHOST *RH);
38 char *ml_get_host_models(RRDHOST *RH);
39
registry/registry.c
+2 -2
@@ -59,7 +59,7 @@ static inline void registry_set_person_cookie(struct web_client *w, REGISTRY_PER
59
60 static inline void registry_json_header(RRDHOST *host, struct web_client *w, const char *action, const char *status) {
61 buffer_flush(w->response.data);
62 - w->response.data->contenttype = CT_APPLICATION_JSON;
62 + w->response.data->content_type = CT_APPLICATION_JSON;
63 buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
64 action, status, rrdhost_registry_hostname(host), host->machine_guid);
65 }
@@ -191,7 +191,7 @@ int registry_request_access_json(RRDHOST *host, struct web_client *w, char *pers
191 if(registry.verify_cookies_redirects > 0 && !person_guid[0]) {
192 buffer_flush(w->response.data);
193 registry_set_cookie(w, REGISTRY_VERIFY_COOKIES_GUID);
194 - w->response.data->contenttype = CT_APPLICATION_JSON;
194 + w->response.data->content_type = CT_APPLICATION_JSON;
195 buffer_sprintf(w->response.data, "{ \"status\": \"redirect\", \"registry\": \"%s\" }", registry.registry_to_announce);
196 return 200;
197 }
streaming/receiver.c
+2 -1
@@ -339,7 +339,8 @@ static size_t streaming_parser(struct receiver_state *rpt, struct plugind *cd, i
339 .host = rpt->host,
340 .opaque = rpt,
341 .cd = cd,
342 - .trust_durations = 1
342 + .trust_durations = 1,
343 + .capabilities = rpt->capabilities,
344 };
345
346 PARSER *parser = parser_init(&user, NULL, NULL, fd,
streaming/replication.c
+44 -55
@@ -88,7 +88,7 @@ struct replication_query {
88 bool locked_data_collection;
89 bool execute;
90 bool interrupted;
91 - bool send_anomaly_bit;
91 + STREAM_CAPABILITIES capabilities;
92 } query;
93
94 time_t wall_clock_time;
@@ -114,7 +114,7 @@ static struct replication_query *replication_query_prepare(
114 time_t query_before,
115 bool query_enable_streaming,
116 time_t wall_clock_time,
117 - bool send_anomaly_bit
117 + STREAM_CAPABILITIES capabilities
118 ) {
119 size_t dimensions = rrdset_number_of_dimensions(st);
120 struct replication_query *q = callocz(1, sizeof(struct replication_query) + dimensions * sizeof(struct replication_dimension));
@@ -133,7 +133,7 @@ static struct replication_query *replication_query_prepare(
133 q->query.after = query_after;
134 q->query.before = query_before;
135 q->query.enable_streaming = query_enable_streaming;
136 - q->query.send_anomaly_bit = send_anomaly_bit;
136 + q->query.capabilities = capabilities;
137
138 q->wall_clock_time = wall_clock_time;
139
@@ -212,29 +212,32 @@ static struct replication_query *replication_query_prepare(
212 return q;
213 }
214
215 -void replication_send_chart_collection_state(BUFFER *wb, RRDSET *st) {
215 +static void replication_send_chart_collection_state(BUFFER *wb, RRDSET *st, STREAM_CAPABILITIES capabilities) {
216 + NUMBER_ENCODING encoding = (capabilities & STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_DECIMAL;
217 RRDDIM *rd;
217 - rrddim_foreach_read(rd, st) {
218 - if(!rd->exposed) continue;
219 -
220 - buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_RRDDIM_STATE " '", sizeof(PLUGINSD_KEYWORD_REPLAY_RRDDIM_STATE) - 1 + 2);
221 - buffer_fast_strcat(wb, rrddim_id(rd), string_strlen(rd->id));
222 - buffer_fast_strcat(wb, "' ", 2);
223 - buffer_print_llu(wb, (usec_t)rd->last_collected_time.tv_sec * USEC_PER_SEC + (usec_t)rd->last_collected_time.tv_usec);
224 - buffer_fast_strcat(wb, " ", 1);
225 - buffer_print_ll(wb, rd->last_collected_value);
226 - buffer_fast_strcat(wb, " ", 1);
227 - buffer_rrd_value(wb, rd->last_calculated_value);
228 - buffer_fast_strcat(wb, " ", 1);
229 - buffer_rrd_value(wb, rd->last_stored_value);
230 - buffer_fast_strcat(wb, "\n", 1);
231 - }
218 + rrddim_foreach_read(rd, st){
219 + if (!rd->exposed) continue;
220 +
221 + buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_RRDDIM_STATE " '",
222 + sizeof(PLUGINSD_KEYWORD_REPLAY_RRDDIM_STATE) - 1 + 2);
223 + buffer_fast_strcat(wb, rrddim_id(rd), string_strlen(rd->id));
224 + buffer_fast_strcat(wb, "' ", 2);
225 + buffer_print_uint64_encoded(wb, encoding, (usec_t) rd->last_collected_time.tv_sec * USEC_PER_SEC +
226 + (usec_t) rd->last_collected_time.tv_usec);
227 + buffer_fast_strcat(wb, " ", 1);
228 + buffer_print_int64_encoded(wb, encoding, rd->last_collected_value);
229 + buffer_fast_strcat(wb, " ", 1);
230 + buffer_print_netdata_double_encoded(wb, encoding, rd->last_calculated_value);
231 + buffer_fast_strcat(wb, " ", 1);
232 + buffer_print_netdata_double_encoded(wb, encoding, rd->last_stored_value);
233 + buffer_fast_strcat(wb, "\n", 1);
234 + }
235 rrddim_foreach_done(rd);
236
237 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_RRDSET_STATE " ", sizeof(PLUGINSD_KEYWORD_REPLAY_RRDSET_STATE) - 1 + 1);
235 - buffer_print_llu(wb, (usec_t)st->last_collected_time.tv_sec * USEC_PER_SEC + (usec_t)st->last_collected_time.tv_usec);
238 + buffer_print_uint64_encoded(wb, encoding, (usec_t) st->last_collected_time.tv_sec * USEC_PER_SEC + (usec_t) st->last_collected_time.tv_usec);
239 buffer_fast_strcat(wb, " ", 1);
237 - buffer_print_llu(wb, (usec_t)st->last_updated.tv_sec * USEC_PER_SEC + (usec_t)st->last_updated.tv_usec);
240 + buffer_print_uint64_encoded(wb, encoding, (usec_t) st->last_updated.tv_sec * USEC_PER_SEC + (usec_t) st->last_updated.tv_usec);
241 buffer_fast_strcat(wb, "\n", 1);
242 }
243
@@ -242,7 +245,7 @@ static void replication_query_finalize(BUFFER *wb, struct replication_query *q,
245 size_t dimensions = q->dimensions;
246
247 if(wb && q->query.enable_streaming)
245 - replication_send_chart_collection_state(wb, q->st);
248 + replication_send_chart_collection_state(wb, q->st, q->query.capabilities);
249
250 if(q->query.locked_data_collection) {
251 netdata_spinlock_unlock(&q->st->data_collection_lock);
@@ -304,6 +307,7 @@ static void replication_query_align_to_optimal_before(struct replication_query *
307 static bool replication_query_execute(BUFFER *wb, struct replication_query *q, size_t max_msg_size) {
308 replication_query_align_to_optimal_before(q);
309
310 + NUMBER_ENCODING encoding = (q->query.capabilities & STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_DECIMAL;
311 time_t after = q->query.after;
312 time_t before = q->query.before;
313 size_t dimensions = q->dimensions;
@@ -436,11 +440,11 @@ static bool replication_query_execute(BUFFER *wb, struct replication_query *q, s
440 last_end_time_in_buffer = min_end_time;
441
442 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_BEGIN " '' ", sizeof(PLUGINSD_KEYWORD_REPLAY_BEGIN) - 1 + 4);
439 - buffer_print_llu(wb, min_start_time);
443 + buffer_print_uint64_encoded(wb, encoding, min_start_time);
444 buffer_fast_strcat(wb, " ", 1);
441 - buffer_print_llu(wb, min_end_time);
445 + buffer_print_uint64_encoded(wb, encoding, min_end_time);
446 buffer_fast_strcat(wb, " ", 1);
443 - buffer_print_llu(wb, wall_clock_time);
447 + buffer_print_uint64_encoded(wb, encoding, wall_clock_time);
448 buffer_fast_strcat(wb, "\n", 1);
449
450 // output the replay values for this time
@@ -456,9 +460,9 @@ static bool replication_query_execute(BUFFER *wb, struct replication_query *q, s
460 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_SET " \"", sizeof(PLUGINSD_KEYWORD_REPLAY_SET) - 1 + 2);
461 buffer_fast_strcat(wb, rrddim_id(d->rd), string_strlen(d->rd->id));
462 buffer_fast_strcat(wb, "\" ", 2);
459 - buffer_rrd_value(wb, d->sp.sum);
463 + buffer_print_netdata_double_encoded(wb, encoding, d->sp.sum);
464 buffer_fast_strcat(wb, " ", 1);
461 - buffer_print_sn_flags(wb, d->sp.flags, q->query.send_anomaly_bit);
465 + buffer_print_sn_flags(wb, d->sp.flags, q->query.capabilities & STREAM_CAP_INTERPOLATED);
466 buffer_fast_strcat(wb, "\n", 1);
467
468 points_generated++;
@@ -514,7 +518,7 @@ static struct replication_query *replication_response_prepare(
518 bool requested_enable_streaming,
519 time_t requested_after,
520 time_t requested_before,
517 - bool send_anomaly_bit
521 + STREAM_CAPABILITIES capabilities
522 ) {
523 time_t wall_clock_time = now_realtime_sec();
524
@@ -576,7 +580,7 @@ static struct replication_query *replication_response_prepare(
580 db_first_entry, db_last_entry,
581 requested_after, requested_before, requested_enable_streaming,
582 query_after, query_before, query_enable_streaming,
579 - wall_clock_time, send_anomaly_bit);
583 + wall_clock_time, capabilities);
584 }
585
586 void replication_response_cancel_and_finalize(struct replication_query *q) {
@@ -586,6 +590,7 @@ void replication_response_cancel_and_finalize(struct replication_query *q) {
590 static bool sender_is_still_connected_for_this_request(struct replication_request *rq);
591
592 bool replication_response_execute_and_finalize(struct replication_query *q, size_t max_msg_size) {
593 + NUMBER_ENCODING encoding = (q->query.capabilities & STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_DECIMAL;
594 struct replication_request *rq = q->rq;
595 RRDSET *st = q->st;
596 RRDHOST *host = st->rrdhost;
@@ -624,37 +629,21 @@ bool replication_response_execute_and_finalize(struct replication_query *q, size
629 // last end time of the data we sent
630
631 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_REPLAY_END " ", sizeof(PLUGINSD_KEYWORD_REPLAY_END) - 1 + 1);
627 - buffer_print_ll(wb, st->update_every);
632 + buffer_print_int64_encoded(wb, encoding, st->update_every);
633 buffer_fast_strcat(wb, " ", 1);
629 - buffer_print_llu(wb, db_first_entry);
634 + buffer_print_uint64_encoded(wb, encoding, db_first_entry);
635 buffer_fast_strcat(wb, " ", 1);
631 - buffer_print_llu(wb, db_last_entry);
636 + buffer_print_uint64_encoded(wb, encoding, db_last_entry);
637 +
638 buffer_fast_strcat(wb, enable_streaming ? " true " : " false ", 7);
633 - buffer_print_llu(wb, after);
639 +
640 + buffer_print_uint64_encoded(wb, encoding, after);
641 buffer_fast_strcat(wb, " ", 1);
635 - buffer_print_llu(wb, before);
642 + buffer_print_uint64_encoded(wb, encoding, before);
643 buffer_fast_strcat(wb, " ", 1);
637 - buffer_print_llu(wb, wall_clock_time);
644 + buffer_print_uint64_encoded(wb, encoding, wall_clock_time);
645 buffer_fast_strcat(wb, "\n", 1);
646
640 -// buffer_sprintf(wb, PLUGINSD_KEYWORD_REPLAY_END " %d %llu %llu %s %llu %llu %llu\n",
641 -//
642 -// // current chart update every
643 -// (int)st->update_every
644 -//
645 -// // child first db time, child end db time
646 -// , (unsigned long long)db_first_entry, (unsigned long long)db_last_entry
647 -//
648 -// // start streaming boolean
649 -// , enable_streaming ? "true" : "false"
650 -//
651 -// // after requested, before requested ('before' can be altered by the child when the request had enable_streaming true)
652 -// , (unsigned long long)after, (unsigned long long)before
653 -//
654 -// // child world clock time
655 -// , (unsigned long long)wall_clock_time
656 -// );
657 -
647 worker_is_busy(WORKER_JOB_BUFFER_COMMIT);
648 sender_commit(host->sender, wb);
649 worker_is_busy(WORKER_JOB_CLEANUP);
@@ -1428,7 +1417,7 @@ static bool replication_execute_request(struct replication_request *rq, bool wor
1417 rq->start_streaming,
1418 rq->after,
1419 rq->before,
1431 - stream_has_capability(rq->sender, STREAM_CAP_INTERPOLATED));
1420 + rq->sender->capabilities);
1421 }
1422
1423 if(likely(workers))
@@ -1712,7 +1701,7 @@ static int replication_execute_next_pending_request(bool cancel) {
1701 rq->start_streaming,
1702 rq->after,
1703 rq->before,
1715 - stream_has_capability(rq->sender, STREAM_CAP_INTERPOLATED));
1704 + rq->sender->capabilities);
1705 }
1706
1707 rq->executed = false;
streaming/rrdpush.c
+29 -8
@@ -68,6 +68,23 @@ static void load_stream_conf() {
68 freez(filename);
69 }
70
71 +STREAM_CAPABILITIES stream_our_capabilities() {
72 + return STREAM_CAP_V1 |
73 + STREAM_CAP_V2 |
74 + STREAM_CAP_VN |
75 + STREAM_CAP_VCAPS |
76 + STREAM_CAP_HLABELS |
77 + STREAM_CAP_CLAIM |
78 + STREAM_CAP_CLABELS |
79 + STREAM_CAP_FUNCTIONS |
80 + STREAM_CAP_REPLICATION |
81 + STREAM_CAP_BINARY |
82 + STREAM_CAP_INTERPOLATED |
83 + STREAM_HAS_COMPRESSION |
84 + (ieee754_doubles ? STREAM_CAP_IEEE754 : 0) |
85 + 0;
86 +}
87 +
88 bool rrdpush_receiver_needs_dbengine() {
89 struct section *co;
90
@@ -326,7 +343,7 @@ static void rrdpush_send_chart_metrics(BUFFER *wb, RRDSET *st, struct sender_sta
343 buffer_fast_strcat(wb, "\" ", 2);
344
345 if(st->last_collected_time.tv_sec > st->upstream_resync_time_s)
329 - buffer_print_llu(wb, st->usec_since_last_update);
346 + buffer_print_uint64(wb, st->usec_since_last_update);
347 else
348 buffer_fast_strcat(wb, "0", 1);
349
@@ -341,7 +358,7 @@ static void rrdpush_send_chart_metrics(BUFFER *wb, RRDSET *st, struct sender_sta
358 buffer_fast_strcat(wb, "SET \"", 5);
359 buffer_fast_strcat(wb, rrddim_id(rd), string_strlen(rd->id));
360 buffer_fast_strcat(wb, "\" = ", 4);
344 - buffer_print_ll(wb, rd->collected_value);
361 + buffer_print_int64(wb, rd->collected_value);
362 buffer_fast_strcat(wb, "\n", 1);
363 }
364 else {
@@ -386,6 +403,8 @@ void rrddim_push_metrics_v2(RRDSET_STREAM_BUFFER *rsb, RRDDIM *rd, usec_t point_
403 if(!rsb->wb || !rsb->v2 || !netdata_double_isnumber(n) || !does_storage_number_exist(flags))
404 return;
405
406 + NUMBER_ENCODING integer_encoding = stream_has_capability(rsb, STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_HEX;
407 + NUMBER_ENCODING doubles_encoding = stream_has_capability(rsb, STREAM_CAP_IEEE754) ? NUMBER_ENCODING_BASE64 : NUMBER_ENCODING_DECIMAL;
408 BUFFER *wb = rsb->wb;
409 time_t point_end_time_s = (time_t)(point_end_time_ut / USEC_PER_SEC);
410 if(unlikely(rsb->last_point_end_time_s != point_end_time_s)) {
@@ -396,14 +415,14 @@ void rrddim_push_metrics_v2(RRDSET_STREAM_BUFFER *rsb, RRDDIM *rd, usec_t point_
415 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_BEGIN_V2 " '", sizeof(PLUGINSD_KEYWORD_BEGIN_V2) - 1 + 2);
416 buffer_fast_strcat(wb, rrdset_id(rd->rrdset), string_strlen(rd->rrdset->id));
417 buffer_fast_strcat(wb, "' ", 2);
399 - buffer_print_llu_hex(wb, rd->rrdset->update_every);
418 + buffer_print_uint64_encoded(wb, integer_encoding, rd->rrdset->update_every);
419 buffer_fast_strcat(wb, " ", 1);
401 - buffer_print_llu_hex(wb, point_end_time_s);
420 + buffer_print_uint64_encoded(wb, integer_encoding, point_end_time_s);
421 buffer_fast_strcat(wb, " ", 1);
422 if(point_end_time_s == rsb->wall_clock_time)
423 buffer_fast_strcat(wb, "#", 1);
424 else
406 - buffer_print_llu_hex(wb, rsb->wall_clock_time);
425 + buffer_print_uint64_encoded(wb, integer_encoding, rsb->wall_clock_time);
426 buffer_fast_strcat(wb, "\n", 1);
427
428 rsb->last_point_end_time_s = point_end_time_s;
@@ -413,13 +432,13 @@ void rrddim_push_metrics_v2(RRDSET_STREAM_BUFFER *rsb, RRDDIM *rd, usec_t point_
432 buffer_fast_strcat(wb, PLUGINSD_KEYWORD_SET_V2 " '", sizeof(PLUGINSD_KEYWORD_SET_V2) - 1 + 2);
433 buffer_fast_strcat(wb, rrddim_id(rd), string_strlen(rd->id));
434 buffer_fast_strcat(wb, "' ", 2);
416 - buffer_print_ll_hex(wb, rd->last_collected_value);
435 + buffer_print_int64_encoded(wb, integer_encoding, rd->last_collected_value);
436 buffer_fast_strcat(wb, " ", 1);
437
438 if((NETDATA_DOUBLE)rd->last_collected_value == n)
439 buffer_fast_strcat(wb, "#", 1);
440 else
422 - buffer_rrd_value(wb, n);
441 + buffer_print_netdata_double_encoded(wb, doubles_encoding, n);
442
443 buffer_fast_strcat(wb, " ", 1);
444 buffer_print_sn_flags(wb, flags, true);
@@ -484,6 +503,7 @@ RRDSET_STREAM_BUFFER rrdset_push_metric_initialize(RRDSET *st, time_t wall_clock
503 return (RRDSET_STREAM_BUFFER) { .wb = NULL, };
504
505 return (RRDSET_STREAM_BUFFER) {
506 + .capabilities = host->sender->capabilities,
507 .v2 = stream_has_capability(host->sender, STREAM_CAP_INTERPOLATED),
508 .rrdset_flags = rrdset_flags,
509 .wb = sender_start(host->sender),
@@ -1148,6 +1168,7 @@ static void stream_capabilities_to_string(BUFFER *wb, STREAM_CAPABILITIES caps)
1168 if(caps & STREAM_CAP_REPLICATION) buffer_strcat(wb, "REPLICATION ");
1169 if(caps & STREAM_CAP_BINARY) buffer_strcat(wb, "BINARY ");
1170 if(caps & STREAM_CAP_INTERPOLATED) buffer_strcat(wb, "INTERPOLATED ");
1171 + if(caps & STREAM_CAP_IEEE754) buffer_strcat(wb, "IEEE754 ");
1172 }
1173
1174 void log_receiver_capabilities(struct receiver_state *rpt) {
@@ -1189,7 +1210,7 @@ STREAM_CAPABILITIES convert_stream_version_to_capabilities(int32_t version) {
1210 if(caps & STREAM_CAP_V2)
1211 caps &= ~(STREAM_CAP_V1);
1212
1192 - return caps & STREAM_OUR_CAPABILITIES;
1213 + return caps & stream_our_capabilities();
1214 }
1215
1216 int32_t stream_capabilities_to_vn(uint32_t caps) {
streaming/rrdpush.h
+4 -6
@@ -42,6 +42,7 @@ typedef enum {
42 STREAM_CAP_REPLICATION = (1 << 12), // replication supported
43 STREAM_CAP_BINARY = (1 << 13), // streaming supports binary data
44 STREAM_CAP_INTERPOLATED = (1 << 14), // streaming supports interpolated streaming of values
45 + STREAM_CAP_IEEE754 = (1 << 15), // streaming supports binary/hex transfer of double values
46
47 STREAM_CAP_INVALID = (1 << 30), // used as an invalid value for capabilities when this is set
48 // this must be signed int, so don't use the last bit
@@ -54,13 +55,9 @@ typedef enum {
55 #define STREAM_HAS_COMPRESSION 0
56 #endif // ENABLE_COMPRESSION
57
57 -#define STREAM_OUR_CAPABILITIES ( \
58 - STREAM_CAP_V1 | STREAM_CAP_V2 | STREAM_CAP_VN | STREAM_CAP_VCAPS | \
59 - STREAM_CAP_HLABELS | STREAM_CAP_CLAIM | STREAM_CAP_CLABELS | \
60 - STREAM_HAS_COMPRESSION | STREAM_CAP_FUNCTIONS | STREAM_CAP_REPLICATION | STREAM_CAP_BINARY | \
61 - STREAM_CAP_INTERPOLATED)
58 +STREAM_CAPABILITIES stream_our_capabilities();
59
63 -#define stream_has_capability(rpt, capability) ((rpt) && ((rpt)->capabilities & (capability)))
60 +#define stream_has_capability(rpt, capability) ((rpt) && ((rpt)->capabilities & (capability)) == (capability))
61
62 // ----------------------------------------------------------------------------
63 // stream handshake
@@ -307,6 +304,7 @@ bool rrdpush_receiver_needs_dbengine();
304 int configured_as_parent();
305
306 typedef struct rrdset_stream_buffer {
307 + STREAM_CAPABILITIES capabilities;
308 bool v2;
309 bool begin_v2_added;
310 time_t wall_clock_time;
streaming/sender.c
+2 -2
@@ -529,7 +529,7 @@ static bool rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_p
529 #endif
530
531 // reset our capabilities to default
532 - s->capabilities = STREAM_OUR_CAPABILITIES;
532 + s->capabilities = stream_our_capabilities();
533
534 #ifdef ENABLE_COMPRESSION
535 // If we don't want compression, remove it from our capabilities
@@ -901,7 +901,7 @@ void stream_execute_function_callback(BUFFER *func_wb, int code, void *data) {
901 pluginsd_function_result_begin_to_buffer(wb
902 , string2str(tmp->transaction)
903 , code
904 - , functions_content_type_to_format(func_wb->contenttype)
904 + , functions_content_type_to_format(func_wb->content_type)
905 , func_wb->expires);
906
907 buffer_fast_strcat(wb, buffer_tostring(func_wb), buffer_strlen(func_wb));
web/api/badges/web_buffer_svg.c
+2 -2
@@ -767,7 +767,7 @@ void buffer_svg(BUFFER *wb, const char *label,
767 label_color_parsed = parse_color_argument(label_color, "555");
768 value_color_parsed = parse_color_argument(value_color_buffer, "555");
769
770 - wb->contenttype = CT_IMAGE_SVG_XML;
770 + wb->content_type = CT_IMAGE_SVG_XML;
771
772 total_width = total_width * scale / 100.0;
773 height = height * scale / 100.0;
@@ -923,7 +923,7 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
923 else if(!strcmp(name, "points")) points_str = value;
924 else if(!strcmp(name, "group_options")) group_options = value;
925 else if(!strcmp(name, "group")) {
926 - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
926 + group = time_grouping_parse(value, RRDR_GROUPING_AVERAGE);
927 }
928 else if(!strcmp(name, "options")) {
929 options |= web_client_api_request_v1_data_options(value);
web/api/exporters/allmetrics.c
+5 -5
@@ -90,17 +90,17 @@ inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client
90
91 switch(format) {
92 case ALLMETRICS_JSON:
93 - w->response.data->contenttype = CT_APPLICATION_JSON;
93 + w->response.data->content_type = CT_APPLICATION_JSON;
94 rrd_stats_api_v1_charts_allmetrics_json(host, filter, w->response.data);
95 return HTTP_RESP_OK;
96
97 case ALLMETRICS_SHELL:
98 - w->response.data->contenttype = CT_TEXT_PLAIN;
98 + w->response.data->content_type = CT_TEXT_PLAIN;
99 rrd_stats_api_v1_charts_allmetrics_shell(host, filter, w->response.data);
100 return HTTP_RESP_OK;
101
102 case ALLMETRICS_PROMETHEUS:
103 - w->response.data->contenttype = CT_PROMETHEUS;
103 + w->response.data->content_type = CT_PROMETHEUS;
104 rrd_stats_api_v1_charts_allmetrics_prometheus_single_host(
105 host
106 , filter
@@ -113,7 +113,7 @@ inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client
113 return HTTP_RESP_OK;
114
115 case ALLMETRICS_PROMETHEUS_ALL_HOSTS:
116 - w->response.data->contenttype = CT_PROMETHEUS;
116 + w->response.data->content_type = CT_PROMETHEUS;
117 rrd_stats_api_v1_charts_allmetrics_prometheus_all_hosts(
118 host
119 , filter
@@ -126,7 +126,7 @@ inline int web_client_api_request_v1_allmetrics(RRDHOST *host, struct web_client
126 return HTTP_RESP_OK;
127
128 default:
129 - w->response.data->contenttype = CT_TEXT_PLAIN;
129 + w->response.data->content_type = CT_TEXT_PLAIN;
130 buffer_strcat(w->response.data, "Which format? '" ALLMETRICS_FORMAT_SHELL "', '" ALLMETRICS_FORMAT_PROMETHEUS "', '" ALLMETRICS_FORMAT_PROMETHEUS_ALL_HOSTS "' and '" ALLMETRICS_FORMAT_JSON "' are currently supported.");
131 return HTTP_RESP_BAD_REQUEST;
132 }
web/api/formatters/charts2json.c
-52
@@ -137,55 +137,3 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
137
138 buffer_sprintf(wb, "\n\t]\n}\n");
139 }
140 -
141 -// generate collectors list for the api/v1/info call
142 -
143 -struct collector {
144 - const char *plugin;
145 - const char *module;
146 -};
147 -
148 -struct array_printer {
149 - int c;
150 - BUFFER *wb;
151 -};
152 -
153 -static int print_collector_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
154 - struct array_printer *ap = (struct array_printer *)data;
155 - BUFFER *wb = ap->wb;
156 - struct collector *col=(struct collector *) entry;
157 - if(ap->c) buffer_strcat(wb, ",");
158 - buffer_strcat(wb, "\n\t\t{\n\t\t\t\"plugin\": \"");
159 - buffer_strcat(wb, col->plugin);
160 - buffer_strcat(wb, "\",\n\t\t\t\"module\": \"");
161 - buffer_strcat(wb, col->module);
162 - buffer_strcat(wb, "\"\n\t\t}");
163 - (ap->c)++;
164 - return 0;
165 -}
166 -
167 -void chartcollectors2json(RRDHOST *host, BUFFER *wb) {
168 - DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED);
169 - RRDSET *st;
170 - char name[500];
171 -
172 - time_t now = now_realtime_sec();
173 - rrdset_foreach_read(st, host) {
174 - if (rrdset_is_available_for_viewers(st)) {
175 - struct collector col = {
176 - .plugin = rrdset_plugin_name(st),
177 - .module = rrdset_module_name(st)
178 - };
179 - sprintf(name, "%s:%s", col.plugin, col.module);
180 - dictionary_set(dict, name, &col, sizeof(struct collector));
181 - st->last_accessed_time_s = now;
182 - }
183 - }
184 - rrdset_foreach_done(st);
185 - struct array_printer ap = {
186 - .c = 0,
187 - .wb = wb
188 - };
189 - dictionary_walkthrough_read(dict, print_collector_callback, &ap);
190 - dictionary_destroy(dict);
191 -}
web/api/formatters/charts2json.h
-1
@@ -6,7 +6,6 @@
6 #include "rrd2json.h"
7
8 void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived);
9 -void chartcollectors2json(RRDHOST *host, BUFFER *wb);
9 const char* get_release_channel();
10
11 #endif //NETDATA_API_FORMATTER_CHARTS2JSON_H
web/api/formatters/csv/csv.c
+8 -11
@@ -11,9 +11,8 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
11
12 // print the csv header
13 for(c = 0, i = 0; c < used ; c++) {
14 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
15 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
16 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
14 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
15 + continue;
16
17 if(!i) {
18 buffer_strcat(wb, startline);
@@ -32,9 +31,8 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
31 if(format == DATASOURCE_CSV_MARKDOWN) {
32 // print the --- line after header
33 for(c = 0, i = 0; c < used ;c++) {
35 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
36 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
37 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
34 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
35 + continue;
36
37 if(!i) {
38 buffer_strcat(wb, startline);
@@ -76,7 +74,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
74
75 if((options & RRDR_OPTION_SECONDS) || (options & RRDR_OPTION_MILLISECONDS)) {
76 // print the timestamp of the line
79 - buffer_rrd_value(wb, (NETDATA_DOUBLE)now);
77 + buffer_print_netdata_double(wb, (NETDATA_DOUBLE) now);
78 // in ms
79 if(options & RRDR_OPTION_MILLISECONDS) buffer_strcat(wb, "000");
80 }
@@ -107,9 +105,8 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
105
106 // for each dimension
107 for(c = 0; c < used ;c++) {
110 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
111 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
112 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
108 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
109 + continue;
110
111 buffer_strcat(wb, separator);
112
@@ -137,7 +134,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
134 if(n > r->max) r->max = n;
135 }
136
140 - buffer_rrd_value(wb, n);
137 + buffer_print_netdata_double(wb, n);
138 }
139 }
140
web/api/formatters/json/json.c
+12 -14
@@ -42,7 +42,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
42 strcpy(post_value, "}");
43 strcpy(post_line, "]}");
44 snprintfz(data_begin, 100, "\n ],\n %srows%s:\n [\n", kq, kq);
45 - strcpy(finish, "\n]\n}");
45 + strcpy(finish, "\n ]\n }");
46
47 snprintfz(overflow_annotation, 200, ",{%sv%s:%sRESET OR OVERFLOW%s},{%sv%s:%sThe counters have been wrapped.%s}", kq, kq, sq, sq, kq, kq, sq, sq);
48 snprintfz(normal_annotation, 200, ",{%sv%s:null},{%sv%s:null}", kq, kq, kq, kq);
@@ -69,9 +69,9 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
69 dates_with_new = 0;
70 }
71 if( options & RRDR_OPTION_OBJECTSROWS )
72 - strcpy(pre_date, " { ");
72 + strcpy(pre_date, " {");
73 else
74 - strcpy(pre_date, " [ ");
74 + strcpy(pre_date, " [");
75 strcpy(pre_label, ",\"");
76 strcpy(post_label, "\"");
77 strcpy(pre_value, ",");
@@ -79,10 +79,10 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
79 strcpy(post_line, "}");
80 else
81 strcpy(post_line, "]");
82 - snprintfz(data_begin, 100, "],\n %sdata%s:\n [\n", kq, kq);
83 - strcpy(finish, "\n]\n}");
82 + snprintfz(data_begin, 100, "],\n %sdata%s:[\n", kq, kq);
83 + strcpy(finish, "\n ]\n }");
84
85 - buffer_sprintf(wb, "{\n %slabels%s: [", kq, kq);
85 + buffer_sprintf(wb, "{\n %slabels%s:[", kq, kq);
86 buffer_sprintf(wb, "%stime%s", sq, sq);
87
88 if( options & RRDR_OPTION_OBJECTSROWS )
@@ -110,9 +110,8 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
110
111 // print the header lines
112 for(c = 0, i = 0; c < used ; c++) {
113 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
114 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
115 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
113 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
114 + continue;
115
116 buffer_fast_strcat(wb, pre_label, pre_label_len);
117 buffer_strcat(wb, string2str(qt->query.array[c].dimension.name));
@@ -203,7 +202,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
202 if(unlikely( options & RRDR_OPTION_OBJECTSROWS ))
203 buffer_fast_strcat(wb, object_rows_time, object_rows_time_len);
204
206 - buffer_rrd_value(wb, (NETDATA_DOUBLE)r->t[i]);
205 + buffer_print_netdata_double(wb, (NETDATA_DOUBLE) r->t[i]);
206
207 // in ms
208 if(unlikely(options & RRDR_OPTION_MILLISECONDS))
@@ -236,9 +235,8 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
235
236 // for each dimension
237 for(c = 0; c < used ;c++) {
239 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
240 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
241 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
238 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
239 + continue;
240
241 NETDATA_DOUBLE n;
242 if(unlikely(options & RRDR_OPTION_INTERNAL_AR))
@@ -273,7 +271,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable) {
271 if(n > r->max) r->max = n;
272 }
273
276 - buffer_rrd_value(wb, n);
274 + buffer_print_netdata_double(wb, n);
275 }
276
277 buffer_fast_strcat(wb, post_value, post_value_len);
web/api/formatters/json_wrapper.c
+309 -359
@@ -2,433 +2,388 @@
2
3 #include "json_wrapper.h"
4
5 -struct value_output {
6 - int c;
7 - BUFFER *wb;
8 -};
9 -
10 -static int value_list_output_callback(const DICTIONARY_ITEM *item __maybe_unused, void *entry, void *data) {
11 - struct value_output *ap = (struct value_output *)data;
12 - BUFFER *wb = ap->wb;
13 - char *output = (char *) entry;
14 - if(ap->c) buffer_strcat(wb, ",");
15 - buffer_strcat(wb, output);
16 - (ap->c)++;
17 - return 0;
18 -}
19 -
20 -static int fill_formatted_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
21 - (void)ls;
22 - DICTIONARY *dict = (DICTIONARY *)data;
23 - char n[RRD_ID_LENGTH_MAX * 2 + 2];
24 - char output[RRD_ID_LENGTH_MAX * 2 + 8];
25 - char v[RRD_ID_LENGTH_MAX * 2 + 1];
26 -
27 - sanitize_json_string(v, (char *)value, RRD_ID_LENGTH_MAX * 2);
28 - int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\", \"%s\"]", name, v);
29 - snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, v);
30 - dictionary_set(dict, n, output, len + 1);
31 -
32 - return 1;
33 -}
34 -
35 -void rrdr_show_plan(RRDR *r, BUFFER *wb, const char *kq, const char *sq __maybe_unused) {
5 +void jsonwrap_query_plan(RRDR *r, BUFFER *wb) {
6 QUERY_TARGET *qt = r->internal.qt;
7
38 - buffer_sprintf(wb, "\n\t%squery_plan%s: {", kq, kq);
39 -
8 + buffer_json_member_add_object(wb, "query_plan");
9 for(size_t m = 0; m < qt->query.used; m++) {
10 QUERY_METRIC *qm = &qt->query.array[m];
11
43 - if(m)
44 - buffer_strcat(wb, ",");
45 -
46 - buffer_sprintf(wb, "\n\t\t%s%s%s: {", kq, string2str(qm->dimension.id), kq);
47 -
48 - buffer_sprintf(wb, "\n\t\t\t%splans%s: [", kq, kq);
49 - for(size_t p = 0; p < qm->plan.used ;p++) {
50 - QUERY_PLAN_ENTRY *qp = &qm->plan.array[p];
51 - if(p)
52 - buffer_strcat(wb, ",");
53 -
54 - buffer_strcat(wb, "\n\t\t\t\t{");
55 - buffer_sprintf(wb, "\n\t\t\t\t\t%stier%s: %zu,", kq, kq, qp->tier);
56 - buffer_sprintf(wb, "\n\t\t\t\t\t%safter%s: %ld,", kq, kq, qp->after);
57 - buffer_sprintf(wb, "\n\t\t\t\t\t%sbefore%s: %ld", kq, kq, qp->before);
58 - buffer_strcat(wb, "\n\t\t\t\t}");
59 - }
60 - buffer_strcat(wb, "\n\t\t\t],");
61 -
62 - buffer_sprintf(wb, "\n\t\t\t%stiers%s: [", kq, kq);
63 - for(size_t tier = 0; tier < storage_tiers ;tier++) {
64 - if(tier)
65 - buffer_strcat(wb, ",");
66 -
67 - buffer_strcat(wb, "\n\t\t\t\t{");
68 - buffer_sprintf(wb, "\n\t\t\t\t\t%stier%s: %zu,", kq, kq, tier);
69 - buffer_sprintf(wb, "\n\t\t\t\t\t%sdb_first_time%s: %ld,", kq, kq, qm->tiers[tier].db_first_time_s);
70 - buffer_sprintf(wb, "\n\t\t\t\t\t%sdb_last_time%s: %ld,", kq, kq, qm->tiers[tier].db_last_time_s);
71 - buffer_sprintf(wb, "\n\t\t\t\t\t%sweight%s: %ld", kq, kq, qm->tiers[tier].weight);
72 - buffer_strcat(wb, "\n\t\t\t\t}");
12 + buffer_json_member_add_object(wb, string2str(qm->dimension.id));
13 + {
14 + buffer_json_member_add_array(wb, "plans");
15 + for (size_t p = 0; p < qm->plan.used; p++) {
16 + QUERY_PLAN_ENTRY *qp = &qm->plan.array[p];
17 +
18 + buffer_json_add_array_item_object(wb);
19 + buffer_json_member_add_uint64(wb, "tier", qp->tier);
20 + buffer_json_member_add_time_t(wb, "after", qp->after);
21 + buffer_json_member_add_time_t(wb, "before", qp->before);
22 + buffer_json_object_close(wb);
23 + }
24 + buffer_json_array_close(wb);
25 +
26 + buffer_json_member_add_array(wb, "tiers");
27 + for (size_t tier = 0; tier < storage_tiers; tier++) {
28 + buffer_json_add_array_item_object(wb);
29 + buffer_json_member_add_uint64(wb, "tier", tier);
30 + buffer_json_member_add_time_t(wb, "db_first_time", qm->tiers[tier].db_first_time_s);
31 + buffer_json_member_add_time_t(wb, "db_last_time", qm->tiers[tier].db_last_time_s);
32 + buffer_json_member_add_int64(wb, "weight", qm->tiers[tier].weight);
33 + buffer_json_object_close(wb);
34 + }
35 + buffer_json_array_close(wb);
36 }
74 - buffer_strcat(wb, "\n\t\t\t]");
75 -
76 - buffer_strcat(wb, "\n\t\t}");
37 + buffer_json_object_close(wb);
38 }
78 -
79 - buffer_strcat(wb, "\n\t},");
39 + buffer_json_object_close(wb);
40 }
41
82 -void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
83 - RRDR_GROUPING group_method)
84 -{
42 +static inline long jsonwrap_dimension_names(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
43 QUERY_TARGET *qt = r->internal.qt;
86 -
87 - long rows = rrdr_rows(r);
88 - long c, i;
44 const long query_used = qt->query.used;
45 + long c, i;
46
91 - //info("JSONWRAPPER(): %s: BEGIN", r->st->id);
92 - char kq[2] = "", // key quote
93 - sq[2] = ""; // string quote
94 -
95 - if( options & RRDR_OPTION_GOOGLE_JSON ) {
96 - kq[0] = '\0';
97 - sq[0] = '\'';
98 - }
99 - else {
100 - kq[0] = '"';
101 - sq[0] = '"';
102 - }
103 -
104 - buffer_sprintf(wb, "{\n"
105 - " %sapi%s: 1,\n"
106 - " %sid%s: %s%s%s,\n"
107 - " %sname%s: %s%s%s,\n"
108 - " %sview_update_every%s: %lld,\n"
109 - " %supdate_every%s: %lld,\n"
110 - " %sfirst_entry%s: %lld,\n"
111 - " %slast_entry%s: %lld,\n"
112 - " %sbefore%s: %lld,\n"
113 - " %safter%s: %lld,\n"
114 - " %sgroup%s: %s%s%s,\n"
115 - " %soptions%s: %s"
116 - , kq, kq
117 - , kq, kq, sq, qt->id, sq
118 - , kq, kq, sq, qt->id, sq
119 - , kq, kq, (long long)r->update_every
120 - , kq, kq, (long long)qt->db.minimum_latest_update_every_s
121 - , kq, kq, (long long)qt->db.first_time_s
122 - , kq, kq, (long long)qt->db.last_time_s
123 - , kq, kq, (long long)r->before
124 - , kq, kq, (long long)r->after
125 - , kq, kq, sq, web_client_api_request_v1_data_group_to_string(group_method), sq
126 - , kq, kq, sq);
127 -
128 - web_client_api_request_v1_data_options_to_buffer(wb, r->internal.query_options);
129 -
130 - buffer_sprintf(wb, "%s,\n %sdimension_names%s: [", sq, kq, kq);
131 -
47 + buffer_json_member_add_array(wb, key);
48 for(c = 0, i = 0; c < query_used ; c++) {
133 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
134 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
135 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
136 -
137 - if(i) buffer_strcat(wb, ", ");
138 - buffer_strcat(wb, sq);
139 - buffer_strcat(wb, string2str(qt->query.array[c].dimension.name));
140 - buffer_strcat(wb, sq);
49 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
50 + continue;
51 +
52 + buffer_json_add_array_item_string(wb, string2str(qt->query.array[c].dimension.name));
53 i++;
54 }
143 - if(!i) {
144 -#ifdef NETDATA_INTERNAL_CHECKS
145 - error("QUERY: '%s', RRDR is empty, %zu dimensions, options is 0x%08x", qt->id, r->d, options);
146 -#endif
147 - rows = 0;
148 - buffer_strcat(wb, sq);
149 - buffer_strcat(wb, "no data");
150 - buffer_strcat(wb, sq);
151 - }
55 + buffer_json_array_close(wb);
56
153 - buffer_sprintf(wb, "],\n"
154 - " %sdimension_ids%s: ["
155 - , kq, kq);
57 + return i;
58 +}
59 +
60 +static inline long jsonwrap_dimension_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
61 + QUERY_TARGET *qt = r->internal.qt;
62 + const long query_used = qt->query.used;
63 + long c, i;
64
65 + buffer_json_member_add_array(wb, key);
66 for(c = 0, i = 0; c < query_used ; c++) {
158 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
159 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
160 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
161 -
162 - if(i) buffer_strcat(wb, ", ");
163 - buffer_strcat(wb, sq);
164 - buffer_strcat(wb, string2str(qt->query.array[c].dimension.id));
165 - buffer_strcat(wb, sq);
67 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
68 + continue;
69 +
70 + buffer_json_add_array_item_string(wb, string2str(qt->query.array[c].dimension.id));
71 i++;
72 }
168 - if(!i) {
169 - rows = 0;
170 - buffer_strcat(wb, sq);
171 - buffer_strcat(wb, "no data");
172 - buffer_strcat(wb, sq);
173 - }
174 - buffer_strcat(wb, "],\n");
73 + buffer_json_array_close(wb);
74
176 - if (r->internal.query_options & RRDR_OPTION_ALL_DIMENSIONS) {
177 - buffer_sprintf(wb, " %sfull_dimension_list%s: [", kq, kq);
75 + return i;
76 +}
77
179 - char name[RRD_ID_LENGTH_MAX * 2 + 2];
180 - char output[RRD_ID_LENGTH_MAX * 2 + 8];
78 +static inline long jsonwrap_chart_ids(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
79 + QUERY_TARGET *qt = r->internal.qt;
80 + const long query_used = qt->query.used;
81 + long c, i;
82
182 - struct value_output co = {.c = 0, .wb = wb};
83 + buffer_json_member_add_array(wb, key);
84 + for (c = 0, i = 0; c < query_used; c++) {
85 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
86 + continue;
87
184 - DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
185 - for (c = 0; c < (long)qt->metrics.used ;c++) {
186 - snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
187 - rrdmetric_acquired_id(qt->metrics.array[c]),
188 - rrdmetric_acquired_name(qt->metrics.array[c]));
88 + QUERY_METRIC *qm = &qt->query.array[c];
89 + buffer_json_add_array_item_string(wb, string2str(qm->chart.id));
90 + i++;
91 + }
92 + buffer_json_array_close(wb);
93
190 - int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]",
191 - rrdmetric_acquired_id(qt->metrics.array[c]),
192 - rrdmetric_acquired_name(qt->metrics.array[c]));
94 + return i;
95 +}
96
194 - dictionary_set(dict, name, output, len + 1);
195 - }
196 - dictionary_walkthrough_read(dict, value_list_output_callback, &co);
197 - dictionary_destroy(dict);
97 +struct rrdlabels_formatting_v2 {
98 + BUFFER *wb;
99 + DICTIONARY *dict;
100 +};
101
199 - co.c = 0;
200 - buffer_sprintf(wb, "],\n %sfull_chart_list%s: [", kq, kq);
201 - dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
202 - for (c = 0; c < (long)qt->instances.used ; c++) {
203 - RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
102 +static int rrdlabels_formatting_v2(const char *name, const char *value, RRDLABEL_SRC ls __maybe_unused, void *data) {
103 + struct rrdlabels_formatting_v2 *t = data;
104 + BUFFER *wb = t->wb;
105 + DICTIONARY *dict = t->dict;
106
205 - snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
206 - rrdinstance_acquired_id(ria),
207 - rrdinstance_acquired_name(ria));
107 + char n[RRD_ID_LENGTH_MAX * 2 + 2];
108 + snprintfz(n, RRD_ID_LENGTH_MAX * 2, "%s:%s", name, value);
109 +
110 + bool existing = 0;
111 + bool *set = dictionary_set(dict, n, &existing, sizeof(bool));
112 + if(!*set) {
113 + *set = true;
114 + buffer_json_add_array_item_array(wb);
115 + buffer_json_add_array_item_string(wb, name);
116 + buffer_json_add_array_item_string(wb, value);
117 + buffer_json_array_close(wb);
118 + }
119 +
120 + return 1;
121 +}
122
209 - int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]",
210 - rrdinstance_acquired_id(ria),
211 - rrdinstance_acquired_name(ria));
123 +static inline void jsonwrap_full_dimension_list(BUFFER *wb, RRDR *r) {
124 + QUERY_TARGET *qt = r->internal.qt;
125
213 - dictionary_set(dict, name, output, len + 1);
126 + char name[RRD_ID_LENGTH_MAX * 2 + 2];
127 +
128 + buffer_json_member_add_array(wb, "full_dimension_list");
129 + DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
130 + for (long c = 0; c < (long)qt->metrics.used ;c++) {
131 + RRDMETRIC_ACQUIRED *rma = qt->metrics.array[c];
132 +
133 + snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
134 + rrdmetric_acquired_id(rma),
135 + rrdmetric_acquired_name(rma));
136 +
137 + bool existing = 0;
138 + bool *set = dictionary_set(dict, name, &existing, sizeof(bool));
139 + if(!*set) {
140 + *set = true;
141 + buffer_json_add_array_item_array(wb);
142 + buffer_json_add_array_item_string(wb, rrdmetric_acquired_id(rma));
143 + buffer_json_add_array_item_string(wb, rrdmetric_acquired_name(rma));
144 + buffer_json_array_close(wb);
145 }
215 - dictionary_walkthrough_read(dict, value_list_output_callback, &co);
216 - dictionary_destroy(dict);
217 -
218 - co.c = 0;
219 - buffer_sprintf(wb, "],\n %sfull_chart_labels%s: [", kq, kq);
220 - dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
221 - for (c = 0; c < (long)qt->instances.used ; c++) {
222 - RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
223 - rrdlabels_walkthrough_read(rrdinstance_acquired_labels(ria), fill_formatted_callback, dict);
146 + }
147 + dictionary_destroy(dict);
148 + buffer_json_array_close(wb);
149 +
150 + buffer_json_member_add_array(wb, "full_chart_list");
151 + dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
152 + for (long c = 0; c < (long)qt->instances.used ; c++) {
153 + RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
154 +
155 + snprintfz(name, RRD_ID_LENGTH_MAX * 2 + 1, "%s:%s",
156 + rrdinstance_acquired_id(ria),
157 + rrdinstance_acquired_name(ria));
158 +
159 + bool existing = 0;
160 + bool *set = dictionary_set(dict, name, &existing, sizeof(bool));
161 + if(!*set) {
162 + *set = true;
163 + buffer_json_add_array_item_array(wb);
164 + buffer_json_add_array_item_string(wb, rrdinstance_acquired_id(ria));
165 + buffer_json_add_array_item_string(wb, rrdinstance_acquired_name(ria));
166 + buffer_json_array_close(wb);
167 }
225 - dictionary_walkthrough_read(dict, value_list_output_callback, &co);
226 - dictionary_destroy(dict);
227 - buffer_strcat(wb, "],\n");
168 }
169 + dictionary_destroy(dict);
170 + buffer_json_array_close(wb);
171 +
172 + buffer_json_member_add_array(wb, "full_chart_labels");
173 + struct rrdlabels_formatting_v2 t = {
174 + .wb = wb,
175 + .dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE),
176 + };
177 + for (long c = 0; c < (long)qt->instances.used ; c++) {
178 + RRDINSTANCE_ACQUIRED *ria = qt->instances.array[c];
179 + rrdlabels_walkthrough_read(rrdinstance_acquired_labels(ria), rrdlabels_formatting_v2, &t);
180 + }
181 + dictionary_destroy(t.dict);
182 + buffer_json_array_close(wb);
183 +}
184
230 - // functions
231 - {
232 - DICTIONARY *funcs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
233 - RRDINSTANCE_ACQUIRED *ria = NULL;
234 - for (c = 0; c < query_used ; c++) {
235 - QUERY_METRIC *qm = &qt->query.array[c];
236 - if(qm->link.ria == ria)
237 - continue;
185 +static inline void jsonwrap_functions(BUFFER *wb, const char *key, RRDR *r) {
186 + QUERY_TARGET *qt = r->internal.qt;
187 + const long query_used = qt->query.used;
188
239 - ria = qm->link.ria;
240 - chart_functions_to_dict(rrdinstance_acquired_functions(ria), funcs);
241 - }
189 + DICTIONARY *funcs = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
190 + RRDINSTANCE_ACQUIRED *ria = NULL;
191 + for (long c = 0; c < query_used ; c++) {
192 + QUERY_METRIC *qm = &qt->query.array[c];
193 + if(qm->link.ria == ria)
194 + continue;
195
243 - buffer_sprintf(wb, " %sfunctions%s: [", kq, kq);
244 - void *t; (void)t;
245 - dfe_start_read(funcs, t) {
246 - const char *comma = "";
247 - if(t_dfe.counter) comma = ", ";
248 - buffer_sprintf(wb, "%s%s%s%s", comma, sq, t_dfe.name, sq);
249 - }
250 - dfe_done(t);
251 - dictionary_destroy(funcs);
252 - buffer_strcat(wb, "],\n");
196 + ria = qm->link.ria;
197 + chart_functions_to_dict(rrdinstance_acquired_functions(ria), funcs);
198 }
199
255 - // context query
256 - if (!qt->request.st) {
257 - buffer_sprintf(
258 - wb,
259 - " %schart_ids%s: [",
260 - kq, kq);
200 + buffer_json_member_add_array(wb, key);
201 + void *t; (void)t;
202 + dfe_start_read(funcs, t)
203 + buffer_json_add_array_item_string(wb, t_dfe.name);
204 + dfe_done(t);
205 + dictionary_destroy(funcs);
206 + buffer_json_array_close(wb);
207 +}
208
262 - for (c = 0, i = 0; c < query_used; c++) {
263 - QUERY_METRIC *qm = &qt->query.array[c];
209 +static inline long jsonwrap_chart_labels_filter(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
210 + QUERY_TARGET *qt = r->internal.qt;
211 + const long query_used = qt->query.used;
212 + long c, i = 0;
213 +
214 + buffer_json_member_add_object(wb, key);
215
265 - if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
266 - if (unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
267 - if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
216 + SIMPLE_PATTERN *pattern = qt->instances.chart_label_key_pattern;
217 + char *label_key = NULL;
218 + while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
219 + buffer_json_member_add_array(wb, label_key);
220 +
221 + for (c = 0, i = 0; c < query_used; c++) {
222 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
223 continue;
224
270 - if (i)
271 - buffer_strcat(wb, ", ");
272 - buffer_strcat(wb, sq);
273 - buffer_strcat(wb, string2str(qm->chart.id));
274 - buffer_strcat(wb, sq);
225 + QUERY_METRIC *qm = &qt->query.array[c];
226 + rrdlabels_value_to_buffer_array_item_or_null(rrdinstance_acquired_labels(qm->link.ria), wb, label_key);
227 i++;
228 }
277 - if (!i) {
278 - rows = 0;
279 - buffer_strcat(wb, sq);
280 - buffer_strcat(wb, "no data");
281 - buffer_strcat(wb, sq);
282 - }
283 - buffer_strcat(wb, "],\n");
284 - if (qt->instances.chart_label_key_pattern) {
285 - buffer_sprintf(wb, " %schart_labels%s: { ", kq, kq);
286 -
287 - SIMPLE_PATTERN *pattern = qt->instances.chart_label_key_pattern;
288 - char *label_key = NULL;
289 - int keys = 0;
290 - while (pattern && (label_key = simple_pattern_iterate(&pattern))) {
291 - if (keys)
292 - buffer_strcat(wb, ", ");
293 - buffer_sprintf(wb, "%s%s%s : [", kq, label_key, kq);
294 - keys++;
295 -
296 - for (c = 0, i = 0; c < query_used; c++) {
297 - QUERY_METRIC *qm = &qt->query.array[c];
298 -
299 - if (unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
300 - if (unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
301 - if (unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO)))
302 - continue;
303 -
304 - if (i)
305 - buffer_strcat(wb, ", ");
306 - rrdlabels_get_value_to_buffer_or_null(rrdinstance_acquired_labels(qm->link.ria), wb, label_key, sq, "null");
307 - i++;
308 - }
309 - if (!i) {
310 - rows = 0;
311 - buffer_strcat(wb, sq);
312 - buffer_strcat(wb, "no data");
313 - buffer_strcat(wb, sq);
314 - }
315 - buffer_strcat(wb, "]");
316 - }
317 - buffer_strcat(wb, "},\n");
318 - }
229 + buffer_json_array_close(wb);
230 }
231
321 - buffer_sprintf(wb, " %slatest_values%s: ["
322 - , kq, kq);
232 + buffer_json_object_close(wb);
233 +
234 + return i;
235 +}
236 +
237 +static inline long jsonwrap_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
238 + QUERY_TARGET *qt = r->internal.qt;
239 + const long query_used = qt->query.used;
240 + long c, i;
241 +
242 + buffer_json_member_add_array(wb, key);
243
244 for(c = 0, i = 0; c < query_used ;c++) {
245 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
246 + continue;
247 +
248 QUERY_METRIC *qm = &qt->query.array[c];
249 + buffer_json_add_array_item_double(wb, rrdmetric_acquired_last_stored_value(qm->link.rma));
250 + i++;
251 + }
252
327 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
328 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
253 + buffer_json_array_close(wb);
254
330 - if(i) buffer_strcat(wb, ", ");
331 - i++;
255 + return i;
256 +}
257
333 - NETDATA_DOUBLE value = rrdmetric_acquired_last_stored_value(qm->link.rma);
334 - if (NAN == value)
335 - buffer_strcat(wb, "null");
336 - else
337 - buffer_rrd_value(wb, value);
338 - }
339 - if(!i) {
340 - rows = 0;
341 - buffer_strcat(wb, "null");
342 - }
258 +static inline long jsonwrap_view_latest_values(BUFFER *wb, const char *key, RRDR *r, RRDR_OPTIONS options) {
259 + QUERY_TARGET *qt = r->internal.qt;
260 + const long query_used = qt->query.used;
261 + long c, i;
262
344 - buffer_sprintf(wb, "],\n"
345 - " %sview_latest_values%s: ["
346 - , kq, kq);
263 + buffer_json_member_add_array(wb, key);
264
348 - i = 0;
349 - if(rows) {
350 - NETDATA_DOUBLE total = 1;
265 + NETDATA_DOUBLE total = 1;
266
352 - if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
353 - total = 0;
354 - for(c = 0; c < query_used ;c++) {
355 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
267 + if(unlikely(options & RRDR_OPTION_PERCENTAGE)) {
268 + total = 0;
269 + for(c = 0; c < query_used ;c++) {
270 + if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
271
357 - NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
358 - NETDATA_DOUBLE n = cn[c];
272 + NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
273 + NETDATA_DOUBLE n = cn[c];
274
360 - if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
361 - n = -n;
275 + if(likely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
276 + n = -n;
277
363 - total += n;
364 - }
365 - // prevent a division by zero
366 - if(total == 0) total = 1;
278 + total += n;
279 }
280 + // prevent a division by zero
281 + if(total == 0) total = 1;
282 + }
283
369 - for(c = 0, i = 0; c < query_used ;c++) {
370 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
371 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
372 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
284 + for(c = 0, i = 0; c < query_used ;c++) {
285 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
286 + continue;
287
374 - if(i) buffer_strcat(wb, ", ");
375 - i++;
288 + i++;
289
377 - NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
378 - RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
379 - NETDATA_DOUBLE n = cn[c];
290 + NETDATA_DOUBLE *cn = &r->v[ (rrdr_rows(r) - 1) * r->d ];
291 + RRDR_VALUE_FLAGS *co = &r->o[ (rrdr_rows(r) - 1) * r->d ];
292 + NETDATA_DOUBLE n = cn[c];
293
381 - if(co[c] & RRDR_VALUE_EMPTY) {
382 - if(options & RRDR_OPTION_NULL2ZERO)
383 - buffer_strcat(wb, "0");
384 - else
385 - buffer_strcat(wb, "null");
386 - }
387 - else {
388 - if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
389 - n = -n;
294 + if(co[c] & RRDR_VALUE_EMPTY) {
295 + if(options & RRDR_OPTION_NULL2ZERO)
296 + buffer_json_add_array_item_double(wb, 0.0);
297 + else
298 + buffer_json_add_array_item_double(wb, NAN);
299 + }
300 + else {
301 + if(unlikely((options & RRDR_OPTION_ABSOLUTE) && n < 0))
302 + n = -n;
303
391 - if(unlikely(options & RRDR_OPTION_PERCENTAGE))
392 - n = n * 100 / total;
304 + if(unlikely(options & RRDR_OPTION_PERCENTAGE))
305 + n = n * 100 / total;
306
394 - buffer_rrd_value(wb, n);
395 - }
307 + buffer_json_add_array_item_double(wb, n);
308 }
309 }
398 - if(!i) {
399 - rows = 0;
400 - buffer_strcat(wb, "null");
310 +
311 + buffer_json_array_close(wb);
312 +
313 + return i;
314 +}
315 +
316 +void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
317 + RRDR_TIME_GROUPING group_method)
318 +{
319 + QUERY_TARGET *qt = r->internal.qt;
320 +
321 + long rows = rrdr_rows(r);
322 +
323 + char kq[2] = "", // key quote
324 + sq[2] = ""; // string quote
325 +
326 + if( options & RRDR_OPTION_GOOGLE_JSON ) {
327 + kq[0] = '\0';
328 + sq[0] = '\'';
329 + }
330 + else {
331 + kq[0] = '"';
332 + sq[0] = '"';
333 }
334
403 - buffer_sprintf(wb, "],\n"
404 - " %sdimensions%s: %ld,\n"
405 - " %spoints%s: %ld,\n"
406 - " %sformat%s: %s"
407 - , kq, kq, i
408 - , kq, kq, rows
409 - , kq, kq, sq
410 - );
335 + buffer_json_initialize(wb, kq, sq, 0, true);
336 +
337 + buffer_json_member_add_uint64(wb, "api", 1);
338 + buffer_json_member_add_string(wb, "id", qt->id);
339 + buffer_json_member_add_string(wb, "name", qt->id);
340 + buffer_json_member_add_time_t(wb, "view_update_every", r->update_every);
341 + buffer_json_member_add_time_t(wb, "update_every", qt->db.minimum_latest_update_every_s);
342 + buffer_json_member_add_time_t(wb, "first_entry", qt->db.first_time_s);
343 + buffer_json_member_add_time_t(wb, "last_entry", qt->db.last_time_s);
344 + buffer_json_member_add_time_t(wb, "after", r->after);
345 + buffer_json_member_add_time_t(wb, "before", r->before);
346 + buffer_json_member_add_string(wb, "group", time_grouping_tostring(group_method));
347 + web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", r->internal.query_options);
348 +
349 + if(!jsonwrap_dimension_names(wb, "dimension_names", r, options))
350 + rows = 0;
351
412 - rrdr_buffer_print_format(wb, format);
352 + if(!jsonwrap_dimension_ids(wb, "dimension_ids", r, options))
353 + rows = 0;
354
414 - buffer_sprintf(wb, "%s,\n"
415 - " %sdb_points_per_tier%s: [ "
416 - , sq
417 - , kq, kq
418 - );
355 + if (r->internal.query_options & RRDR_OPTION_ALL_DIMENSIONS)
356 + jsonwrap_full_dimension_list(wb, r);
357
420 - for(size_t tier = 0; tier < storage_tiers ; tier++)
421 - buffer_sprintf(wb, "%s%zu", tier>0?", ":"", r->internal.tier_points_read[tier]);
358 + jsonwrap_functions(wb, "functions", r);
359
423 - buffer_strcat(wb, " ],");
360 + if (!qt->request.st && !jsonwrap_chart_ids(wb, "chart_ids", r, options))
361 + rows = 0;
362
425 - if(options & RRDR_OPTION_SHOW_PLAN)
426 - rrdr_show_plan(r, wb, kq, sq);
363 + if (qt->instances.chart_label_key_pattern && !jsonwrap_chart_labels_filter(wb, "chart_labels", r, options))
364 + rows = 0;
365
428 - buffer_sprintf(wb, "\n %sresult%s: ", kq, kq);
366 + if(!jsonwrap_latest_values(wb, "latest_values", r, options))
367 + rows = 0;
368
369 + long dimensions = jsonwrap_view_latest_values(wb, "view_latest_values", r, options);
370 + if(!dimensions)
371 + rows = 0;
372 +
373 + buffer_json_member_add_uint64(wb, "dimensions", dimensions);
374 + buffer_json_member_add_uint64(wb, "points", rows);
375 + buffer_json_member_add_string(wb, "format", rrdr_format_to_string(format));
376 +
377 + buffer_json_member_add_array(wb, "db_points_per_tier");
378 + for(size_t tier = 0; tier < storage_tiers ; tier++)
379 + buffer_json_add_array_item_uint64(wb, r->internal.tier_points_read[tier]);
380 + buffer_json_array_close(wb);
381 +
382 + if(options & RRDR_OPTION_SHOW_PLAN)
383 + jsonwrap_query_plan(r, wb);
384 +
385 + buffer_sprintf(wb, ",\n %sresult%s:", kq, kq);
386 if(string_value) buffer_strcat(wb, sq);
431 - //info("JSONWRAPPER(): %s: END", r->st->id);
387 }
388
389 void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
@@ -455,23 +410,18 @@ void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint3
410 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value) {
411 (void)format;
412
458 - char kq[2] = "", // key quote
459 - sq[2] = ""; // string quote
413 + char sq[2] = ""; // string quote
414
415 if( options & RRDR_OPTION_GOOGLE_JSON ) {
462 - kq[0] = '\0';
416 sq[0] = '\'';
417 }
418 else {
466 - kq[0] = '"';
419 sq[0] = '"';
420 }
421
422 if(string_value) buffer_strcat(wb, sq);
423
472 - buffer_sprintf(wb, ",\n %smin%s: ", kq, kq);
473 - buffer_rrd_value(wb, r->min);
474 - buffer_sprintf(wb, ",\n %smax%s: ", kq, kq);
475 - buffer_rrd_value(wb, r->max);
476 - buffer_strcat(wb, "\n}\n");
424 + buffer_json_member_add_double(wb, "min", r->min);
425 + buffer_json_member_add_double(wb, "max", r->max);
426 + buffer_json_finalize(wb);
427 }
web/api/formatters/json_wrapper.h
+1 -1
@@ -8,7 +8,7 @@
8
9
10 void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, int string_value,
11 - RRDR_GROUPING group_method);
11 + RRDR_TIME_GROUPING group_method);
12 void rrdr_json_wrapper_anomaly_rates(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value);
13 void rrdr_json_wrapper_end(RRDR *r, BUFFER *wb, uint32_t format, uint32_t options, int string_value);
14
web/api/formatters/rrd2json.c
+35 -35
@@ -7,63 +7,63 @@ void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb) {
7 rrdset2json(st, wb, NULL, NULL, 0);
8 }
9
10 -void rrdr_buffer_print_format(BUFFER *wb, uint32_t format) {
10 +const char *rrdr_format_to_string(uint32_t format) {
11 switch(format) {
12 case DATASOURCE_JSON:
13 - buffer_strcat(wb, DATASOURCE_FORMAT_JSON);
13 + return DATASOURCE_FORMAT_JSON;
14 break;
15
16 case DATASOURCE_DATATABLE_JSON:
17 - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSON);
17 + return DATASOURCE_FORMAT_DATATABLE_JSON;
18 break;
19
20 case DATASOURCE_DATATABLE_JSONP:
21 - buffer_strcat(wb, DATASOURCE_FORMAT_DATATABLE_JSONP);
21 + return DATASOURCE_FORMAT_DATATABLE_JSONP;
22 break;
23
24 case DATASOURCE_JSONP:
25 - buffer_strcat(wb, DATASOURCE_FORMAT_JSONP);
25 + return DATASOURCE_FORMAT_JSONP;
26 break;
27
28 case DATASOURCE_SSV:
29 - buffer_strcat(wb, DATASOURCE_FORMAT_SSV);
29 + return DATASOURCE_FORMAT_SSV;
30 break;
31
32 case DATASOURCE_CSV:
33 - buffer_strcat(wb, DATASOURCE_FORMAT_CSV);
33 + return DATASOURCE_FORMAT_CSV;
34 break;
35
36 case DATASOURCE_TSV:
37 - buffer_strcat(wb, DATASOURCE_FORMAT_TSV);
37 + return DATASOURCE_FORMAT_TSV;
38 break;
39
40 case DATASOURCE_HTML:
41 - buffer_strcat(wb, DATASOURCE_FORMAT_HTML);
41 + return DATASOURCE_FORMAT_HTML;
42 break;
43
44 case DATASOURCE_JS_ARRAY:
45 - buffer_strcat(wb, DATASOURCE_FORMAT_JS_ARRAY);
45 + return DATASOURCE_FORMAT_JS_ARRAY;
46 break;
47
48 case DATASOURCE_SSV_COMMA:
49 - buffer_strcat(wb, DATASOURCE_FORMAT_SSV_COMMA);
49 + return DATASOURCE_FORMAT_SSV_COMMA;
50 break;
51
52 default:
53 - buffer_strcat(wb, "unknown");
53 + return "unknown";
54 break;
55 }
56 }
57
58 int rrdset2value_api_v1(
59 - RRDSET *st
59 + RRDSET *st
60 , BUFFER *wb
61 , NETDATA_DOUBLE *n
62 , const char *dimensions
63 , size_t points
64 , time_t after
65 , time_t before
66 - , RRDR_GROUPING group_method
66 + , RRDR_TIME_GROUPING group_method
67 , const char *group_options
68 , time_t resampling_time
69 , uint32_t options
@@ -167,76 +167,76 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
167
168 DATASOURCE_FORMAT format = qt->request.format;
169 RRDR_OPTIONS options = qt->request.options;
170 - RRDR_GROUPING group_method = qt->request.group_method;
170 + RRDR_TIME_GROUPING group_method = qt->request.time_group_method;
171
172 switch(format) {
173 case DATASOURCE_SSV:
174 if(options & RRDR_OPTION_JSON_WRAP) {
175 - wb->contenttype = CT_APPLICATION_JSON;
175 + wb->content_type = CT_APPLICATION_JSON;
176 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
177 rrdr2ssv(r, wb, options, "", " ", "");
178 rrdr_json_wrapper_end(r, wb, format, options, 1);
179 }
180 else {
181 - wb->contenttype = CT_TEXT_PLAIN;
181 + wb->content_type = CT_TEXT_PLAIN;
182 rrdr2ssv(r, wb, options, "", " ", "");
183 }
184 break;
185
186 case DATASOURCE_SSV_COMMA:
187 if(options & RRDR_OPTION_JSON_WRAP) {
188 - wb->contenttype = CT_APPLICATION_JSON;
188 + wb->content_type = CT_APPLICATION_JSON;
189 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
190 rrdr2ssv(r, wb, options, "", ",", "");
191 rrdr_json_wrapper_end(r, wb, format, options, 1);
192 }
193 else {
194 - wb->contenttype = CT_TEXT_PLAIN;
194 + wb->content_type = CT_TEXT_PLAIN;
195 rrdr2ssv(r, wb, options, "", ",", "");
196 }
197 break;
198
199 case DATASOURCE_JS_ARRAY:
200 if(options & RRDR_OPTION_JSON_WRAP) {
201 - wb->contenttype = CT_APPLICATION_JSON;
201 + wb->content_type = CT_APPLICATION_JSON;
202 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
203 rrdr2ssv(r, wb, options, "[", ",", "]");
204 rrdr_json_wrapper_end(r, wb, format, options, 0);
205 }
206 else {
207 - wb->contenttype = CT_APPLICATION_JSON;
207 + wb->content_type = CT_APPLICATION_JSON;
208 rrdr2ssv(r, wb, options, "[", ",", "]");
209 }
210 break;
211
212 case DATASOURCE_CSV:
213 if(options & RRDR_OPTION_JSON_WRAP) {
214 - wb->contenttype = CT_APPLICATION_JSON;
214 + wb->content_type = CT_APPLICATION_JSON;
215 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
216 rrdr2csv(r, wb, format, options, "", ",", "\\n", "");
217 rrdr_json_wrapper_end(r, wb, format, options, 1);
218 }
219 else {
220 - wb->contenttype = CT_TEXT_PLAIN;
220 + wb->content_type = CT_TEXT_PLAIN;
221 rrdr2csv(r, wb, format, options, "", ",", "\r\n", "");
222 }
223 break;
224
225 case DATASOURCE_CSV_MARKDOWN:
226 if(options & RRDR_OPTION_JSON_WRAP) {
227 - wb->contenttype = CT_APPLICATION_JSON;
227 + wb->content_type = CT_APPLICATION_JSON;
228 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
229 rrdr2csv(r, wb, format, options, "", "|", "\\n", "");
230 rrdr_json_wrapper_end(r, wb, format, options, 1);
231 }
232 else {
233 - wb->contenttype = CT_TEXT_PLAIN;
233 + wb->content_type = CT_TEXT_PLAIN;
234 rrdr2csv(r, wb, format, options, "", "|", "\r\n", "");
235 }
236 break;
237
238 case DATASOURCE_CSV_JSON_ARRAY:
239 - wb->contenttype = CT_APPLICATION_JSON;
239 + wb->content_type = CT_APPLICATION_JSON;
240 if(options & RRDR_OPTION_JSON_WRAP) {
241 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
242 buffer_strcat(wb, "[\n");
@@ -245,7 +245,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
245 rrdr_json_wrapper_end(r, wb, format, options, 0);
246 }
247 else {
248 - wb->contenttype = CT_APPLICATION_JSON;
248 + wb->content_type = CT_APPLICATION_JSON;
249 buffer_strcat(wb, "[\n");
250 rrdr2csv(r, wb, format, options + RRDR_OPTION_LABEL_QUOTES, "[", ",", "]", ",\n");
251 buffer_strcat(wb, "\n]");
@@ -254,20 +254,20 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
254
255 case DATASOURCE_TSV:
256 if(options & RRDR_OPTION_JSON_WRAP) {
257 - wb->contenttype = CT_APPLICATION_JSON;
257 + wb->content_type = CT_APPLICATION_JSON;
258 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
259 rrdr2csv(r, wb, format, options, "", "\t", "\\n", "");
260 rrdr_json_wrapper_end(r, wb, format, options, 1);
261 }
262 else {
263 - wb->contenttype = CT_TEXT_PLAIN;
263 + wb->content_type = CT_TEXT_PLAIN;
264 rrdr2csv(r, wb, format, options, "", "\t", "\r\n", "");
265 }
266 break;
267
268 case DATASOURCE_HTML:
269 if(options & RRDR_OPTION_JSON_WRAP) {
270 - wb->contenttype = CT_APPLICATION_JSON;
270 + wb->content_type = CT_APPLICATION_JSON;
271 rrdr_json_wrapper_begin(r, wb, format, options, 1, group_method);
272 buffer_strcat(wb, "<html>\\n<center>\\n<table border=\\\"0\\\" cellpadding=\\\"5\\\" cellspacing=\\\"5\\\">\\n");
273 rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\\n", "");
@@ -275,7 +275,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
275 rrdr_json_wrapper_end(r, wb, format, options, 1);
276 }
277 else {
278 - wb->contenttype = CT_TEXT_HTML;
278 + wb->content_type = CT_TEXT_HTML;
279 buffer_strcat(wb, "<html>\n<center>\n<table border=\"0\" cellpadding=\"5\" cellspacing=\"5\">\n");
280 rrdr2csv(r, wb, format, options, "<tr><td>", "</td><td>", "</td></tr>\n", "");
281 buffer_strcat(wb, "</table>\n</center>\n</html>\n");
@@ -283,7 +283,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
283 break;
284
285 case DATASOURCE_DATATABLE_JSONP:
286 - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
286 + wb->content_type = CT_APPLICATION_X_JAVASCRIPT;
287
288 if(options & RRDR_OPTION_JSON_WRAP)
289 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
@@ -295,7 +295,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
295 break;
296
297 case DATASOURCE_DATATABLE_JSON:
298 - wb->contenttype = CT_APPLICATION_JSON;
298 + wb->content_type = CT_APPLICATION_JSON;
299
300 if(options & RRDR_OPTION_JSON_WRAP)
301 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
@@ -307,7 +307,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
307 break;
308
309 case DATASOURCE_JSONP:
310 - wb->contenttype = CT_APPLICATION_X_JAVASCRIPT;
310 + wb->content_type = CT_APPLICATION_X_JAVASCRIPT;
311 if(options & RRDR_OPTION_JSON_WRAP)
312 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
313
@@ -319,7 +319,7 @@ int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, QUERY_TARGET *qt, time_t *l
319
320 case DATASOURCE_JSON:
321 default:
322 - wb->contenttype = CT_APPLICATION_JSON;
322 + wb->content_type = CT_APPLICATION_JSON;
323
324 if(options & RRDR_OPTION_JSON_WRAP)
325 rrdr_json_wrapper_begin(r, wb, format, options, 0, group_method);
web/api/formatters/rrd2json.h
+10 -3
@@ -53,19 +53,19 @@ typedef enum {
53 #define DATASOURCE_FORMAT_CSV_MARKDOWN "markdown"
54
55 void rrd_stats_api_v1_chart(RRDSET *st, BUFFER *wb);
56 -void rrdr_buffer_print_format(BUFFER *wb, uint32_t format);
56 +const char *rrdr_format_to_string(uint32_t format);
57
58 int data_query_execute(ONEWAYALLOC *owa, BUFFER *wb, struct query_target *qt, time_t *latest_timestamp);
59
60 int rrdset2value_api_v1(
61 - RRDSET *st
61 + RRDSET *st
62 , BUFFER *wb
63 , NETDATA_DOUBLE *n
64 , const char *dimensions
65 , size_t points
66 , time_t after
67 , time_t before
68 - , RRDR_GROUPING group_method
68 + , RRDR_TIME_GROUPING group_method
69 , const char *group_options
70 , time_t resampling_time
71 , uint32_t options
@@ -82,4 +82,11 @@ int rrdset2value_api_v1(
82 , STORAGE_PRIORITY priority
83 );
84
85 +static inline bool rrdr_dimension_should_be_exposed(RRDR_DIMENSION_FLAGS rrdr_dim_flags, RRDR_OPTIONS options) {
86 + if(unlikely(rrdr_dim_flags & RRDR_DIMENSION_HIDDEN)) return false;
87 + if(unlikely(!(rrdr_dim_flags & RRDR_DIMENSION_QUERIED))) return false;
88 + if(unlikely((options & RRDR_OPTION_NONZERO) && !(rrdr_dim_flags & RRDR_DIMENSION_NONZERO))) return false;
89 + return true;
90 +}
91 +
92 #endif /* NETDATA_RRD2JSON_H */
web/api/formatters/rrdset2json.c
+4 -4
@@ -96,9 +96,9 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
96 buffer_strcat(wb, ",\n\t\t\t\t\"");
97 else
98 buffer_strcat(wb, "\t\t\t\t\"");
99 - buffer_strcat_jsonescape(wb, rrddim_id(rd));
99 + buffer_json_strcat(wb, rrddim_id(rd));
100 buffer_strcat(wb, "\": { \"name\": \"");
101 - buffer_strcat_jsonescape(wb, rrddim_name(rd));
101 + buffer_json_strcat(wb, rrddim_name(rd));
102 buffer_strcat(wb, "\" }");
103
104 dimensions++;
@@ -112,9 +112,9 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
112 health_api_v1_chart_custom_variables2json(st, wb);
113
114 buffer_strcat(wb, ",\n\t\t\t\"green\": ");
115 - buffer_rrd_value(wb, st->green);
115 + buffer_print_netdata_double(wb, st->green);
116 buffer_strcat(wb, ",\n\t\t\t\"red\": ");
117 - buffer_rrd_value(wb, st->red);
117 + buffer_print_netdata_double(wb, st->red);
118
119 if (likely(!skip_volatile)) {
120 buffer_strcat(wb, ",\n\t\t\t\"alarms\": {\n");
web/api/formatters/ssv/ssv.c
+1 -1
@@ -38,7 +38,7 @@ void rrdr2ssv(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, const char *prefix, con
38 buffer_strcat(wb, "null");
39 }
40 else
41 - buffer_rrd_value(wb, v);
41 + buffer_print_netdata_double(wb, v);
42 }
43 buffer_strcat(wb, suffix);
44 //info("RRD2SSV(): %s: END", r->st->id);
web/api/formatters/value/value.c
+5 -6
@@ -37,9 +37,8 @@ inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all
37
38 // for each dimension
39 for (c = 0; c < used; c++) {
40 - if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) continue;
41 - if(unlikely(!(r->od[c] & RRDR_DIMENSION_QUERIED))) continue;
42 - if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
40 + if(!rrdr_dimension_should_be_exposed(r->od[c], options))
41 + continue;
42
43 NETDATA_DOUBLE n = cn[c];
44
@@ -107,7 +106,7 @@ inline NETDATA_DOUBLE rrdr2value(RRDR *r, long i, RRDR_OPTIONS options, int *all
106 QUERY_VALUE rrdmetric2value(RRDHOST *host,
107 struct rrdcontext_acquired *rca, struct rrdinstance_acquired *ria, struct rrdmetric_acquired *rma,
108 time_t after, time_t before,
110 - RRDR_OPTIONS options, RRDR_GROUPING group_method, const char *group_options,
109 + RRDR_OPTIONS options, RRDR_TIME_GROUPING group_method, const char *group_options,
110 size_t tier, time_t timeout, QUERY_SOURCE query_source, STORAGE_PRIORITY priority
111 ) {
112 QUERY_TARGET_REQUEST qtr = {
@@ -119,8 +118,8 @@ QUERY_VALUE rrdmetric2value(RRDHOST *host,
118 .before = before,
119 .points = 1,
120 .options = options,
122 - .group_method = group_method,
123 - .group_options = group_options,
121 + .time_group_method = group_method,
122 + .time_group_options = group_options,
123 .tier = tier,
124 .timeout = timeout,
125 .query_source = query_source,
web/api/formatters/value/value.h
+1 -1
@@ -22,7 +22,7 @@ struct rrdcontext_acquired;
22 QUERY_VALUE rrdmetric2value(RRDHOST *host,
23 struct rrdcontext_acquired *rca, struct rrdinstance_acquired *ria, struct rrdmetric_acquired *rma,
24 time_t after, time_t before,
25 - RRDR_OPTIONS options, RRDR_GROUPING group_method, const char *group_options,
25 + RRDR_OPTIONS options, RRDR_TIME_GROUPING group_method, const char *group_options,
26 size_t tier, time_t timeout, QUERY_SOURCE query_source, STORAGE_PRIORITY priority
27 );
28
web/api/health/health_cmdapi.c
+2 -2
@@ -121,7 +121,7 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
121
122 BUFFER *wb = w->response.data;
123 buffer_flush(wb);
124 - wb->contenttype = CT_TEXT_PLAIN;
124 + wb->content_type = CT_TEXT_PLAIN;
125
126 buffer_flush(w->response.data);
127
@@ -171,7 +171,7 @@ int web_client_api_request_v1_mgmt_health(RRDHOST *host, struct web_client *w, c
171 silencers->silencers = NULL;
172 buffer_strcat(wb, HEALTH_CMDAPI_MSG_RESET);
173 } else if (!strcmp(value, HEALTH_CMDAPI_CMD_LIST)) {
174 - w->response.data->contenttype = CT_APPLICATION_JSON;
174 + w->response.data->content_type = CT_APPLICATION_JSON;
175 health_silencers2json(wb);
176 config_changed=0;
177 }
web/api/queries/query.c
+13 -13
@@ -24,7 +24,7 @@
24 static struct {
25 const char *name;
26 uint32_t hash;
27 - RRDR_GROUPING value;
27 + RRDR_TIME_GROUPING value;
28
29 // One time initialization for the module.
30 // This is called once, when netdata starts.
@@ -590,7 +590,7 @@ static struct {
590 }
591 };
592
593 -void web_client_api_v1_init_grouping(void) {
593 +void time_grouping_init(void) {
594 int i;
595
596 for(i = 0; api_v1_data_groups[i].name ; i++) {
@@ -601,7 +601,7 @@ void web_client_api_v1_init_grouping(void) {
601 }
602 }
603
604 -const char *group_method2string(RRDR_GROUPING group) {
604 +const char *time_grouping_method2string(RRDR_TIME_GROUPING group) {
605 int i;
606
607 for(i = 0; api_v1_data_groups[i].name ; i++) {
@@ -613,7 +613,7 @@ const char *group_method2string(RRDR_GROUPING group) {
613 return "unknown-group-method";
614 }
615
616 -RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPING def) {
616 +RRDR_TIME_GROUPING time_grouping_parse(const char *name, RRDR_TIME_GROUPING def) {
617 int i;
618
619 uint32_t hash = simple_hash(name);
@@ -624,7 +624,7 @@ RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPI
624 return def;
625 }
626
627 -const char *web_client_api_request_v1_data_group_to_string(RRDR_GROUPING group) {
627 +const char *time_grouping_tostring(RRDR_TIME_GROUPING group) {
628 int i;
629
630 for(i = 0; api_v1_data_groups[i].name ; i++)
@@ -634,7 +634,7 @@ const char *web_client_api_request_v1_data_group_to_string(RRDR_GROUPING group)
634 return "unknown";
635 }
636
637 -static void rrdr_set_grouping_function(RRDR *r, RRDR_GROUPING group_method) {
637 +static void rrdr_set_grouping_function(RRDR *r, RRDR_TIME_GROUPING group_method) {
638 int i, found = 0;
639 for(i = 0; !found && api_v1_data_groups[i].name ;i++) {
640 if(api_v1_data_groups[i].value == group_method) {
@@ -1721,7 +1721,7 @@ void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, size_t tier, time_t now_s
1721 #ifdef NETDATA_INTERNAL_CHECKS
1722 static void rrd2rrdr_log_request_response_metadata(RRDR *r
1723 , RRDR_OPTIONS options __maybe_unused
1724 - , RRDR_GROUPING group_method
1724 + , RRDR_TIME_GROUPING group_method
1725 , bool aligned
1726 , size_t group
1727 , time_t resampling_time
@@ -1753,7 +1753,7 @@ static void rrd2rrdr_log_request_response_metadata(RRDR *r
1753
1754 // grouping
1755 , (aligned) ? "aligned" : "unaligned"
1756 - , group_method2string(group_method)
1756 + , time_grouping_method2string(group_method)
1757 , group
1758 , resampling_time
1759 , resampling_group
@@ -1890,7 +1890,7 @@ bool query_target_calculate_window(QUERY_TARGET *qt) {
1890 size_t points_requested = (long)qt->request.points;
1891 time_t after_requested = qt->request.after;
1892 time_t before_requested = qt->request.before;
1893 - RRDR_GROUPING group_method = qt->request.group_method;
1893 + RRDR_TIME_GROUPING group_method = qt->request.time_group_method;
1894 time_t resampling_time_requested = qt->request.resampling_time;
1895 RRDR_OPTIONS options = qt->request.options;
1896 size_t tier = qt->request.tier;
@@ -2146,7 +2146,7 @@ bool query_target_calculate_window(QUERY_TARGET *qt) {
2146 qt->window.points = points_wanted;
2147 qt->window.group = group;
2148 qt->window.group_method = group_method;
2149 - qt->window.group_options = qt->request.group_options;
2149 + qt->window.group_options = qt->request.time_group_options;
2150 qt->window.query_granularity = query_granularity;
2151 qt->window.resampling_group = resampling_group;
2152 qt->window.resampling_divisor = resampling_divisor;
@@ -2160,7 +2160,7 @@ bool query_target_calculate_window(QUERY_TARGET *qt) {
2160 RRDR *rrd2rrdr_legacy(
2161 ONEWAYALLOC *owa,
2162 RRDSET *st, size_t points, time_t after, time_t before,
2163 - RRDR_GROUPING group_method, time_t resampling_time, RRDR_OPTIONS options, const char *dimensions,
2163 + RRDR_TIME_GROUPING group_method, time_t resampling_time, RRDR_OPTIONS options, const char *dimensions,
2164 const char *group_options, time_t timeout, size_t tier, QUERY_SOURCE query_source,
2165 STORAGE_PRIORITY priority) {
2166
@@ -2169,11 +2169,11 @@ RRDR *rrd2rrdr_legacy(
2169 .points = points,
2170 .after = after,
2171 .before = before,
2172 - .group_method = group_method,
2172 + .time_group_method = group_method,
2173 .resampling_time = resampling_time,
2174 .options = options,
2175 .dimensions = dimensions,
2176 - .group_options = group_options,
2176 + .time_group_options = group_options,
2177 .timeout = timeout,
2178 .tier = tier,
2179 .query_source = query_source,
web/api/queries/query.h
+21 -6
@@ -7,7 +7,7 @@
7 extern "C" {
8 #endif
9
10 -typedef enum rrdr_grouping {
10 +typedef enum rrdr_time_grouping {
11 RRDR_GROUPING_UNDEFINED = 0,
12 RRDR_GROUPING_AVERAGE,
13 RRDR_GROUPING_MIN,
@@ -45,12 +45,27 @@ typedef enum rrdr_grouping {
45 RRDR_GROUPING_SES,
46 RRDR_GROUPING_DES,
47 RRDR_GROUPING_COUNTIF,
48 -} RRDR_GROUPING;
48 +} RRDR_TIME_GROUPING;
49
50 -const char *group_method2string(RRDR_GROUPING group);
51 -void web_client_api_v1_init_grouping(void);
52 -RRDR_GROUPING web_client_api_request_v1_data_group(const char *name, RRDR_GROUPING def);
53 -const char *web_client_api_request_v1_data_group_to_string(RRDR_GROUPING group);
50 +const char *time_grouping_method2string(RRDR_TIME_GROUPING group);
51 +void time_grouping_init(void);
52 +RRDR_TIME_GROUPING time_grouping_parse(const char *name, RRDR_TIME_GROUPING def);
53 +const char *time_grouping_tostring(RRDR_TIME_GROUPING group);
54 +
55 +typedef enum rrdr_group_by {
56 + RRDR_GROUP_BY_UNDEFINED = 0,
57 + RRDR_GROUP_BY_NODE,
58 + RRDR_GROUP_BY_INSTANCE,
59 + RRDR_GROUP_BY_LABEL,
60 +} RRDR_GROUP_BY;
61 +
62 +typedef enum rrdr_group_by_function {
63 + RRDR_GROUP_BY_FUNCTION_AVERAGE,
64 + RRDR_GROUP_BY_FUNCTION_MIN,
65 + RRDR_GROUP_BY_FUNCTION_MAX,
66 + RRDR_GROUP_BY_FUNCTION_SUM,
67 + RRDR_GROUP_BY_FUNCTION_SUM_COUNT,
68 +} RRDR_GROUP_BY_FUNCTION;
69
70 #ifdef __cplusplus
71 }
web/api/queries/rrdr.h
+1 -1
@@ -138,7 +138,7 @@ RRDR *rrdr_create(ONEWAYALLOC *owa, struct query_target *qt);
138 RRDR *rrd2rrdr_legacy(
139 ONEWAYALLOC *owa,
140 RRDSET *st, size_t points, time_t after, time_t before,
141 - RRDR_GROUPING group_method, time_t resampling_time, RRDR_OPTIONS options, const char *dimensions,
141 + RRDR_TIME_GROUPING group_method, time_t resampling_time, RRDR_OPTIONS options, const char *dimensions,
142 const char *group_options, time_t timeout, size_t tier, QUERY_SOURCE query_source,
143 STORAGE_PRIORITY priority);
144
web/api/queries/weights.c
+102 -133
@@ -114,112 +114,91 @@ static void results_header_to_json(DICTIONARY *results __maybe_unused, BUFFER *w
114 time_t after, time_t before,
115 time_t baseline_after, time_t baseline_before,
116 size_t points, WEIGHTS_METHOD method,
117 - RRDR_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
117 + RRDR_TIME_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
118 size_t examined_dimensions __maybe_unused, usec_t duration,
119 WEIGHTS_STATS *stats) {
120
121 - buffer_sprintf(wb, "{\n"
122 - "\t\"after\": %lld,\n"
123 - "\t\"before\": %lld,\n"
124 - "\t\"duration\": %lld,\n"
125 - "\t\"points\": %zu,\n",
126 - (long long)after,
127 - (long long)before,
128 - (long long)(before - after),
129 - points
130 - );
131 -
132 - if(method == WEIGHTS_METHOD_MC_KS2 || method == WEIGHTS_METHOD_MC_VOLUME)
133 - buffer_sprintf(wb, ""
134 - "\t\"baseline_after\": %lld,\n"
135 - "\t\"baseline_before\": %lld,\n"
136 - "\t\"baseline_duration\": %lld,\n"
137 - "\t\"baseline_points\": %zu,\n",
138 - (long long)baseline_after,
139 - (long long)baseline_before,
140 - (long long)(baseline_before - baseline_after),
141 - points << shifts
142 - );
143 -
144 - buffer_sprintf(wb, ""
145 - "\t\"statistics\": {\n"
146 - "\t\t\"query_time_ms\": %f,\n"
147 - "\t\t\"db_queries\": %zu,\n"
148 - "\t\t\"query_result_points\": %zu,\n"
149 - "\t\t\"binary_searches\": %zu,\n"
150 - "\t\t\"db_points_read\": %zu,\n"
151 - "\t\t\"db_points_per_tier\": [ ",
152 - (double)duration / (double)USEC_PER_MS,
153 - stats->db_queries,
154 - stats->result_points,
155 - stats->binary_searches,
156 - stats->db_points
157 - );
158 -
159 - for(size_t tier = 0; tier < storage_tiers ;tier++)
160 - buffer_sprintf(wb, "%s%zu", tier?", ":"", stats->db_points_per_tier[tier]);
161 -
162 - buffer_sprintf(wb, " ]\n"
163 - "\t},\n"
164 - "\t\"group\": \"%s\",\n"
165 - "\t\"method\": \"%s\",\n"
166 - "\t\"options\": \"",
167 - web_client_api_request_v1_data_group_to_string(group),
168 - weights_method_to_string(method)
169 - );
170 -
171 - web_client_api_request_v1_data_options_to_buffer(wb, options);
121 + buffer_json_initialize(wb, "\"", "\"", 0, true);
122 + buffer_json_member_add_time_t(wb, "after", after);
123 + buffer_json_member_add_time_t(wb, "before", before);
124 + buffer_json_member_add_time_t(wb, "duration", before - after);
125 + buffer_json_member_add_uint64(wb, "points", points);
126 +
127 + if(method == WEIGHTS_METHOD_MC_KS2 || method == WEIGHTS_METHOD_MC_VOLUME) {
128 + buffer_json_member_add_time_t(wb, "baseline_after", baseline_after);
129 + buffer_json_member_add_time_t(wb, "baseline_before", baseline_before);
130 + buffer_json_member_add_time_t(wb, "baseline_duration", baseline_before - baseline_after);
131 + buffer_json_member_add_uint64(wb, "baseline_points", points << shifts);
132 + }
133 +
134 + buffer_json_member_add_object(wb, "statistics");
135 + {
136 + buffer_json_member_add_double(wb, "query_time_ms", (double) duration / (double) USEC_PER_MS);
137 + buffer_json_member_add_uint64(wb, "db_queries", stats->db_queries);
138 + buffer_json_member_add_uint64(wb, "query_result_points", stats->result_points);
139 + buffer_json_member_add_uint64(wb, "binary_searches", stats->binary_searches);
140 + buffer_json_member_add_uint64(wb, "db_points_read", stats->db_points);
141 +
142 + buffer_json_member_add_array(wb, "db_points_per_tier");
143 + {
144 + for (size_t tier = 0; tier < storage_tiers; tier++)
145 + buffer_json_add_array_item_uint64(wb, stats->db_points_per_tier[tier]);
146 + }
147 + buffer_json_array_close(wb);
148 + }
149 + buffer_json_object_close(wb);
150 +
151 + buffer_json_member_add_string(wb, "group", time_grouping_tostring(group));
152 + buffer_json_member_add_string(wb, "method", weights_method_to_string(method));
153 + web_client_api_request_v1_data_options_to_buffer_json_array(wb, "options", options);
154 }
155
156 static size_t registered_results_to_json_charts(DICTIONARY *results, BUFFER *wb,
157 time_t after, time_t before,
158 time_t baseline_after, time_t baseline_before,
159 size_t points, WEIGHTS_METHOD method,
178 - RRDR_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
160 + RRDR_TIME_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
161 size_t examined_dimensions, usec_t duration,
162 WEIGHTS_STATS *stats) {
163
164 results_header_to_json(results, wb, after, before, baseline_after, baseline_before,
165 points, method, group, options, shifts, examined_dimensions, duration, stats);
166
185 - buffer_strcat(wb, "\",\n\t\"correlated_charts\": {\n");
167 + buffer_json_member_add_object(wb, "correlated_charts");
168
187 - size_t charts = 0, chart_dims = 0, total_dimensions = 0;
169 + size_t charts = 0, total_dimensions = 0;
170 struct register_result *t;
171 RRDINSTANCE_ACQUIRED *last_ria = NULL; // never access this - we use it only for comparison
172 dfe_start_read(results, t) {
173 if(t->ria != last_ria) {
174 last_ria = t->ria;
175
194 - if(charts) buffer_strcat(wb, "\n\t\t\t}\n\t\t},\n");
195 - buffer_strcat(wb, "\t\t\"");
196 - buffer_strcat(wb, rrdinstance_acquired_id(t->ria));
197 - buffer_strcat(wb, "\": {\n");
198 - buffer_strcat(wb, "\t\t\t\"context\": \"");
199 - buffer_strcat(wb, rrdcontext_acquired_id(t->rca));
200 - buffer_strcat(wb, "\",\n\t\t\t\"dimensions\": {\n");
176 + if(charts) {
177 + buffer_json_object_close(wb); // dimensions
178 + buffer_json_object_close(wb); // chart:id
179 + }
180 +
181 + buffer_json_member_add_object(wb, rrdinstance_acquired_id(t->ria));
182 + buffer_json_member_add_string(wb, "context", rrdcontext_acquired_id(t->rca));
183 + buffer_json_member_add_object(wb, "dimensions");
184 charts++;
202 - chart_dims = 0;
185 }
204 - if (chart_dims) buffer_sprintf(wb, ",\n");
205 - buffer_sprintf(wb, "\t\t\t\t\"%s\": " NETDATA_DOUBLE_FORMAT, rrdmetric_acquired_name(t->rma), t->value);
206 - chart_dims++;
186 + buffer_json_member_add_double(wb, rrdmetric_acquired_name(t->rma), t->value);
187 total_dimensions++;
188 }
189 dfe_done(t);
190
191 // close dimensions and chart
212 - if (total_dimensions)
213 - buffer_strcat(wb, "\n\t\t\t}\n\t\t}\n");
214 -
215 - // close correlated_charts
216 - buffer_sprintf(wb, "\t},\n"
217 - "\t\"correlated_dimensions\": %zu,\n"
218 - "\t\"total_dimensions_count\": %zu\n"
219 - "}\n",
220 - total_dimensions,
221 - examined_dimensions
222 - );
192 + if (total_dimensions) {
193 + buffer_json_object_close(wb); // dimensions
194 + buffer_json_object_close(wb); // chart:id
195 + }
196 +
197 + buffer_json_object_close(wb);
198 +
199 + buffer_json_member_add_uint64(wb, "correlated_dimensions", total_dimensions);
200 + buffer_json_member_add_uint64(wb, "total_dimensions_count", examined_dimensions);
201 + buffer_json_finalize(wb);
202
203 return total_dimensions;
204 }
@@ -228,14 +207,14 @@ static size_t registered_results_to_json_contexts(DICTIONARY *results, BUFFER *w
207 time_t after, time_t before,
208 time_t baseline_after, time_t baseline_before,
209 size_t points, WEIGHTS_METHOD method,
231 - RRDR_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
210 + RRDR_TIME_GROUPING group, RRDR_OPTIONS options, uint32_t shifts,
211 size_t examined_dimensions, usec_t duration,
212 WEIGHTS_STATS *stats) {
213
214 results_header_to_json(results, wb, after, before, baseline_after, baseline_before,
215 points, method, group, options, shifts, examined_dimensions, duration, stats);
216
238 - buffer_strcat(wb, "\",\n\t\"contexts\": {\n");
217 + buffer_json_member_add_object(wb, "contexts");
218
219 size_t contexts = 0, charts = 0, total_dimensions = 0, context_dims = 0, chart_dims = 0;
220 NETDATA_DOUBLE contexts_total_weight = 0.0, charts_total_weight = 0.0;
@@ -247,18 +226,17 @@ static size_t registered_results_to_json_contexts(DICTIONARY *results, BUFFER *w
226 if(t->rca != last_rca) {
227 last_rca = t->rca;
228
250 - if(contexts)
251 - buffer_sprintf(wb, "\n"
252 - "\t\t\t\t\t},\n"
253 - "\t\t\t\t\t\"weight\":" NETDATA_DOUBLE_FORMAT "\n"
254 - "\t\t\t\t}\n\t\t\t},\n"
255 - "\t\t\t\"weight\":" NETDATA_DOUBLE_FORMAT "\n\t\t},\n"
256 - , charts_total_weight / (double)chart_dims
257 - , contexts_total_weight / (double)context_dims);
229 + if(contexts) {
230 + buffer_json_object_close(wb); // dimensions
231 + buffer_json_member_add_double(wb, "weight", charts_total_weight / (double) chart_dims);
232 + buffer_json_object_close(wb); // chart:id
233 + buffer_json_object_close(wb); // charts
234 + buffer_json_member_add_double(wb, "weight", contexts_total_weight / (double) context_dims);
235 + buffer_json_object_close(wb); // context
236 + }
237
259 - buffer_strcat(wb, "\t\t\"");
260 - buffer_strcat(wb, rrdcontext_acquired_id(t->rca));
261 - buffer_strcat(wb, "\": {\n\t\t\t\"charts\":{\n");
238 + buffer_json_member_add_object(wb, rrdcontext_acquired_id(t->rca));
239 + buffer_json_member_add_object(wb, "charts");
240
241 contexts++;
242 charts = 0;
@@ -271,25 +249,21 @@ static size_t registered_results_to_json_contexts(DICTIONARY *results, BUFFER *w
249 if(t->ria != last_ria) {
250 last_ria = t->ria;
251
274 - if(charts)
275 - buffer_sprintf(wb, "\n"
276 - "\t\t\t\t\t},\n"
277 - "\t\t\t\t\t\"weight\":" NETDATA_DOUBLE_FORMAT "\n"
278 - "\t\t\t\t},\n"
279 - , charts_total_weight / (double)chart_dims);
252 + if(charts) {
253 + buffer_json_object_close(wb); // dimensions
254 + buffer_json_member_add_double(wb, "weight", charts_total_weight / (double) chart_dims);
255 + buffer_json_object_close(wb); // chart:id
256 + }
257
281 - buffer_strcat(wb, "\t\t\t\t\"");
282 - buffer_strcat(wb, rrdinstance_acquired_id(t->ria));
283 - buffer_strcat(wb, "\": {\n");
284 - buffer_strcat(wb, "\t\t\t\t\t\"dimensions\": {\n");
258 + buffer_json_member_add_object(wb, rrdinstance_acquired_id(t->ria));
259 + buffer_json_member_add_object(wb, "dimensions");
260
261 charts++;
262 chart_dims = 0;
263 charts_total_weight = 0.0;
264 }
265
291 - if (chart_dims) buffer_sprintf(wb, ",\n");
292 - buffer_sprintf(wb, "\t\t\t\t\t\t\"%s\": " NETDATA_DOUBLE_FORMAT, rrdmetric_acquired_name(t->rma), t->value);
266 + buffer_json_member_add_double(wb, rrdmetric_acquired_name(t->rma), t->value);
267 charts_total_weight += t->value;
268 contexts_total_weight += t->value;
269 chart_dims++;
@@ -299,25 +273,20 @@ static size_t registered_results_to_json_contexts(DICTIONARY *results, BUFFER *w
273 dfe_done(t);
274
275 // close dimensions and chart
302 - if (total_dimensions)
303 - buffer_sprintf(wb, "\n"
304 - "\t\t\t\t\t},\n"
305 - "\t\t\t\t\t\"weight\":" NETDATA_DOUBLE_FORMAT "\n"
306 - "\t\t\t\t}\n"
307 - "\t\t\t},\n"
308 - "\t\t\t\"weight\":" NETDATA_DOUBLE_FORMAT "\n"
309 - "\t\t}\n"
310 - , charts_total_weight / (double)chart_dims
311 - , contexts_total_weight / (double)context_dims);
312 -
313 - // close correlated_charts
314 - buffer_sprintf(wb, "\t},\n"
315 - "\t\"weighted_dimensions\": %zu,\n"
316 - "\t\"total_dimensions_count\": %zu\n"
317 - "}\n",
318 - total_dimensions,
319 - examined_dimensions
320 - );
276 + if (total_dimensions) {
277 + buffer_json_object_close(wb); // dimensions
278 + buffer_json_member_add_double(wb, "weight", charts_total_weight / (double) chart_dims);
279 + buffer_json_object_close(wb); // chart:id
280 + buffer_json_object_close(wb); // charts
281 + buffer_json_member_add_double(wb, "weight", contexts_total_weight / (double) context_dims);
282 + buffer_json_object_close(wb); // context
283 + }
284 +
285 + buffer_json_object_close(wb);
286 +
287 + buffer_json_member_add_uint64(wb, "correlated_dimensions", total_dimensions);
288 + buffer_json_member_add_uint64(wb, "total_dimensions_count", examined_dimensions);
289 + buffer_json_finalize(wb);
290
291 return total_dimensions;
292 }
@@ -500,7 +469,7 @@ NETDATA_DOUBLE *rrd2rrdr_ks2(
469 ONEWAYALLOC *owa, RRDHOST *host,
470 RRDCONTEXT_ACQUIRED *rca, RRDINSTANCE_ACQUIRED *ria, RRDMETRIC_ACQUIRED *rma,
471 time_t after, time_t before, size_t points, RRDR_OPTIONS options,
503 - RRDR_GROUPING group_method, const char *group_options, size_t tier,
472 + RRDR_TIME_GROUPING group_method, const char *group_options, size_t tier,
473 WEIGHTS_STATS *stats,
474 size_t *entries
475 ) {
@@ -516,11 +485,11 @@ NETDATA_DOUBLE *rrd2rrdr_ks2(
485 .before = before,
486 .points = points,
487 .options = options,
519 - .group_method = group_method,
520 - .group_options = group_options,
488 + .time_group_method = group_method,
489 + .time_group_options = group_options,
490 .tier = tier,
491 .query_source = QUERY_SOURCE_API_WEIGHTS,
523 - .priority = STORAGE_PRIORITY_NORMAL,
492 + .priority = STORAGE_PRIORITY_SYNCHRONOUS,
493 };
494
495 RRDR *r = rrd2rrdr(owa, query_target_create(&qtr));
@@ -570,7 +539,7 @@ static void rrdset_metric_correlations_ks2(
539 time_t baseline_after, time_t baseline_before,
540 time_t after, time_t before,
541 size_t points, RRDR_OPTIONS options,
573 - RRDR_GROUPING group_method, const char *group_options, size_t tier,
542 + RRDR_TIME_GROUPING group_method, const char *group_options, size_t tier,
543 uint32_t shifts,
544 WEIGHTS_STATS *stats, bool register_zero
545 ) {
@@ -636,7 +605,7 @@ static void rrdset_metric_correlations_volume(
605 DICTIONARY *results,
606 time_t baseline_after, time_t baseline_before,
607 time_t after, time_t before,
639 - RRDR_OPTIONS options, RRDR_GROUPING group_method, const char *group_options,
608 + RRDR_OPTIONS options, RRDR_TIME_GROUPING group_method, const char *group_options,
609 size_t tier,
610 WEIGHTS_STATS *stats, bool register_zero) {
611
@@ -644,7 +613,7 @@ static void rrdset_metric_correlations_volume(
613
614 QUERY_VALUE baseline_average = rrdmetric2value(host, rca, ria, rma, baseline_after, baseline_before,
615 options, group_method, group_options, tier, 0,
647 - QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_NORMAL);
616 + QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_SYNCHRONOUS);
617 merge_query_value_to_stats(&baseline_average, stats);
618
619 if(!netdata_double_isnumber(baseline_average.value)) {
@@ -654,7 +623,7 @@ static void rrdset_metric_correlations_volume(
623
624 QUERY_VALUE highlight_average = rrdmetric2value(host, rca, ria, rma, after, before,
625 options, group_method, group_options, tier, 0,
657 - QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_NORMAL);
626 + QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_SYNCHRONOUS);
627 merge_query_value_to_stats(&highlight_average, stats);
628
629 if(!netdata_double_isnumber(highlight_average.value))
@@ -669,7 +638,7 @@ static void rrdset_metric_correlations_volume(
638 snprintfz(highlight_countif_options, 50, "%s" NETDATA_DOUBLE_FORMAT, highlight_average.value < baseline_average.value ? "<" : ">", baseline_average.value);
639 QUERY_VALUE highlight_countif = rrdmetric2value(host, rca, ria, rma, after, before,
640 options, RRDR_GROUPING_COUNTIF, highlight_countif_options, tier, 0,
672 - QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_NORMAL);
641 + QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_SYNCHRONOUS);
642 merge_query_value_to_stats(&highlight_countif, stats);
643
644 if(!netdata_double_isnumber(highlight_countif.value)) {
@@ -704,7 +673,7 @@ static void rrdset_weights_anomaly_rate(
673 RRDCONTEXT_ACQUIRED *rca, RRDINSTANCE_ACQUIRED *ria, RRDMETRIC_ACQUIRED *rma,
674 DICTIONARY *results,
675 time_t after, time_t before,
707 - RRDR_OPTIONS options, RRDR_GROUPING group_method, const char *group_options,
676 + RRDR_OPTIONS options, RRDR_TIME_GROUPING group_method, const char *group_options,
677 size_t tier,
678 WEIGHTS_STATS *stats, bool register_zero) {
679
@@ -712,7 +681,7 @@ static void rrdset_weights_anomaly_rate(
681
682 QUERY_VALUE qv = rrdmetric2value(host, rca, ria, rma, after, before,
683 options, group_method, group_options, tier, 0,
715 - QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_NORMAL);
684 + QUERY_SOURCE_API_WEIGHTS, STORAGE_PRIORITY_SYNCHRONOUS);
685
686 merge_query_value_to_stats(&qv, stats);
687
@@ -807,7 +776,7 @@ static size_t spread_results_evenly(DICTIONARY *results, WEIGHTS_STATS *stats) {
776
777 int web_api_v1_weights(
778 RRDHOST *host, BUFFER *wb, WEIGHTS_METHOD method, WEIGHTS_FORMAT format,
810 - RRDR_GROUPING group, const char *group_options,
779 + RRDR_TIME_GROUPING group, const char *group_options,
780 time_t baseline_after, time_t baseline_before,
781 time_t after, time_t before,
782 size_t points, RRDR_OPTIONS options, SIMPLE_PATTERN *contexts, size_t tier, size_t timeout) {
web/api/queries/weights.h
+4 -4
@@ -21,10 +21,10 @@ extern int metric_correlations_version;
21 extern WEIGHTS_METHOD default_metric_correlations_method;
22
23 int web_api_v1_weights (RRDHOST *host, BUFFER *wb, WEIGHTS_METHOD method, WEIGHTS_FORMAT format,
24 - RRDR_GROUPING group, const char *group_options,
25 - time_t baseline_after, time_t baseline_before,
26 - time_t after, time_t before,
27 - size_t points, RRDR_OPTIONS options, SIMPLE_PATTERN *contexts, size_t tier, size_t timeout);
24 + RRDR_TIME_GROUPING group, const char *group_options,
25 + time_t baseline_after, time_t baseline_before,
26 + time_t after, time_t before,
27 + size_t points, RRDR_OPTIONS options, SIMPLE_PATTERN *contexts, size_t tier, size_t timeout);
28
29 WEIGHTS_METHOD weights_string_to_method(const char *method);
30 const char *weights_method_to_string(WEIGHTS_METHOD method);
web/api/web_api_v1.c
+173 -241
@@ -92,7 +92,7 @@ void web_client_api_v1_init(void) {
92 for(i = 0; api_v1_data_google_formats[i].name ; i++)
93 api_v1_data_google_formats[i].hash = simple_hash(api_v1_data_google_formats[i].name);
94
95 - web_client_api_v1_init_grouping();
95 + time_grouping_init();
96
97 uuid_t uuid;
98
@@ -186,20 +186,20 @@ inline RRDR_OPTIONS web_client_api_request_v1_data_options(char *o) {
186 return ret;
187 }
188
189 -void web_client_api_request_v1_data_options_to_buffer(BUFFER *wb, RRDR_OPTIONS options) {
189 +void web_client_api_request_v1_data_options_to_buffer_json_array(BUFFER *wb, const char *key, RRDR_OPTIONS options) {
190 + buffer_json_member_add_array(wb, key);
191 +
192 RRDR_OPTIONS used = 0; // to prevent adding duplicates
191 - int added = 0;
193 for(int i = 0; api_v1_data_options[i].name ; i++) {
194 if (unlikely((api_v1_data_options[i].value & options) && !(api_v1_data_options[i].value & used))) {
195 const char *name = api_v1_data_options[i].name;
196 used |= api_v1_data_options[i].value;
197
197 - if(added) buffer_strcat(wb, ",");
198 - buffer_strcat(wb, name);
199 -
200 - added++;
198 + buffer_json_add_array_item_string(wb, name);
199 }
200 }
201 +
202 + buffer_json_array_close(wb);
203 }
204
205 void web_client_api_request_v1_data_options_to_string(char *buf, size_t size, RRDR_OPTIONS options) {
@@ -268,7 +268,7 @@ inline int web_client_api_request_v1_alarms(RRDHOST *host, struct web_client *w,
268 int all = web_client_api_request_v1_alarms_select(url);
269
270 buffer_flush(w->response.data);
271 - w->response.data->contenttype = CT_APPLICATION_JSON;
271 + w->response.data->content_type = CT_APPLICATION_JSON;
272 health_alarms2json(host, w->response.data, all);
273 buffer_no_cacheable(w->response.data);
274 return HTTP_RESP_OK;
@@ -278,7 +278,7 @@ inline int web_client_api_request_v1_alarms_values(RRDHOST *host, struct web_cli
278 int all = web_client_api_request_v1_alarms_select(url);
279
280 buffer_flush(w->response.data);
281 - w->response.data->contenttype = CT_APPLICATION_JSON;
281 + w->response.data->content_type = CT_APPLICATION_JSON;
282 health_alarms_values2json(host, w->response.data, all);
283 buffer_no_cacheable(w->response.data);
284 return HTTP_RESP_OK;
@@ -321,7 +321,7 @@ inline int web_client_api_request_v1_alarm_count(RRDHOST *host, struct web_clien
321 health_aggregate_alarms(host, w->response.data, contexts, status);
322
323 buffer_sprintf(w->response.data, "]\n");
324 - w->response.data->contenttype = CT_APPLICATION_JSON;
324 + w->response.data->content_type = CT_APPLICATION_JSON;
325 buffer_no_cacheable(w->response.data);
326
327 buffer_free(contexts);
@@ -345,7 +345,7 @@ inline int web_client_api_request_v1_alarm_log(RRDHOST *host, struct web_client
345 }
346
347 buffer_flush(w->response.data);
348 - w->response.data->contenttype = CT_APPLICATION_JSON;
348 + w->response.data->content_type = CT_APPLICATION_JSON;
349 health_alarm_log2json(host, w->response.data, after, chart);
350 return HTTP_RESP_OK;
351 }
@@ -388,7 +388,7 @@ inline int web_client_api_request_single_chart(RRDHOST *host, struct web_client
388 goto cleanup;
389 }
390
391 - w->response.data->contenttype = CT_APPLICATION_JSON;
391 + w->response.data->content_type = CT_APPLICATION_JSON;
392 st->last_accessed_time_s = now_realtime_sec();
393 callback(st, w->response.data);
394 return HTTP_RESP_OK;
@@ -486,7 +486,7 @@ static int web_client_api_request_v1_context(RRDHOST *host, struct web_client *w
486 buffer_free(dimensions);
487 }
488
489 - w->response.data->contenttype = CT_APPLICATION_JSON;
489 + w->response.data->content_type = CT_APPLICATION_JSON;
490 int ret = rrdcontext_to_json(host, w->response.data, after, before, options, context, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
491
492 simple_pattern_free(chart_label_key_pattern);
@@ -542,7 +542,7 @@ static int web_client_api_request_v1_contexts(RRDHOST *host, struct web_client *
542 buffer_free(dimensions);
543 }
544
545 - w->response.data->contenttype = CT_APPLICATION_JSON;
545 + w->response.data->content_type = CT_APPLICATION_JSON;
546 int ret = rrdcontexts_to_json(host, w->response.data, after, before, options, chart_label_key_pattern, chart_labels_filter_pattern, chart_dimensions_pattern);
547
548 simple_pattern_free(chart_label_key_pattern);
@@ -556,7 +556,7 @@ inline int web_client_api_request_v1_charts(RRDHOST *host, struct web_client *w,
556 (void)url;
557
558 buffer_flush(w->response.data);
559 - w->response.data->contenttype = CT_APPLICATION_JSON;
559 + w->response.data->content_type = CT_APPLICATION_JSON;
560 charts2json(host, w->response.data, 0, 0);
561 return HTTP_RESP_OK;
562 }
@@ -604,7 +604,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
604 char *chart_labels_filter = NULL;
605 char *group_options = NULL;
606 size_t tier = 0;
607 - RRDR_GROUPING group = RRDR_GROUPING_AVERAGE;
607 + RRDR_TIME_GROUPING group = RRDR_GROUPING_AVERAGE;
608 DATASOURCE_FORMAT format = DATASOURCE_JSON;
609 RRDR_OPTIONS options = 0;
610
@@ -638,7 +638,7 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
638 else if(!strcmp(name, "gtime")) group_time_str = value;
639 else if(!strcmp(name, "group_options")) group_options = value;
640 else if(!strcmp(name, "group")) {
641 - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
641 + group = time_grouping_parse(value, RRDR_GROUPING_AVERAGE);
642 }
643 else if(!strcmp(name, "format")) {
644 format = web_client_api_request_v1_data_format(value);
@@ -734,8 +734,8 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
734 .points = points,
735 .format = format,
736 .options = options,
737 - .group_method = group,
738 - .group_options = group_options,
737 + .time_group_method = group,
738 + .time_group_options = group_options,
739 .resampling_time = group_time,
740 .tier = tier,
741 .chart_label_key = chart_label_key,
@@ -1014,7 +1014,9 @@ inline int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *
1014 }
1015
1016 static inline void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST *host, BUFFER *wb) {
1017 - int alarm_normal = 0, alarm_warn = 0, alarm_crit = 0;
1017 + buffer_json_member_add_object(wb, "alarms");
1018 +
1019 + size_t normal = 0, warning = 0, critical = 0;
1020 RRDCALC *rc;
1021 foreach_rrdcalc_in_rrdhost_read(host, rc) {
1022 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
@@ -1022,274 +1024,204 @@ static inline void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST
1024
1025 switch(rc->status) {
1026 case RRDCALC_STATUS_WARNING:
1025 - alarm_warn++;
1027 + warning++;
1028 break;
1029 case RRDCALC_STATUS_CRITICAL:
1028 - alarm_crit++;
1030 + critical++;
1031 break;
1032 default:
1031 - alarm_normal++;
1033 + normal++;
1034 }
1035 }
1036 foreach_rrdcalc_in_rrdhost_done(rc);
1035 - buffer_sprintf(wb, "\t\t\"normal\": %d,\n", alarm_normal);
1036 - buffer_sprintf(wb, "\t\t\"warning\": %d,\n", alarm_warn);
1037 - buffer_sprintf(wb, "\t\t\"critical\": %d\n", alarm_crit);
1037 +
1038 + buffer_json_member_add_uint64(wb, "normal", normal);
1039 + buffer_json_member_add_uint64(wb, "warning", warning);
1040 + buffer_json_member_add_uint64(wb, "critical", critical);
1041 +
1042 + buffer_json_object_close(wb);
1043 }
1044
1045 static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
1046 RRDHOST *host;
1042 - int count = 0;
1047
1044 - buffer_strcat(wb, "\t\"mirrored_hosts\": [\n");
1048 rrd_rdlock();
1046 - rrdhost_foreach_read(host) {
1047 - if (count > 0)
1048 - buffer_strcat(wb, ",\n");
1049
1050 - buffer_sprintf(wb, "\t\t\"%s\"", rrdhost_hostname(host));
1051 - count++;
1052 - }
1053 -
1054 - buffer_strcat(wb, "\n\t],\n\t\"mirrored_hosts_status\": [\n");
1055 - count = 0;
1050 + buffer_json_member_add_array(wb, "mirrored_hosts");
1051 rrdhost_foreach_read(host)
1057 - {
1058 - if (count > 0)
1059 - buffer_strcat(wb, ",\n");
1052 + buffer_json_add_array_item_string(wb, rrdhost_hostname(host));
1053 + buffer_json_array_close(wb);
1054
1061 - buffer_sprintf(
1062 - wb, "\t\t{ \"guid\": \"%s\", \"hostname\": \"%s\", \"reachable\": %s, \"hops\": %d"
1063 - , host->machine_guid
1064 - , rrdhost_hostname(host)
1065 - , (host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)) ? "true" : "false"
1066 - , host->system_info ? host->system_info->hops : (host == localhost) ? 0 : 1
1067 - );
1055 + buffer_json_member_add_array(wb, "mirrored_hosts_status");
1056 + rrdhost_foreach_read(host) {
1057 + buffer_json_add_array_item_object(wb);
1058 +
1059 + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(host));
1060 + buffer_json_member_add_uint64(wb, "hops", host->system_info ? host->system_info->hops : (host == localhost) ? 0 : 1);
1061 + buffer_json_member_add_boolean(wb, "reachable", (host == localhost || !rrdhost_flag_check(host, RRDHOST_FLAG_ORPHAN)));
1062
1063 + buffer_json_member_add_string(wb, "guid", host->machine_guid);
1064 + buffer_json_member_add_uuid(wb, "node_id", host->node_id);
1065 rrdhost_aclk_state_lock(host);
1070 - if (host->aclk_state.claimed_id)
1071 - buffer_sprintf(wb, ", \"claim_id\": \"%s\"", host->aclk_state.claimed_id);
1072 - else
1073 - buffer_strcat(wb, ", \"claim_id\": null");
1066 + buffer_json_member_add_string(wb, "claim_id", host->aclk_state.claimed_id);
1067 rrdhost_aclk_state_unlock(host);
1068
1076 - if (host->node_id) {
1077 - char node_id_str[GUID_LEN + 1];
1078 - uuid_unparse_lower(*host->node_id, node_id_str);
1079 - buffer_sprintf(wb, ", \"node_id\": \"%s\" }", node_id_str);
1080 - } else
1081 - buffer_strcat(wb, ", \"node_id\": null }");
1082 -
1083 - count++;
1069 + buffer_json_object_close(wb);
1070 }
1071 + buffer_json_array_close(wb);
1072 +
1073 rrd_unlock();
1074 +}
1075
1087 - buffer_strcat(wb, "\n\t],\n");
1076 +static inline void host_labels2json(RRDHOST *host, BUFFER *wb) {
1077 + buffer_json_member_add_object(wb, "host_labels");
1078 + rrdlabels_to_buffer_json_members(host->rrdlabels, wb);
1079 + buffer_json_object_close(wb);
1080 }
1081
1090 -inline void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation) {
1091 - char tabs[11];
1082 +static void host_collectors(RRDHOST *host, BUFFER *wb) {
1083 + buffer_json_member_add_array(wb, "collectors");
1084 +
1085 + DICTIONARY *dict = dictionary_create(DICT_OPTION_SINGLE_THREADED|DICT_OPTION_DONT_OVERWRITE_VALUE);
1086 + RRDSET *st;
1087 + char name[500];
1088
1093 - if (indentation > 10)
1094 - indentation = 10;
1089 + time_t now = now_realtime_sec();
1090
1096 - tabs[0] = '\0';
1097 - while (indentation) {
1098 - strcat(tabs, "\t");
1099 - indentation--;
1091 + rrdset_foreach_read(st, host) {
1092 + if (!rrdset_is_available_for_viewers(st))
1093 + continue;
1094 +
1095 + sprintf(name, "%s:%s", rrdset_plugin_name(st), rrdset_module_name(st));
1096 +
1097 + bool old = 0;
1098 + bool *set = dictionary_set(dict, name, &old, sizeof(bool));
1099 + if(!*set) {
1100 + *set = true;
1101 + st->last_accessed_time_s = now;
1102 + buffer_json_add_array_item_object(wb);
1103 + buffer_json_member_add_string(wb, "plugin", rrdset_plugin_name(st));
1104 + buffer_json_member_add_string(wb, "module", rrdset_module_name(st));
1105 + buffer_json_object_close(wb);
1106 + }
1107 }
1108 + rrdset_foreach_done(st);
1109 + dictionary_destroy(dict);
1110
1102 - rrdlabels_to_buffer(host->rrdlabels, wb, tabs, ":", "\"", ",\n", NULL, NULL, NULL, NULL);
1103 - buffer_strcat(wb, "\n");
1111 + buffer_json_array_close(wb);
1112 }
1113
1114 extern int aclk_connected;
1107 -inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
1108 -{
1109 - buffer_strcat(wb, "{\n");
1110 - buffer_sprintf(wb, "\t\"version\": \"%s\",\n", rrdhost_program_version(host));
1111 - buffer_sprintf(wb, "\t\"uid\": \"%s\",\n", host->machine_guid);
1115 +inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb) {
1116 + buffer_json_initialize(wb, "\"", "\"", 0, true);
1117
1118 + buffer_json_member_add_string(wb, "version", rrdhost_program_version(host));
1119 + buffer_json_member_add_string(wb, "uid", host->machine_guid);
1120 +
1121 + buffer_json_member_add_uint64(wb, "hosts-available", rrdhost_hosts_available());
1122 web_client_api_request_v1_info_mirrored_hosts(wb);
1123
1115 - buffer_strcat(wb, "\t\"alarms\": {\n");
1124 web_client_api_request_v1_info_summary_alarm_statuses(host, wb);
1117 - buffer_strcat(wb, "\t},\n");
1118 -
1119 - buffer_sprintf(wb, "\t\"os_name\": \"%s\",\n", (host->system_info->host_os_name) ? host->system_info->host_os_name : "");
1120 - buffer_sprintf(wb, "\t\"os_id\": \"%s\",\n", (host->system_info->host_os_id) ? host->system_info->host_os_id : "");
1121 - buffer_sprintf(wb, "\t\"os_id_like\": \"%s\",\n", (host->system_info->host_os_id_like) ? host->system_info->host_os_id_like : "");
1122 - buffer_sprintf(wb, "\t\"os_version\": \"%s\",\n", (host->system_info->host_os_version) ? host->system_info->host_os_version : "");
1123 - buffer_sprintf(wb, "\t\"os_version_id\": \"%s\",\n", (host->system_info->host_os_version_id) ? host->system_info->host_os_version_id : "");
1124 - buffer_sprintf(wb, "\t\"os_detection\": \"%s\",\n", (host->system_info->host_os_detection) ? host->system_info->host_os_detection : "");
1125 - buffer_sprintf(wb, "\t\"cores_total\": \"%s\",\n", (host->system_info->host_cores) ? host->system_info->host_cores : "");
1126 - buffer_sprintf(wb, "\t\"total_disk_space\": \"%s\",\n", (host->system_info->host_disk_space) ? host->system_info->host_disk_space : "");
1127 - buffer_sprintf(wb, "\t\"cpu_freq\": \"%s\",\n", (host->system_info->host_cpu_freq) ? host->system_info->host_cpu_freq : "");
1128 - buffer_sprintf(wb, "\t\"ram_total\": \"%s\",\n", (host->system_info->host_ram_total) ? host->system_info->host_ram_total : "");
1129 -
1130 - if (host->system_info->container_os_name)
1131 - buffer_sprintf(wb, "\t\"container_os_name\": \"%s\",\n", host->system_info->container_os_name);
1132 - if (host->system_info->container_os_id)
1133 - buffer_sprintf(wb, "\t\"container_os_id\": \"%s\",\n", host->system_info->container_os_id);
1134 - if (host->system_info->container_os_id_like)
1135 - buffer_sprintf(wb, "\t\"container_os_id_like\": \"%s\",\n", host->system_info->container_os_id_like);
1136 - if (host->system_info->container_os_version)
1137 - buffer_sprintf(wb, "\t\"container_os_version\": \"%s\",\n", host->system_info->container_os_version);
1138 - if (host->system_info->container_os_version_id)
1139 - buffer_sprintf(wb, "\t\"container_os_version_id\": \"%s\",\n", host->system_info->container_os_version_id);
1140 - if (host->system_info->container_os_detection)
1141 - buffer_sprintf(wb, "\t\"container_os_detection\": \"%s\",\n", host->system_info->container_os_detection);
1142 - if (host->system_info->is_k8s_node)
1143 - buffer_sprintf(wb, "\t\"is_k8s_node\": \"%s\",\n", host->system_info->is_k8s_node);
1144 -
1145 - buffer_sprintf(wb, "\t\"kernel_name\": \"%s\",\n", (host->system_info->kernel_name) ? host->system_info->kernel_name : "");
1146 - buffer_sprintf(wb, "\t\"kernel_version\": \"%s\",\n", (host->system_info->kernel_version) ? host->system_info->kernel_version : "");
1147 - buffer_sprintf(wb, "\t\"architecture\": \"%s\",\n", (host->system_info->architecture) ? host->system_info->architecture : "");
1148 - buffer_sprintf(wb, "\t\"virtualization\": \"%s\",\n", (host->system_info->virtualization) ? host->system_info->virtualization : "");
1149 - buffer_sprintf(wb, "\t\"virt_detection\": \"%s\",\n", (host->system_info->virt_detection) ? host->system_info->virt_detection : "");
1150 - buffer_sprintf(wb, "\t\"container\": \"%s\",\n", (host->system_info->container) ? host->system_info->container : "");
1151 - buffer_sprintf(wb, "\t\"container_detection\": \"%s\",\n", (host->system_info->container_detection) ? host->system_info->container_detection : "");
1152 -
1153 - if (host->system_info->cloud_provider_type)
1154 - buffer_sprintf(wb, "\t\"cloud_provider_type\": \"%s\",\n", host->system_info->cloud_provider_type);
1155 - if (host->system_info->cloud_instance_type)
1156 - buffer_sprintf(wb, "\t\"cloud_instance_type\": \"%s\",\n", host->system_info->cloud_instance_type);
1157 - if (host->system_info->cloud_instance_region)
1158 - buffer_sprintf(wb, "\t\"cloud_instance_region\": \"%s\",\n", host->system_info->cloud_instance_region);
1159 -
1160 - buffer_strcat(wb, "\t\"host_labels\": {\n");
1161 - host_labels2json(host, wb, 2);
1162 - buffer_strcat(wb, "\t},\n");
1163 -
1164 - buffer_strcat(wb, "\t\"functions\": {\n");
1165 - host_functions2json(host, wb, 2, "\"", "\"");
1166 - buffer_strcat(wb, "\t},\n");
1167 -
1168 - buffer_strcat(wb, "\t\"collectors\": [");
1169 - chartcollectors2json(host, wb);
1170 - buffer_strcat(wb, "\n\t],\n");
1125 +
1126 + buffer_json_member_add_string_or_empty(wb, "os_name", host->system_info->host_os_name);
1127 + buffer_json_member_add_string_or_empty(wb, "os_id", host->system_info->host_os_id);
1128 + buffer_json_member_add_string_or_empty(wb, "os_id_like", host->system_info->host_os_id_like);
1129 + buffer_json_member_add_string_or_empty(wb, "os_version", host->system_info->host_os_version);
1130 + buffer_json_member_add_string_or_empty(wb, "os_version_id", host->system_info->host_os_version_id);
1131 + buffer_json_member_add_string_or_empty(wb, "os_detection", host->system_info->host_os_detection);
1132 + buffer_json_member_add_string_or_empty(wb, "cores_total", host->system_info->host_cores);
1133 + buffer_json_member_add_string_or_empty(wb, "total_disk_space", host->system_info->host_disk_space);
1134 + buffer_json_member_add_string_or_empty(wb, "cpu_freq", host->system_info->host_cpu_freq);
1135 + buffer_json_member_add_string_or_empty(wb, "ram_total", host->system_info->host_ram_total);
1136 +
1137 + buffer_json_member_add_string_or_omit(wb, "container_os_name", host->system_info->container_os_name);
1138 + buffer_json_member_add_string_or_omit(wb, "container_os_id", host->system_info->container_os_id);
1139 + buffer_json_member_add_string_or_omit(wb, "container_os_id_like", host->system_info->container_os_id_like);
1140 + buffer_json_member_add_string_or_omit(wb, "container_os_version", host->system_info->container_os_version);
1141 + buffer_json_member_add_string_or_omit(wb, "container_os_version_id", host->system_info->container_os_version_id);
1142 + buffer_json_member_add_string_or_omit(wb, "container_os_detection", host->system_info->container_os_detection);
1143 + buffer_json_member_add_string_or_omit(wb, "is_k8s_node", host->system_info->is_k8s_node);
1144 +
1145 + buffer_json_member_add_string_or_empty(wb, "kernel_name", host->system_info->kernel_name);
1146 + buffer_json_member_add_string_or_empty(wb, "kernel_version", host->system_info->kernel_version);
1147 + buffer_json_member_add_string_or_empty(wb, "architecture", host->system_info->architecture);
1148 + buffer_json_member_add_string_or_empty(wb, "virtualization", host->system_info->virtualization);
1149 + buffer_json_member_add_string_or_empty(wb, "virt_detection", host->system_info->virt_detection);
1150 + buffer_json_member_add_string_or_empty(wb, "container", host->system_info->container);
1151 + buffer_json_member_add_string_or_empty(wb, "container_detection", host->system_info->container_detection);
1152 +
1153 + buffer_json_member_add_string_or_omit(wb, "cloud_provider_type", host->system_info->cloud_provider_type);
1154 + buffer_json_member_add_string_or_omit(wb, "cloud_instance_type", host->system_info->cloud_instance_type);
1155 + buffer_json_member_add_string_or_omit(wb, "cloud_instance_region", host->system_info->cloud_instance_region);
1156 +
1157 + host_labels2json(host, wb);
1158 + host_functions2json(host, wb);
1159 + host_collectors(host, wb);
1160
1161 #ifdef DISABLE_CLOUD
1173 - buffer_strcat(wb, "\t\"cloud-enabled\": false,\n");
1162 + buffer_json_member_add_boolean(wb, "cloud-enabled", false);
1163 #else
1175 - buffer_sprintf(wb, "\t\"cloud-enabled\": %s,\n",
1176 - appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", 1) ? "true" : "false");
1164 + buffer_json_member_add_boolean(wb, "cloud-enabled",
1165 + appconfig_get_boolean(&cloud_config, CONFIG_SECTION_GLOBAL, "enabled", true));
1166 #endif
1167
1168 #ifdef ENABLE_ACLK
1180 - buffer_strcat(wb, "\t\"cloud-available\": true,\n");
1169 + buffer_json_member_add_boolean(wb, "cloud-available", true);
1170 #else
1182 - buffer_strcat(wb, "\t\"cloud-available\": false,\n");
1171 + buffer_json_member_add_boolean(wb, "cloud-available", false);
1172 #endif
1173 +
1174 char *agent_id = get_agent_claimid();
1185 - if (agent_id == NULL)
1186 - buffer_strcat(wb, "\t\"agent-claimed\": false,\n");
1187 - else {
1188 - buffer_strcat(wb, "\t\"agent-claimed\": true,\n");
1189 - freez(agent_id);
1190 - }
1175 + buffer_json_member_add_boolean(wb, "agent-claimed", agent_id != NULL);
1176 + freez(agent_id);
1177 +
1178 #ifdef ENABLE_ACLK
1192 - if (aclk_connected) {
1193 - buffer_strcat(wb, "\t\"aclk-available\": true,\n");
1194 - }
1195 - else
1179 + buffer_json_member_add_boolean(wb, "aclk-available", aclk_connected);
1180 +#else
1181 + buffer_json_member_add_boolean(wb, "aclk-available", false);
1182 #endif
1197 - buffer_strcat(wb, "\t\"aclk-available\": false,\n"); // Intentionally valid with/without #ifdef above
1198 -
1199 - buffer_strcat(wb, "\t\"memory-mode\": ");
1200 - analytics_get_data(analytics_data.netdata_config_memory_mode, wb);
1201 - buffer_strcat(wb, ",\n");
1183
1203 - buffer_strcat(wb, "\t\"multidb-disk-quota\": ");
1204 - analytics_get_data(analytics_data.netdata_config_multidb_disk_quota, wb);
1205 - buffer_strcat(wb, ",\n");
1206 -
1207 - buffer_strcat(wb, "\t\"page-cache-size\": ");
1208 - analytics_get_data(analytics_data.netdata_config_page_cache_size, wb);
1209 - buffer_strcat(wb, ",\n");
1210 -
1211 - buffer_strcat(wb, "\t\"stream-enabled\": ");
1212 - analytics_get_data(analytics_data.netdata_config_stream_enabled, wb);
1213 - buffer_strcat(wb, ",\n");
1184 + buffer_json_member_add_string(wb, "memory-mode", rrd_memory_mode_name(host->rrd_memory_mode));
1185 + buffer_json_member_add_uint64(wb, "multidb-disk-quota", default_multidb_disk_quota_mb);
1186 + buffer_json_member_add_uint64(wb, "page-cache-size", default_rrdeng_page_cache_mb);
1187 + buffer_json_member_add_boolean(wb, "web-enabled", web_server_mode != WEB_SERVER_MODE_NONE);
1188 + buffer_json_member_add_boolean(wb, "stream-enabled", default_rrdpush_enabled);
1189
1190 #ifdef ENABLE_COMPRESSION
1216 - if(host->sender){
1217 - buffer_strcat(wb, "\t\"stream-compression\": ");
1218 - buffer_strcat(wb, stream_has_capability(host->sender, STREAM_CAP_COMPRESSION) ? "true" : "false");
1219 - buffer_strcat(wb, ",\n");
1220 - }else{
1221 - buffer_strcat(wb, "\t\"stream-compression\": null,\n");
1222 - }
1191 + buffer_json_member_add_boolean(wb, "stream-compression",
1192 + host->sender && stream_has_capability(host->sender, STREAM_CAP_COMPRESSION));
1193 #else
1224 - buffer_strcat(wb, "\t\"stream-compression\": null,\n");
1225 -#endif //ENABLE_COMPRESSION
1226 -
1227 - buffer_strcat(wb, "\t\"hosts-available\": ");
1228 - analytics_get_data(analytics_data.netdata_config_hosts_available, wb);
1229 - buffer_strcat(wb, ",\n");
1230 -
1231 - buffer_strcat(wb, "\t\"https-enabled\": ");
1232 - analytics_get_data(analytics_data.netdata_config_https_enabled, wb);
1233 - buffer_strcat(wb, ",\n");
1234 -
1235 - buffer_strcat(wb, "\t\"buildinfo\": ");
1236 - analytics_get_data(analytics_data.netdata_buildinfo, wb);
1237 - buffer_strcat(wb, ",\n");
1194 + buffer_json_member_add_boolean(wb, "stream-compression", false);
1195 +#endif //ENABLE_COMPRESSION
1196
1239 - buffer_strcat(wb, "\t\"release-channel\": ");
1240 - analytics_get_data(analytics_data.netdata_config_release_channel, wb);
1241 - buffer_strcat(wb, ",\n");
1242 -
1243 - buffer_strcat(wb, "\t\"web-enabled\": ");
1244 - analytics_get_data(analytics_data.netdata_config_web_enabled, wb);
1245 - buffer_strcat(wb, ",\n");
1246 -
1247 - buffer_strcat(wb, "\t\"notification-methods\": ");
1248 - analytics_get_data(analytics_data.netdata_notification_methods, wb);
1249 - buffer_strcat(wb, ",\n");
1250 -
1251 - buffer_strcat(wb, "\t\"exporting-enabled\": ");
1252 - analytics_get_data(analytics_data.netdata_config_exporting_enabled, wb);
1253 - buffer_strcat(wb, ",\n");
1254 -
1255 - buffer_strcat(wb, "\t\"exporting-connectors\": ");
1256 - analytics_get_data(analytics_data.netdata_exporting_connectors, wb);
1257 - buffer_strcat(wb, ",\n");
1258 -
1259 - buffer_strcat(wb, "\t\"allmetrics-prometheus-used\": ");
1260 - analytics_get_data(analytics_data.netdata_allmetrics_prometheus_used, wb);
1261 - buffer_strcat(wb, ",\n");
1262 -
1263 - buffer_strcat(wb, "\t\"allmetrics-shell-used\": ");
1264 - analytics_get_data(analytics_data.netdata_allmetrics_shell_used, wb);
1265 - buffer_strcat(wb, ",\n");
1197 +#ifdef ENABLE_HTTPS
1198 + buffer_json_member_add_boolean(wb, "https-enabled", true);
1199 +#else
1200 + buffer_json_member_add_boolean(wb, "https-enabled", false);
1201 +#endif
1202
1267 - buffer_strcat(wb, "\t\"allmetrics-json-used\": ");
1268 - analytics_get_data(analytics_data.netdata_allmetrics_json_used, wb);
1269 - buffer_strcat(wb, ",\n");
1203 + buffer_json_member_add_quoted_string(wb, "buildinfo", analytics_data.netdata_buildinfo);
1204 + buffer_json_member_add_quoted_string(wb, "release-channel", analytics_data.netdata_config_release_channel);
1205 + buffer_json_member_add_quoted_string(wb, "notification-methods", analytics_data.netdata_notification_methods);
1206
1271 - buffer_strcat(wb, "\t\"dashboard-used\": ");
1272 - analytics_get_data(analytics_data.netdata_dashboard_used, wb);
1273 - buffer_strcat(wb, ",\n");
1207 + buffer_json_member_add_boolean(wb, "exporting-enabled", analytics_data.exporting_enabled);
1208 + buffer_json_member_add_quoted_string(wb, "exporting-connectors", analytics_data.netdata_exporting_connectors);
1209
1275 - buffer_strcat(wb, "\t\"charts-count\": ");
1276 - analytics_get_data(analytics_data.netdata_charts_count, wb);
1277 - buffer_strcat(wb, ",\n");
1210 + buffer_json_member_add_uint64(wb, "allmetrics-prometheus-used", analytics_data.prometheus_hits);
1211 + buffer_json_member_add_uint64(wb, "allmetrics-shell-used", analytics_data.shell_hits);
1212 + buffer_json_member_add_uint64(wb, "allmetrics-json-used", analytics_data.json_hits);
1213 + buffer_json_member_add_uint64(wb, "dashboard-used", analytics_data.dashboard_hits);
1214
1279 - buffer_strcat(wb, "\t\"metrics-count\": ");
1280 - analytics_get_data(analytics_data.netdata_metrics_count, wb);
1215 + buffer_json_member_add_uint64(wb, "charts-count", analytics_data.charts_count);
1216 + buffer_json_member_add_uint64(wb, "metrics-count", analytics_data.metrics_count);
1217
1218 #if defined(ENABLE_ML)
1283 - buffer_strcat(wb, ",\n");
1284 - char *ml_info = ml_get_host_info(host);
1285 -
1286 - buffer_strcat(wb, "\t\"ml-info\": ");
1287 - buffer_strcat(wb, ml_info);
1288 -
1289 - freez(ml_info);
1219 + buffer_json_member_add_object(wb, "ml-info");
1220 + ml_get_host_info(host, wb);
1221 + buffer_json_object_close(wb);
1222 #endif
1223
1292 - buffer_strcat(wb, "\n}");
1224 + buffer_json_finalize(wb);
1225 return 0;
1226 }
1227
@@ -1306,7 +1238,7 @@ int web_client_api_request_v1_ml_info(RRDHOST *host, struct web_client *w, char
1238
1239 BUFFER *wb = w->response.data;
1240 buffer_flush(wb);
1309 - wb->contenttype = CT_APPLICATION_JSON;
1241 + wb->content_type = CT_APPLICATION_JSON;
1242 buffer_strcat(wb, s);
1243 buffer_no_cacheable(wb);
1244
@@ -1326,7 +1258,7 @@ int web_client_api_request_v1_ml_models(RRDHOST *host, struct web_client *w, cha
1258
1259 BUFFER *wb = w->response.data;
1260 buffer_flush(wb);
1329 - wb->contenttype = CT_APPLICATION_JSON;
1261 + wb->content_type = CT_APPLICATION_JSON;
1262 buffer_strcat(wb, s);
1263 buffer_no_cacheable(wb);
1264
@@ -1340,7 +1272,7 @@ inline int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, c
1272 if (!netdata_ready) return HTTP_RESP_BACKEND_FETCH_FAILED;
1273 BUFFER *wb = w->response.data;
1274 buffer_flush(wb);
1343 - wb->contenttype = CT_APPLICATION_JSON;
1275 + wb->content_type = CT_APPLICATION_JSON;
1276
1277 web_client_api_request_v1_info_fill_buffer(host, wb);
1278
@@ -1360,7 +1292,7 @@ static int web_client_api_request_v1_aclk_state(RRDHOST *host, struct web_client
1292 buffer_strcat(wb, str);
1293 freez(str);
1294
1363 - wb->contenttype = CT_APPLICATION_JSON;
1295 + wb->content_type = CT_APPLICATION_JSON;
1296 buffer_no_cacheable(wb);
1297 return HTTP_RESP_OK;
1298 }
@@ -1372,7 +1304,7 @@ static int web_client_api_request_v1_weights_internal(RRDHOST *host, struct web_
1304 long long baseline_after = 0, baseline_before = 0, after = 0, before = 0, points = 0;
1305 RRDR_OPTIONS options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NONZERO | RRDR_OPTION_NULL2ZERO;
1306 int options_count = 0;
1375 - RRDR_GROUPING group = RRDR_GROUPING_AVERAGE;
1307 + RRDR_TIME_GROUPING group = RRDR_GROUPING_AVERAGE;
1308 int timeout = 0;
1309 size_t tier = 0;
1310 const char *group_options = NULL, *contexts_str = NULL;
@@ -1407,7 +1339,7 @@ static int web_client_api_request_v1_weights_internal(RRDHOST *host, struct web_
1339 timeout = (int) strtoul(value, NULL, 0);
1340
1341 else if(!strcmp(name, "group"))
1410 - group = web_client_api_request_v1_data_group(value, RRDR_GROUPING_AVERAGE);
1342 + group = time_grouping_parse(value, RRDR_GROUPING_AVERAGE);
1343
1344 else if(!strcmp(name, "options")) {
1345 if(!options_count) options = RRDR_OPTION_NOT_ALIGNED | RRDR_OPTION_NULL2ZERO;
@@ -1432,7 +1364,7 @@ static int web_client_api_request_v1_weights_internal(RRDHOST *host, struct web_
1364
1365 BUFFER *wb = w->response.data;
1366 buffer_flush(wb);
1435 - wb->contenttype = CT_APPLICATION_JSON;
1367 + wb->content_type = CT_APPLICATION_JSON;
1368
1369 SIMPLE_PATTERN *contexts = (contexts_str) ? simple_pattern_create(contexts_str, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT) : NULL;
1370
@@ -1475,7 +1407,7 @@ int web_client_api_request_v1_function(RRDHOST *host, struct web_client *w, char
1407
1408 BUFFER *wb = w->response.data;
1409 buffer_flush(wb);
1478 - wb->contenttype = CT_APPLICATION_JSON;
1410 + wb->content_type = CT_APPLICATION_JSON;
1411 buffer_no_cacheable(wb);
1412
1413 return rrd_call_function_and_wait(host, wb, timeout, function);
@@ -1487,12 +1419,12 @@ int web_client_api_request_v1_functions(RRDHOST *host, struct web_client *w, cha
1419
1420 BUFFER *wb = w->response.data;
1421 buffer_flush(wb);
1490 - wb->contenttype = CT_APPLICATION_JSON;
1422 + wb->content_type = CT_APPLICATION_JSON;
1423 buffer_no_cacheable(wb);
1424
1493 - buffer_strcat(wb, "{\n");
1494 - host_functions2json(host, wb, 1, "\"", "\"");
1495 - buffer_strcat(wb, "}");
1425 + buffer_json_initialize(wb, "\"", "\"", 0, true);
1426 + host_functions2json(host, wb);
1427 + buffer_json_finalize(wb);
1428
1429 return HTTP_RESP_OK;
1430 }
@@ -1576,7 +1508,7 @@ int web_client_api_request_v1_dbengine_stats(RRDHOST *host __maybe_unused, struc
1508 return HTTP_RESP_NOT_FOUND;
1509 }
1510
1579 - wb->contenttype = CT_APPLICATION_JSON;
1511 + wb->content_type = CT_APPLICATION_JSON;
1512 buffer_no_cacheable(wb);
1513 buffer_strcat(wb, "{");
1514 for(size_t tier = 0; tier < storage_tiers ;tier++) {
web/api/web_api_v1.h
+1 -2
@@ -10,7 +10,7 @@
10 #include "web/api/queries/weights.h"
11
12 RRDR_OPTIONS web_client_api_request_v1_data_options(char *o);
13 -void web_client_api_request_v1_data_options_to_buffer(BUFFER *wb, RRDR_OPTIONS options);
13 +void web_client_api_request_v1_data_options_to_buffer_json_array(BUFFER *wb, const char *key, RRDR_OPTIONS options);
14 void web_client_api_request_v1_data_options_to_string(char *buf, size_t size, RRDR_OPTIONS options);
15
16 uint32_t web_client_api_request_v1_data_format(char *name);
@@ -29,7 +29,6 @@ int web_client_api_request_v1_registry(RRDHOST *host, struct web_client *w, char
29 int web_client_api_request_v1_info(RRDHOST *host, struct web_client *w, char *url);
30 int web_client_api_request_v1(RRDHOST *host, struct web_client *w, char *url);
31 int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb);
32 -void host_labels2json(RRDHOST *host, BUFFER *wb, size_t indentation);
32
33 void web_client_api_v1_init(void);
34 void web_client_api_v1_management_init(void);
web/server/web_client.c
+19 -19
@@ -13,7 +13,7 @@ int web_enable_gzip = 1, web_gzip_level = 3, web_gzip_strategy = Z_DEFAULT_STRAT
13 #endif /* NETDATA_WITH_ZLIB */
14
15 inline int web_client_permission_denied(struct web_client *w) {
16 - w->response.data->contenttype = CT_TEXT_PLAIN;
16 + w->response.data->content_type = CT_TEXT_PLAIN;
17 buffer_flush(w->response.data);
18 buffer_strcat(w->response.data, "You are not allowed to access this resource.");
19 w->response.code = HTTP_RESP_FORBIDDEN;
@@ -273,7 +273,7 @@ static inline uint8_t contenttype_for_filename(const char *filename) {
273 }
274
275 static inline int access_to_file_is_not_permitted(struct web_client *w, const char *filename) {
276 - w->response.data->contenttype = CT_TEXT_HTML;
276 + w->response.data->content_type = CT_TEXT_HTML;
277 buffer_strcat(w->response.data, "Access to file is not permitted: ");
278 buffer_strcat_htmlescape(w->response.data, filename);
279 return HTTP_RESP_FORBIDDEN;
@@ -295,7 +295,7 @@ int mysendfile(struct web_client *w, char *filename) {
295 for(s = filename; *s ;s++) {
296 if( !isalnum(*s) && *s != '/' && *s != '.' && *s != '-' && *s != '_') {
297 debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
298 - w->response.data->contenttype = CT_TEXT_HTML;
298 + w->response.data->content_type = CT_TEXT_HTML;
299 buffer_sprintf(w->response.data, "Filename contains invalid characters: ");
300 buffer_strcat_htmlescape(w->response.data, filename);
301 return HTTP_RESP_BAD_REQUEST;
@@ -305,7 +305,7 @@ int mysendfile(struct web_client *w, char *filename) {
305 // if the filename contains a double dot refuse to serve it
306 if(strstr(filename, "..") != 0) {
307 debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not acceptable.", w->id, filename);
308 - w->response.data->contenttype = CT_TEXT_HTML;
308 + w->response.data->content_type = CT_TEXT_HTML;
309 buffer_strcat(w->response.data, "Relative filenames are not supported: ");
310 buffer_strcat_htmlescape(w->response.data, filename);
311 return HTTP_RESP_BAD_REQUEST;
@@ -321,7 +321,7 @@ int mysendfile(struct web_client *w, char *filename) {
321 // check if the file exists
322 if (lstat(webfilename, &statbuf) != 0) {
323 debug(D_WEB_CLIENT_ACCESS, "%llu: File '%s' is not found.", w->id, webfilename);
324 - w->response.data->contenttype = CT_TEXT_HTML;
324 + w->response.data->content_type = CT_TEXT_HTML;
325 buffer_strcat(w->response.data, "File does not exist, or is not accessible: ");
326 buffer_strcat_htmlescape(w->response.data, webfilename);
327 return HTTP_RESP_NOT_FOUND;
@@ -347,7 +347,7 @@ int mysendfile(struct web_client *w, char *filename) {
347
348 if(errno == EBUSY || errno == EAGAIN) {
349 error("%llu: File '%s' is busy, sending 307 Moved Temporarily to force retry.", w->id, webfilename);
350 - w->response.data->contenttype = CT_TEXT_HTML;
350 + w->response.data->content_type = CT_TEXT_HTML;
351 buffer_sprintf(w->response.header, "Location: /%s\r\n", filename);
352 buffer_strcat(w->response.data, "File is currently busy, please try again later: ");
353 buffer_strcat_htmlescape(w->response.data, webfilename);
@@ -355,7 +355,7 @@ int mysendfile(struct web_client *w, char *filename) {
355 }
356 else {
357 error("%llu: Cannot open file '%s'.", w->id, webfilename);
358 - w->response.data->contenttype = CT_TEXT_HTML;
358 + w->response.data->content_type = CT_TEXT_HTML;
359 buffer_strcat(w->response.data, "Cannot open file: ");
360 buffer_strcat_htmlescape(w->response.data, webfilename);
361 return HTTP_RESP_NOT_FOUND;
@@ -364,7 +364,7 @@ int mysendfile(struct web_client *w, char *filename) {
364
365 sock_setnonblock(w->ifd);
366
367 - w->response.data->contenttype = contenttype_for_filename(webfilename);
367 + w->response.data->content_type = contenttype_for_filename(webfilename);
368 debug(D_WEB_CLIENT_ACCESS, "%llu: Sending file '%s' (%"PRId64" bytes, ifd %d, ofd %d).", w->id, webfilename, (int64_t)statbuf.st_size, w->ifd, w->ofd);
369
370 w->mode = WEB_CLIENT_MODE_FILECOPY;
@@ -537,7 +537,7 @@ int web_client_api_request(RRDHOST *host, struct web_client *w, char *url)
537 return web_client_api_request_v1(host, w, url);
538 else {
539 buffer_flush(w->response.data);
540 - w->response.data->contenttype = CT_TEXT_HTML;
540 + w->response.data->content_type = CT_TEXT_HTML;
541 buffer_strcat(w->response.data, "Unsupported API version: ");
542 buffer_strcat_htmlescape(w->response.data, tok);
543 return HTTP_RESP_NOT_FOUND;
@@ -550,8 +550,8 @@ int web_client_api_request(RRDHOST *host, struct web_client *w, char *url)
550 }
551 }
552
553 -const char *web_content_type_to_string(uint8_t contenttype) {
554 - switch(contenttype) {
553 +const char *web_content_type_to_string(HTTP_CONTENT_TYPE content_type) {
554 + switch(content_type) {
555 case CT_TEXT_HTML:
556 return "text/html; charset=utf-8";
557
@@ -1084,7 +1084,7 @@ void web_client_build_http_header(struct web_client *w) {
1084 // prepare the HTTP response header
1085 debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, w->response.code);
1086
1087 - const char *content_type_string = web_content_type_to_string(w->response.data->contenttype);
1087 + const char *content_type_string = web_content_type_to_string(w->response.data->content_type);
1088 const char *code_msg = web_response_code_to_string(w->response.code);
1089
1090 // prepare the last modified and expiration dates
@@ -1309,7 +1309,7 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1309 }
1310
1311 buffer_flush(w->response.data);
1312 - w->response.data->contenttype = CT_TEXT_HTML;
1312 + w->response.data->content_type = CT_TEXT_HTML;
1313 buffer_strcat(w->response.data, "This netdata does not maintain a database for host: ");
1314 buffer_strcat_htmlescape(w->response.data, tok?tok:"");
1315 return HTTP_RESP_NOT_FOUND;
@@ -1357,7 +1357,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1357 return web_client_permission_denied(w);
1358
1359 debug(D_WEB_CLIENT_ACCESS, "%llu: generating netdata.conf ...", w->id);
1360 - w->response.data->contenttype = CT_TEXT_PLAIN;
1360 + w->response.data->content_type = CT_TEXT_PLAIN;
1361 buffer_flush(w->response.data);
1362 config_generate(w->response.data, 0);
1363 return HTTP_RESP_OK;
@@ -1367,7 +1367,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1367 if(unlikely(!web_client_can_access_netdataconf(w)))
1368 return web_client_permission_denied(w);
1369
1370 - w->response.data->contenttype = CT_TEXT_PLAIN;
1370 + w->response.data->content_type = CT_TEXT_PLAIN;
1371 buffer_flush(w->response.data);
1372
1373 if(!netdata_exit)
@@ -1394,7 +1394,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1394 RRDSET *st = rrdset_find_byname(host, tok);
1395 if(!st) st = rrdset_find(host, tok);
1396 if(!st) {
1397 - w->response.data->contenttype = CT_TEXT_HTML;
1397 + w->response.data->content_type = CT_TEXT_HTML;
1398 buffer_strcat(w->response.data, "Chart is not found: ");
1399 buffer_strcat_htmlescape(w->response.data, tok);
1400 debug(D_WEB_CLIENT_ACCESS, "%llu: %s is not found.", w->id, tok);
@@ -1408,7 +1408,7 @@ static inline int web_client_process_url(RRDHOST *host, struct web_client *w, ch
1408 else
1409 rrdset_flag_set(st, RRDSET_FLAG_DEBUG);
1410
1411 - w->response.data->contenttype = CT_TEXT_HTML;
1411 + w->response.data->content_type = CT_TEXT_HTML;
1412 buffer_sprintf(w->response.data, "Chart has now debug %s: ", rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
1413 buffer_strcat_htmlescape(w->response.data, tok);
1414 debug(D_WEB_CLIENT_ACCESS, "%llu: debug for %s is %s.", w->id, tok, rrdset_flag_check(st, RRDSET_FLAG_DEBUG)?"enabled":"disabled");
@@ -1473,7 +1473,7 @@ void web_client_process_request(struct web_client *w) {
1473 break;
1474 }
1475
1476 - w->response.data->contenttype = CT_TEXT_PLAIN;
1476 + w->response.data->content_type = CT_TEXT_PLAIN;
1477 buffer_flush(w->response.data);
1478 buffer_strcat(w->response.data, "OK");
1479 w->response.code = HTTP_RESP_OK;
@@ -1516,7 +1516,7 @@ void web_client_process_request(struct web_client *w) {
1516 case HTTP_VALIDATION_REDIRECT:
1517 {
1518 buffer_flush(w->response.data);
1519 - w->response.data->contenttype = CT_TEXT_HTML;
1519 + w->response.data->content_type = CT_TEXT_HTML;
1520 buffer_strcat(w->response.data,
1521 "<!DOCTYPE html><!-- SPDX-License-Identifier: GPL-3.0-or-later --><html>"
1522 "<body onload=\"window.location.href ='https://'+ window.location.hostname +"