allow any field to be a facet (#15880)
Costa Tsaousis committed
Aug 25, 2023 at 09:43 UTC
b194954ff59488b1f86dbc81a08532817170048f
3 files changed
+79
-52
collectors/systemd-journal.plugin/systemd-journal.c
+58
-39
@@ -29,6 +29,7 @@
29
#define JOURNAL_PARAMETER_ANCHOR "anchor"
30
#define JOURNAL_PARAMETER_LAST "last"
31
#define JOURNAL_PARAMETER_QUERY "query"
32
+#define JOURNAL_PARAMETER_FACETS "facets"
33
#define JOURNAL_PARAMETER_HISTOGRAM "histogram"
34
35
#define SYSTEMD_ALWAYS_VISIBLE_KEYS NULL
@@ -52,6 +53,8 @@
53
"|_SYSTEMD_USER_UNIT" \
54
"|USER_UNIT" \
55
"|UNIT" \
56
+ "|CONTAINER_NAME" \
57
+ "|IMAGE_NAME" \
58
""
59
60
static netdata_mutex_t mutex = NETDATA_MUTEX_INITIALIZER;
@@ -232,8 +235,7 @@ static char *uid_to_username(uid_t uid, char *buffer, size_t buffer_size) {
235
if (getpwuid_r(uid, &pw, tmp, 1024, &result) != 0 || result == NULL)
236
return NULL;
237
235
- strncpy(buffer, pw.pw_name, buffer_size - 1);
236
- buffer[buffer_size - 1] = '\0'; // Null-terminate just in case
238
+ snprintfz(buffer, buffer_size - 1, "%u (%s)", uid, pw.pw_name);
239
return buffer;
240
}
241
@@ -244,8 +246,7 @@ static char *gid_to_groupname(gid_t gid, char* buffer, size_t buffer_size) {
246
if (getgrgid_r(gid, &grp, tmp, 1024, &result) != 0 || result == NULL)
247
return NULL;
248
247
- strncpy(buffer, grp.gr_name, buffer_size - 1);
248
- buffer[buffer_size - 1] = '\0'; // Null-terminate just in case
249
+ snprintfz(buffer, buffer_size - 1, "%u (%s)", gid, grp.gr_name);
250
return buffer;
251
}
252
@@ -336,9 +337,6 @@ static void systemd_journal_dynamic_row_id(FACETS *facets __maybe_unused, BUFFER
337
}
338
339
static void function_systemd_journal(const char *transaction, char *function, char *line_buffer __maybe_unused, int line_max __maybe_unused, int timeout __maybe_unused) {
339
- char *words[SYSTEMD_JOURNAL_MAX_PARAMS] = { NULL };
340
- size_t num_words = quoted_strings_splitter_pluginsd(function, words, SYSTEMD_JOURNAL_MAX_PARAMS);
341
-
340
BUFFER *wb = buffer_create(0, NULL);
341
buffer_flush(wb);
342
buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_NEWLINE_ON_ARRAY_ITEMS);
@@ -353,31 +351,34 @@ static void function_systemd_journal(const char *transaction, char *function, ch
351
facets_accepted_param(facets, JOURNAL_PARAMETER_ANCHOR);
352
facets_accepted_param(facets, JOURNAL_PARAMETER_LAST);
353
facets_accepted_param(facets, JOURNAL_PARAMETER_QUERY);
354
+ facets_accepted_param(facets, JOURNAL_PARAMETER_FACETS);
355
facets_accepted_param(facets, JOURNAL_PARAMETER_HISTOGRAM);
356
357
// register the fields in the order you want them on the dashboard
358
360
- facets_register_dynamic_key(facets, "ND_JOURNAL_PROCESS", FACET_KEY_OPTION_NO_FACET|FACET_KEY_OPTION_VISIBLE|FACET_KEY_OPTION_FTS,
361
- systemd_journal_dynamic_row_id, NULL);
359
+ facets_register_dynamic_key_name(facets, "ND_JOURNAL_PROCESS",
360
+ FACET_KEY_OPTION_NO_FACET | FACET_KEY_OPTION_VISIBLE | FACET_KEY_OPTION_FTS,
361
+ systemd_journal_dynamic_row_id, NULL);
362
363
- facets_register_key(facets, "MESSAGE",
364
- FACET_KEY_OPTION_NO_FACET|FACET_KEY_OPTION_MAIN_TEXT|FACET_KEY_OPTION_VISIBLE|FACET_KEY_OPTION_FTS);
363
+ facets_register_key_name(facets, "MESSAGE",
364
+ FACET_KEY_OPTION_NO_FACET | FACET_KEY_OPTION_MAIN_TEXT | FACET_KEY_OPTION_VISIBLE |
365
+ FACET_KEY_OPTION_FTS);
366
366
- facets_register_key_transformation(facets, "PRIORITY", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS,
367
- systemd_journal_transform_priority, NULL);
367
+ facets_register_key_name_transformation(facets, "PRIORITY", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS,
368
+ systemd_journal_transform_priority, NULL);
369
369
- facets_register_key_transformation(facets, "SYSLOG_FACILITY", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS,
370
- systemd_journal_transform_syslog_facility, NULL);
370
+ facets_register_key_name_transformation(facets, "SYSLOG_FACILITY", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS,
371
+ systemd_journal_transform_syslog_facility, NULL);
372
372
- facets_register_key(facets, "SYSLOG_IDENTIFIER", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS);
373
- facets_register_key(facets, "UNIT", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS);
374
- facets_register_key(facets, "USER_UNIT", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS);
373
+ facets_register_key_name(facets, "SYSLOG_IDENTIFIER", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS);
374
+ facets_register_key_name(facets, "UNIT", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS);
375
+ facets_register_key_name(facets, "USER_UNIT", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS);
376
376
- facets_register_key_transformation(facets, "_UID", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS,
377
- systemd_journal_transform_uid, uids);
377
+ facets_register_key_name_transformation(facets, "_UID", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS,
378
+ systemd_journal_transform_uid, uids);
379
379
- facets_register_key_transformation(facets, "_GID", FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS,
380
- systemd_journal_transform_gid, gids);
380
+ facets_register_key_name_transformation(facets, "_GID", FACET_KEY_OPTION_FACET | FACET_KEY_OPTION_FTS,
381
+ systemd_journal_transform_gid, gids);
382
383
time_t after_s = 0, before_s = 0;
384
usec_t anchor = 0;
@@ -386,33 +387,53 @@ static void function_systemd_journal(const char *transaction, char *function, ch
387
const char *chart = NULL;
388
389
buffer_json_member_add_object(wb, "request");
389
- buffer_json_member_add_object(wb, "filters");
390
391
+ char *words[SYSTEMD_JOURNAL_MAX_PARAMS] = { NULL };
392
+ size_t num_words = quoted_strings_splitter_pluginsd(function, words, SYSTEMD_JOURNAL_MAX_PARAMS);
393
for(int i = 1; i < SYSTEMD_JOURNAL_MAX_PARAMS ;i++) {
392
- const char *keyword = get_word(words, num_words, i);
394
+ char *keyword = get_word(words, num_words, i);
395
if(!keyword) break;
396
397
if(strcmp(keyword, JOURNAL_PARAMETER_HELP) == 0) {
398
systemd_journal_function_help(transaction);
399
goto cleanup;
400
}
399
- else if(strncmp(keyword, JOURNAL_PARAMETER_AFTER ":", strlen(JOURNAL_PARAMETER_AFTER ":")) == 0) {
400
- after_s = str2l(&keyword[strlen(JOURNAL_PARAMETER_AFTER ":")]);
401
+ else if(strncmp(keyword, JOURNAL_PARAMETER_AFTER ":", sizeof(JOURNAL_PARAMETER_AFTER ":") - 1) == 0) {
402
+ after_s = str2l(&keyword[sizeof(JOURNAL_PARAMETER_AFTER ":") - 1]);
403
}
402
- else if(strncmp(keyword, JOURNAL_PARAMETER_BEFORE ":", strlen(JOURNAL_PARAMETER_BEFORE ":")) == 0) {
403
- before_s = str2l(&keyword[strlen(JOURNAL_PARAMETER_BEFORE ":")]);
404
+ else if(strncmp(keyword, JOURNAL_PARAMETER_BEFORE ":", sizeof(JOURNAL_PARAMETER_BEFORE ":") - 1) == 0) {
405
+ before_s = str2l(&keyword[sizeof(JOURNAL_PARAMETER_BEFORE ":") - 1]);
406
}
405
- else if(strncmp(keyword, JOURNAL_PARAMETER_ANCHOR ":", strlen(JOURNAL_PARAMETER_ANCHOR ":")) == 0) {
406
- anchor = str2ull(&keyword[strlen(JOURNAL_PARAMETER_ANCHOR ":")], NULL);
407
+ else if(strncmp(keyword, JOURNAL_PARAMETER_ANCHOR ":", sizeof(JOURNAL_PARAMETER_ANCHOR ":") - 1) == 0) {
408
+ anchor = str2ull(&keyword[sizeof(JOURNAL_PARAMETER_ANCHOR ":") - 1], NULL);
409
}
408
- else if(strncmp(keyword, JOURNAL_PARAMETER_LAST ":", strlen(JOURNAL_PARAMETER_LAST ":")) == 0) {
409
- last = str2ul(&keyword[strlen(JOURNAL_PARAMETER_LAST ":")]);
410
+ else if(strncmp(keyword, JOURNAL_PARAMETER_LAST ":", sizeof(JOURNAL_PARAMETER_LAST ":") - 1) == 0) {
411
+ last = str2ul(&keyword[sizeof(JOURNAL_PARAMETER_LAST ":") - 1]);
412
}
411
- else if(strncmp(keyword, JOURNAL_PARAMETER_QUERY ":", strlen(JOURNAL_PARAMETER_QUERY ":")) == 0) {
412
- query= &keyword[strlen(JOURNAL_PARAMETER_QUERY ":")];
413
+ else if(strncmp(keyword, JOURNAL_PARAMETER_QUERY ":", sizeof(JOURNAL_PARAMETER_QUERY ":") - 1) == 0) {
414
+ query= &keyword[sizeof(JOURNAL_PARAMETER_QUERY ":") - 1];
415
}
414
- else if(strncmp(keyword, JOURNAL_PARAMETER_HISTOGRAM ":", strlen(JOURNAL_PARAMETER_HISTOGRAM ":")) == 0) {
415
- chart = &keyword[strlen(JOURNAL_PARAMETER_HISTOGRAM ":")];
416
+ else if(strncmp(keyword, JOURNAL_PARAMETER_HISTOGRAM ":", sizeof(JOURNAL_PARAMETER_HISTOGRAM ":") - 1) == 0) {
417
+ chart = &keyword[sizeof(JOURNAL_PARAMETER_HISTOGRAM ":") - 1];
418
+ }
419
+ else if(strncmp(keyword, JOURNAL_PARAMETER_FACETS ":", sizeof(JOURNAL_PARAMETER_FACETS ":") - 1) == 0) {
420
+ char *value = &keyword[sizeof(JOURNAL_PARAMETER_FACETS ":") - 1];
421
+ if(*value) {
422
+ buffer_json_member_add_array(wb, JOURNAL_PARAMETER_FACETS);
423
+
424
+ while(value) {
425
+ char *sep = strchr(value, ',');
426
+ if(sep)
427
+ *sep++ = '\0';
428
+
429
+ facets_register_facet_id(facets, value, FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS|FACET_KEY_OPTION_REORDER);
430
+ buffer_json_add_array_item_string(wb, value);
431
+
432
+ value = sep;
433
+ }
434
+
435
+ buffer_json_array_close(wb); // JOURNAL_PARAMETER_FACETS
436
+ }
437
}
438
else {
439
char *value = strchr(keyword, ':');
@@ -426,7 +447,7 @@ static void function_systemd_journal(const char *transaction, char *function, ch
447
if(sep)
448
*sep++ = '\0';
449
429
- facets_register_facet_filter(facets, keyword, value, FACET_KEY_OPTION_REORDER);
450
+ facets_register_facet_id_filter(facets, keyword, value, FACET_KEY_OPTION_FACET|FACET_KEY_OPTION_FTS|FACET_KEY_OPTION_REORDER);
451
buffer_json_add_array_item_string(wb, value);
452
453
value = sep;
@@ -437,8 +458,6 @@ static void function_systemd_journal(const char *transaction, char *function, ch
458
}
459
}
460
440
- buffer_json_object_close(wb); // filters
441
-
461
time_t expires = now_realtime_sec() + 1;
462
time_t now_s;
463
libnetdata/facets/facets.c
+16
-9
@@ -841,7 +841,7 @@ void facets_accepted_param(FACETS *facets, const char *param) {
841
dictionary_set(facets->accepted_params, param, NULL, 0);
842
}
843
844
-inline FACET_KEY *facets_register_key(FACETS *facets, const char *key, FACET_KEY_OPTIONS options) {
844
+inline FACET_KEY *facets_register_key_name(FACETS *facets, const char *key, FACET_KEY_OPTIONS options) {
845
FACET_KEY tk = {
846
.name = key,
847
.options = options,
@@ -852,15 +852,15 @@ inline FACET_KEY *facets_register_key(FACETS *facets, const char *key, FACET_KEY
852
return dictionary_set(facets->keys, hash, &tk, sizeof(tk));
853
}
854
855
-inline FACET_KEY *facets_register_key_transformation(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facets_key_transformer_t cb, void *data) {
856
- FACET_KEY *k = facets_register_key(facets, key, options);
855
+inline FACET_KEY *facets_register_key_name_transformation(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facets_key_transformer_t cb, void *data) {
856
+ FACET_KEY *k = facets_register_key_name(facets, key, options);
857
k->transform.cb = cb;
858
k->transform.data = data;
859
return k;
860
}
861
862
-inline FACET_KEY *facets_register_dynamic_key(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facet_dynamic_row_t cb, void *data) {
863
- FACET_KEY *k = facets_register_key(facets, key, options);
862
+inline FACET_KEY *facets_register_dynamic_key_name(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facet_dynamic_row_t cb, void *data) {
863
+ FACET_KEY *k = facets_register_key_name(facets, key, options);
864
k->dynamic.cb = cb;
865
k->dynamic.data = data;
866
return k;
@@ -881,17 +881,24 @@ void facets_set_anchor(FACETS *facets, usec_t anchor) {
881
facets->anchor = anchor;
882
}
883
884
-void facets_register_facet_filter(FACETS *facets, const char *key_id, char *value_ids, FACET_KEY_OPTIONS options) {
884
+inline FACET_KEY *facets_register_facet_id(FACETS *facets, const char *key_id, FACET_KEY_OPTIONS options) {
885
FACET_KEY tk = {
886
.options = options,
887
+ .default_selected_for_values = true,
888
};
889
FACET_KEY *k = dictionary_set(facets->keys, key_id, &tk, sizeof(tk));
890
890
- k->default_selected_for_values = false;
891
k->options |= FACET_KEY_OPTION_FACET;
892
k->options &= ~FACET_KEY_OPTION_NO_FACET;
893
facet_key_late_init(facets, k);
894
895
+ return k;
896
+}
897
+
898
+void facets_register_facet_id_filter(FACETS *facets, const char *key_id, char *value_ids, FACET_KEY_OPTIONS options) {
899
+ FACET_KEY *k = facets_register_facet_id(facets, key_id, options);
900
+ k->default_selected_for_values = false;
901
+
902
FACET_VALUE tv = {
903
.selected = true,
904
};
@@ -935,7 +942,7 @@ static inline void facets_check_value(FACETS *facets __maybe_unused, FACET_KEY *
942
}
943
944
void facets_add_key_value(FACETS *facets, const char *key, const char *value) {
938
- FACET_KEY *k = facets_register_key(facets, key, 0);
945
+ FACET_KEY *k = facets_register_key_name(facets, key, 0);
946
buffer_flush(k->current_value.b);
947
buffer_strcat(k->current_value.b, value);
948
k->current_value.updated = true;
@@ -944,7 +951,7 @@ void facets_add_key_value(FACETS *facets, const char *key, const char *value) {
951
}
952
953
void facets_add_key_value_length(FACETS *facets, const char *key, const char *value, size_t value_len) {
947
- FACET_KEY *k = facets_register_key(facets, key, 0);
954
+ FACET_KEY *k = facets_register_key_name(facets, key, 0);
955
buffer_flush(k->current_value.b);
956
buffer_strncat(k->current_value.b, value, value_len);
957
k->current_value.updated = true;
libnetdata/facets/facets.h
+5
-4
@@ -34,8 +34,8 @@ void facets_string_hash(const char *src, size_t len, char *out);
34
35
typedef void (*facets_key_transformer_t)(FACETS *facets __maybe_unused, BUFFER *wb, void *data);
36
typedef void (*facet_dynamic_row_t)(FACETS *facets, BUFFER *json_array, FACET_ROW_KEY_VALUE *rkv, FACET_ROW *row, void *data);
37
-FACET_KEY *facets_register_dynamic_key(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facet_dynamic_row_t cb, void *data);
38
-FACET_KEY *facets_register_key_transformation(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facets_key_transformer_t cb, void *data);
37
+FACET_KEY *facets_register_dynamic_key_name(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facet_dynamic_row_t cb, void *data);
38
+FACET_KEY *facets_register_key_name_transformation(FACETS *facets, const char *key, FACET_KEY_OPTIONS options, facets_key_transformer_t cb, void *data);
39
40
typedef enum __attribute__((packed)) {
41
FACETS_OPTION_ALL_FACETS_VISIBLE = (1 << 0), // all facets, should be visible by default in the table
@@ -50,11 +50,12 @@ void facets_accepted_param(FACETS *facets, const char *param);
50
void facets_rows_begin(FACETS *facets);
51
void facets_row_finished(FACETS *facets, usec_t usec);
52
53
-FACET_KEY *facets_register_key(FACETS *facets, const char *param, FACET_KEY_OPTIONS options);
53
+FACET_KEY *facets_register_key_name(FACETS *facets, const char *key, FACET_KEY_OPTIONS options);
54
void facets_set_query(FACETS *facets, const char *query);
55
void facets_set_items(FACETS *facets, uint32_t items);
56
void facets_set_anchor(FACETS *facets, usec_t anchor);
57
-void facets_register_facet_filter(FACETS *facets, const char *key_id, char *value_ids, FACET_KEY_OPTIONS options);
57
+FACET_KEY *facets_register_facet_id(FACETS *facets, const char *key_id, FACET_KEY_OPTIONS options);
58
+void facets_register_facet_id_filter(FACETS *facets, const char *key_id, char *value_ids, FACET_KEY_OPTIONS options);
59
void facets_set_histogram(FACETS *facets, const char *chart, usec_t after_ut, usec_t before_ut);
60
61
void facets_add_key_value(FACETS *facets, const char *key, const char *value);