@cryptotaxi247 / netdata-1 / commits / cc6ff3568

POST Functions (#18611)

* fix functions payload parsing * remove raw facets field

Costa Tsaousis committed Sep 24, 2024 at 17:05 UTC cc6ff35685ad66ea6f8ed46446a16c1a6e606198
7 files changed +65 -20
src/collectors/systemd-journal.plugin/systemd-journal.c
+1 -1
@@ -1166,7 +1166,7 @@ void function_systemd_journal(const char *transaction, char *function, usec_t *s
1166 LOGS_QUERY_STATUS tmp_fqs = {
1167 .facets = lqs_facets_create(
1168 LQS_DEFAULT_ITEMS_PER_QUERY,
1169 - FACETS_OPTION_ALL_KEYS_FTS,
1169 + FACETS_OPTION_ALL_KEYS_FTS | FACETS_OPTION_HASH_IDS,
1170 SYSTEMD_ALWAYS_VISIBLE_KEYS,
1171 SYSTEMD_KEYS_INCLUDED_IN_FACETS,
1172 SYSTEMD_KEYS_EXCLUDED_FROM_FACETS,
src/collectors/windows-events.plugin/windows-events.c
+1 -1
@@ -1081,7 +1081,7 @@ void function_windows_events(const char *transaction, char *function, usec_t *st
1081 LOGS_QUERY_STATUS tmp_fqs = {
1082 .facets = lqs_facets_create(
1083 LQS_DEFAULT_ITEMS_PER_QUERY,
1084 - FACETS_OPTION_ALL_KEYS_FTS,
1084 + FACETS_OPTION_ALL_KEYS_FTS | FACETS_OPTION_HASH_IDS,
1085 WEVT_ALWAYS_VISIBLE_KEYS,
1086 WEVT_KEYS_INCLUDED_IN_FACETS,
1087 WEVT_KEYS_EXCLUDED_FROM_FACETS,
src/libnetdata/facets/facets.c
+35 -12
@@ -359,6 +359,28 @@ uint32_t facets_rows(FACETS *facets) {
359 return facets->items_to_return;
360 }
361
362 +static const char *facets_key_id(FACET_KEY *k) {
363 + if(k->facets->options & FACETS_OPTION_HASH_IDS)
364 + return hash_to_static_string(k->hash);
365 + else
366 + return k->name ? k->name : hash_to_static_string(k->hash);
367 +}
368 +
369 +static const char *facets_key_value_id(FACET_KEY *k, FACET_VALUE *v) {
370 + if(k->facets->options & FACETS_OPTION_HASH_IDS)
371 + return hash_to_static_string(v->hash);
372 + else
373 + return v->name ? v->name : hash_to_static_string(v->hash);
374 +}
375 +
376 +void facets_use_hashes_for_ids(FACETS *facets, bool set) {
377 + netdata_log_info("FACETS_OPTION_HASH_IDS = %s", set ? "true" : "false");
378 + if(set)
379 + facets->options |= FACETS_OPTION_HASH_IDS;
380 + else
381 + facets->options &= ~(FACETS_OPTION_HASH_IDS);
382 +}
383 +
384 // ----------------------------------------------------------------------------
385
386 static void facets_row_free(FACETS *facets __maybe_unused, FACET_ROW *row);
@@ -2346,7 +2368,7 @@ void facets_accepted_parameters_to_json_array(FACETS *facets, BUFFER *wb, bool w
2368 if (!k->values.enabled)
2369 continue;
2370
2349 - buffer_json_add_array_item_string(wb, hash_to_static_string(k->hash));
2371 + buffer_json_add_array_item_string(wb, facets_key_id(k));
2372 }
2373 foreach_key_in_facets_done(k);
2374 }
@@ -2526,8 +2548,8 @@ static uint32_t facets_sort_and_reorder_values(FACET_KEY *k) {
2548 return ret;
2549 }
2550
2529 -void facets_table_config(BUFFER *wb) {
2530 - buffer_json_member_add_boolean(wb, "show_ids", false); // do not show the column ids to the user
2551 +void facets_table_config(FACETS *facets, BUFFER *wb) {
2552 + buffer_json_member_add_boolean(wb, "show_ids", (facets->options & FACETS_OPTION_HASH_IDS) ? false : true);
2553 buffer_json_member_add_boolean(wb, "has_history", true); // enable date-time picker with after-before
2554
2555 buffer_json_member_add_object(wb, "pagination");
@@ -2543,8 +2565,9 @@ void facets_table_config(BUFFER *wb) {
2565 void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry) {
2566 facets->report.used_hashes_registry = used_hashes_registry;
2567
2568 + facets_table_config(facets, wb);
2569 +
2570 if(!(facets->options & FACETS_OPTION_DATA_ONLY)) {
2547 - facets_table_config(wb);
2571 facets_accepted_parameters_to_json_array(facets, wb, true);
2572 }
2573
@@ -2577,13 +2600,13 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2600 buffer_json_add_array_item_object(wb); // key
2601 {
2602 buffer_json_member_add_string(
2580 - wb, "id", hash_to_static_string(k->hash));
2603 + wb, "id", facets_key_id(k));
2604
2605 buffer_json_member_add_string(
2606 wb, "name",
2607 facets_key_name_cached(k, facets->report.used_hashes_registry));
2608
2586 - buffer_json_member_add_string(wb, "raw", k->name);
2609 + // buffer_json_member_add_string(wb, "raw", k->name);
2610
2611 if(!k->order) k->order = facets->order++;
2612 buffer_json_member_add_uint64(wb, "order", k->order);
@@ -2600,11 +2623,11 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2623
2624 buffer_json_add_array_item_object(wb);
2625 {
2603 - buffer_json_member_add_string(wb, "id", hash_to_static_string(v->hash));
2626 + buffer_json_member_add_string(wb, "id", facets_key_value_id(k, v));
2627
2628 facets_key_value_transformed(facets, k, v, tb, FACETS_TRANSFORM_FACET);
2629 buffer_json_member_add_string(wb, "name", buffer_tostring(tb));
2607 - buffer_json_member_add_string(wb, "raw", v->name);
2630 + // buffer_json_member_add_string(wb, "raw", v->name);
2631 buffer_json_member_add_uint64(wb, "count", v->final_facet_value_counter);
2632 buffer_json_member_add_uint64(wb, "order", v->order);
2633 }
@@ -2673,11 +2696,11 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2696 if (k->options & FACET_KEY_OPTION_PRETTY_XML)
2697 transform = RRDF_FIELD_TRANSFORM_XML;
2698
2676 - const char *hash_str = hash_to_static_string(k->hash);
2699 + const char *key_id = facets_key_id(k);
2700
2701 buffer_rrdf_table_add_field(
2702 wb, field_id++,
2680 - hash_str, k->name ? k->name : hash_str,
2703 + key_id, k->name ? k->name : key_id,
2704 RRDF_FIELD_TYPE_STRING,
2705 visual, transform, 0, NULL, NAN,
2706 RRDF_FIELD_SORT_FIXED,
@@ -2771,7 +2794,7 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2794 first_histogram_hash = k->hash;
2795
2796 buffer_json_add_array_item_object(wb);
2774 - buffer_json_member_add_string(wb, "id", hash_to_static_string(k->hash));
2797 + buffer_json_member_add_string(wb, "id", facets_key_id(k));
2798 buffer_json_member_add_string(wb, "name", k->name);
2799 buffer_json_member_add_uint64(wb, "order", k->order);
2800 buffer_json_object_close(wb);
@@ -2799,7 +2822,7 @@ void facets_report(FACETS *facets, BUFFER *wb, DICTIONARY *used_hashes_registry)
2822 }
2823
2824 if(show_histogram) {
2802 - buffer_json_member_add_string(wb, "id", k ? hash_to_static_string(k->hash) : "");
2825 + buffer_json_member_add_string(wb, "id", k ? facets_key_id(k) : "");
2826 buffer_json_member_add_string(wb, "name", k ? k->name : "");
2827 buffer_json_member_add_object(wb, "chart");
2828 {
src/libnetdata/facets/facets.h
+4 -1
@@ -88,6 +88,7 @@ typedef enum __attribute__((packed)) {
88 FACETS_OPTION_DONT_SEND_EMPTY_VALUE_FACETS = (1 << 5), // empty facet values will not be included in the report
89 FACETS_OPTION_SORT_FACETS_ALPHABETICALLY = (1 << 6),
90 FACETS_OPTION_SHOW_DELTAS = (1 << 7),
91 + FACETS_OPTION_HASH_IDS = (1 << 8), // when set, the id of the facets, keys and values will be their hash
92 } FACETS_OPTIONS;
93
94 FACETS *facets_create(uint32_t items_to_return, FACETS_OPTIONS options, const char *visible_keys, const char *facet_keys, const char *non_facet_keys);
@@ -138,7 +139,7 @@ usec_t facets_row_oldest_ut(FACETS *facets);
139 usec_t facets_row_newest_ut(FACETS *facets);
140 uint32_t facets_rows(FACETS *facets);
141
141 -void facets_table_config(BUFFER *wb);
142 +void facets_table_config(FACETS *facets, BUFFER *wb);
143
144 const char *facets_severity_to_string(FACET_ROW_SEVERITY severity);
145
@@ -148,4 +149,6 @@ bool facets_foreach_selected_value_in_key(FACETS *facets, const char *key, size_
149 void facets_row_bin_data_set(FACETS *facets, void (*cleanup_cb)(void *data), void *data);
150 void *facets_row_bin_data_get(FACETS *facets __maybe_unused, FACET_ROW *row);
151
152 +void facets_use_hashes_for_ids(FACETS *facets, bool set);
153 +
154 #endif
src/libnetdata/facets/logs_query_status.h
+14 -3
@@ -354,6 +354,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
354 if (json_object_object_get_ex(jobj, LQS_PARAMETER_SOURCE, &sources)) {
355 if (json_object_get_type(sources) != json_type_array) {
356 buffer_sprintf(error, "member '%s' is not an array", LQS_PARAMETER_SOURCE);
357 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: '%s' is not an array", LQS_PARAMETER_SOURCE);
358 return false;
359 }
360
@@ -369,6 +370,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
370
371 if (json_object_get_type(src) != json_type_string) {
372 buffer_sprintf(error, "sources array item %zu is not a string", i);
373 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: sources array item %zu is not a string", i);
374 return false;
375 }
376
@@ -401,6 +403,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
403 if (json_object_object_get_ex(jobj, LQS_PARAMETER_FACETS, &fcts)) {
404 if (json_object_get_type(sources) != json_type_array) {
405 buffer_sprintf(error, "member '%s' is not an array", LQS_PARAMETER_FACETS);
406 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: '%s' is not an array", LQS_PARAMETER_FACETS);
407 return false;
408 }
409
@@ -415,6 +418,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
418
419 if (json_object_get_type(fct) != json_type_string) {
420 buffer_sprintf(error, "facets array item %zu is not a string", i);
421 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: facets array item %zu is not a string", i);
422 return false;
423 }
424
@@ -430,6 +434,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
434 if (json_object_object_get_ex(jobj, "selections", &selections)) {
435 if (json_object_get_type(selections) != json_type_object) {
436 buffer_sprintf(error, "member 'selections' is not an object");
437 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: '%s' is not an object", "selections");
438 return false;
439 }
440
@@ -438,6 +443,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
443 json_object_object_foreach(selections, key, val) {
444 if (json_object_get_type(val) != json_type_array) {
445 buffer_sprintf(error, "selection '%s' is not an array", key);
446 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: selection '%s' is not an array", key);
447 return false;
448 }
449
@@ -449,6 +455,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
455
456 if (json_object_get_type(value_obj) != json_type_string) {
457 buffer_sprintf(error, "selection '%s' array item %zu is not a string", key, i);
458 + // nd_log(NDLS_COLLECTORS, NDLP_ERR, "POST payload: selection '%s' array item %zu is not a string", key, i);
459 return false;
460 }
461
@@ -468,6 +475,7 @@ static inline bool lqs_request_parse_json_payload(json_object *jobj, const char
475 buffer_json_object_close(wb); // selections
476 }
477
478 + facets_use_hashes_for_ids(facets, false);
479 rq->fields_are_ids = false;
480 return true;
481 }
@@ -476,6 +484,8 @@ static inline bool lqs_request_parse_POST(LOGS_QUERY_STATUS *lqs, BUFFER *wb, BU
484 FACETS *facets = lqs->facets;
485 LOGS_QUERY_REQUEST *rq = &lqs->rq;
486
487 + buffer_json_member_add_object(wb, "_request");
488 +
489 struct logs_query_data qd = {
490 .transaction = transaction,
491 .facets = facets,
@@ -498,7 +508,7 @@ static inline bool lqs_request_parse_GET(LOGS_QUERY_STATUS *lqs, BUFFER *wb, cha
508 buffer_json_member_add_object(wb, "_request");
509
510 char func_copy[strlen(function) + 1];
501 - strcpy(func_copy, function);
511 + memcpy(func_copy, function, sizeof(func_copy));
512
513 char *words[LQS_MAX_PARAMS] = { NULL };
514 size_t num_words = quoted_strings_splitter_pluginsd(func_copy, words, LQS_MAX_PARAMS);
@@ -661,6 +671,7 @@ static inline bool lqs_request_parse_GET(LOGS_QUERY_STATUS *lqs, BUFFER *wb, cha
671 }
672 }
673
674 + facets_use_hashes_for_ids(facets, true);
675 rq->fields_are_ids = true;
676 return true;
677 }
@@ -689,7 +700,7 @@ static inline void lqs_info_response(BUFFER *wb, FACETS *facets) {
700 }
701 buffer_json_array_close(wb); // required_params array
702
692 - facets_table_config(wb);
703 + facets_table_config(facets, wb);
704
705 buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
706 buffer_json_member_add_string(wb, "type", "table");
@@ -702,7 +713,7 @@ static inline void lqs_info_response(BUFFER *wb, FACETS *facets) {
713
714 static inline BUFFER *lqs_create_output_buffer(void) {
715 BUFFER *wb = buffer_create(0, NULL);
705 - buffer_flush(wb);
716 + buffer_reset(wb);
717 buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_MINIFY);
718 return wb;
719 }
src/libnetdata/functions_evloop/functions_evloop.c
+9 -1
@@ -137,6 +137,8 @@ static void worker_add_job(struct functions_evloop_globals *wg, const char *keyw
137 function?function:"(unset)");
138 }
139 else {
140 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "WORKER JOB WITH PAYLOAD '%s'", payload ? buffer_tostring(payload) : "NONE");
141 +
142 int timeout = str2i(timeout_s);
143
144 const char *msg = "No function with this name found";
@@ -222,6 +224,8 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
224 char *s = (char *)buffer_tostring(buffer);
225
226 if(strstr(&s[deferred.last_len], PLUGINSD_CALL_FUNCTION_PAYLOAD_END "\n") != NULL) {
227 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "FUNCTION PAYLOAD END");
228 +
229 if(deferred.last_len > 0)
230 // remove the trailing newline from the buffer
231 deferred.last_len--;
@@ -254,6 +258,7 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
258 const char *keyword = get_word(words, num_words, 0);
259
260 if(keyword && (strcmp(keyword, PLUGINSD_CALL_FUNCTION) == 0)) {
261 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "FUNCTION CALL");
262 char *transaction = get_word(words, num_words, 1);
263 char *timeout_s = get_word(words, num_words, 2);
264 char *function = get_word(words, num_words, 3);
@@ -262,6 +267,7 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
267 worker_add_job(wg, keyword, transaction, function, timeout_s, NULL, access, source);
268 }
269 else if(keyword && (strcmp(keyword, PLUGINSD_CALL_FUNCTION_PAYLOAD_BEGIN) == 0)) {
270 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "FUNCTION PAYLOAD CALL");
271 char *transaction = get_word(words, num_words, 1);
272 char *timeout_s = get_word(words, num_words, 2);
273 char *function = get_word(words, num_words, 3);
@@ -279,6 +285,7 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
285 deferred.enabled = true;
286 }
287 else if(keyword && strcmp(keyword, PLUGINSD_CALL_FUNCTION_CANCEL) == 0) {
288 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "FUNCTION CANCEL");
289 char *transaction = get_word(words, num_words, 1);
290 const DICTIONARY_ITEM *acquired = dictionary_get_and_acquire_item(wg->worker_queue, transaction);
291 if(acquired) {
@@ -292,6 +299,7 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
299 nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "Received CANCEL for transaction '%s', but it not available here", transaction);
300 }
301 else if(keyword && strcmp(keyword, PLUGINSD_CALL_FUNCTION_PROGRESS) == 0) {
302 + // nd_log(NDLS_COLLECTORS, NDLP_INFO, "FUNCTION PROGRESS");
303 char *transaction = get_word(words, num_words, 1);
304 const DICTIONARY_ITEM *acquired = dictionary_get_and_acquire_item(wg->worker_queue, transaction);
305 if(acquired) {
@@ -305,7 +313,7 @@ static void *rrd_functions_worker_globals_reader_main(void *arg) {
313 nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "Received PROGRESS for transaction '%s', but it not available here", transaction);
314 }
315 else
308 - nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "Received unknown command: %s", keyword?keyword:"(unset)");
316 + nd_log(NDLS_COLLECTORS, NDLP_NOTICE, "Received unknown command: %s", keyword ? keyword : "(unset)");
317
318 buffer_flush(buffer);
319 }
src/web/api/v1/api_v1_function.c
+1 -1
@@ -39,6 +39,6 @@ int api_v1_function(RRDHOST *host, struct web_client *w, char *url) {
39 return rrd_function_run(host, wb, timeout, w->access, function, true, transaction,
40 NULL, NULL,
41 web_client_progress_functions_update, w,
42 - web_client_interrupt_callback, w, NULL,
42 + web_client_interrupt_callback, w, w->payload,
43 buffer_tostring(source), false);
44 }