summaryrefslogtreecommitdiffstats
path: root/libnetdata
diff options
context:
space:
mode:
authorCosta Tsaousis <costa@netdata.cloud>2023-03-02 22:50:48 +0200
committerGitHub <noreply@github.com>2023-03-02 22:50:48 +0200
commit021e252fc5d18a7225c0f4c975b3281016861d3c (patch)
tree63f92adc27419ca9df464635cd85424f52c94179 /libnetdata
parentc4d8d35b9f065f2a847f2780acb4342dabdfd34c (diff)
/api/v2/contexts (#14592)
* preparation for /api/v2/contexts * working /api/v2/contexts * add anomaly rate information in all statistics; when sum-count is requested, return sums and counts instead of averages * minor fix * query targegt now accurately counts hosts, contexts, instances, dimensions, metrics * cleanup /api/v2/contexts * full text search with /api/v2/contexts * simple patterns now support the option to search ignoring case * full text search API with /api/v2/q * simple pattern execution optimization * do not show q when not given * full text search accounting * separated /api/v2/nodes from /api/v2/contexts * fix ssv queries for group_by * count query instances queried and failed per context and host * split rrdcontext.c to multiple files * add query totals * fix anomaly rate calculation; provide "ni" for indexing hosts * do not generate zero valued members * faster calculation of anomaly rate; by just summing integers for each db points and doing math once for every generated point * fix typo when printing dimensions totals * added option minify to remove spaces and newlines fron JSON output * send instance ids and names when they differ * do not add in query target dimensions, instances, contexts and hosts for which there is no retention in the current timeframe * fix for the previous + renames and code cleanup * when a dimension is filtered, include in the response all the other dimensions that are selectable * do not add nodes that do not have retention in the current window * move selection of dimensions to query_dimension_add(), instead of query_metric_add() * increase the pre-processing capacity of queries * generate instance fqdn ids and names only when they are needed * provide detailed statistics about tiers retention, queries, points, update_every * late allocation of query dimensions * cleanup * more cleanup * support for annotations per displayed point, RESET and PARTIAL * new type annotations * if a chart is not linked to contexts and it is collected, link it when it is collected * make ML run reentrant * make ML rrdr query synchronous * optimize replication memory allocation of replication_sort_entry * change units to percentage, when requesting a coefficinet of variation, or a percentage query * initialize replication before starting main threads * properly decrement no room requests counter * propagate the non-zero flag to group-by * the same by avoiding the extra loop * respect non-zero in all dimension arrays * remove dictionary garbage collection from dictionary_entries() and dictionary_version() * be more verbose when jv2 indexing is postponed * prevent infinite loop * use hidden dimensions even when dimensions pattern is unset * traverse hosts using dictionaries * fix dictionary unittests
Diffstat (limited to 'libnetdata')
-rw-r--r--libnetdata/buffer/buffer.c14
-rw-r--r--libnetdata/buffer/buffer.h50
-rw-r--r--libnetdata/dictionary/dictionary.c9
-rw-r--r--libnetdata/health/health.c10
-rw-r--r--libnetdata/simple_pattern/simple_pattern.c140
-rw-r--r--libnetdata/simple_pattern/simple_pattern.h16
6 files changed, 172 insertions, 67 deletions
diff --git a/libnetdata/buffer/buffer.c b/libnetdata/buffer/buffer.c
index ab79a82c52..142fbca143 100644
--- a/libnetdata/buffer/buffer.c
+++ b/libnetdata/buffer/buffer.c
@@ -304,11 +304,13 @@ void buffer_increase(BUFFER *b, size_t free_size_required) {
// ----------------------------------------------------------------------------
-void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth, bool add_anonymous_object) {
+void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth,
+ bool add_anonymous_object, bool minify) {
strncpyz(wb->json.key_quote, key_quote, BUFFER_QUOTE_MAX_SIZE);
strncpyz(wb->json.value_quote, value_quote, BUFFER_QUOTE_MAX_SIZE);
- wb->json.depth = depth - 1;
+ wb->json.minify = minify;
+ wb->json.depth = (int8_t)(depth - 1);
_buffer_json_depth_push(wb, BUFFER_JSON_OBJECT);
if(add_anonymous_object)
@@ -331,7 +333,9 @@ void buffer_json_finalize(BUFFER *wb) {
break;
}
}
- buffer_fast_strcat(wb, "\n", 1);
+
+ if(!wb->json.minify)
+ buffer_fast_strcat(wb, "\n", 1);
}
// ----------------------------------------------------------------------------
@@ -481,13 +485,13 @@ int buffer_unittest(void) {
buffer_flush(wb);
- buffer_json_initialize(wb, "\"", "\"", 0, true);
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
buffer_json_finalize(wb);
errors += buffer_expect(wb, "{\n}\n");
buffer_flush(wb);
- buffer_json_initialize(wb, "\"", "\"", 0, true);
+ buffer_json_initialize(wb, "\"", "\"", 0, true, false);
buffer_json_member_add_string(wb, "hello", "world");
buffer_json_member_add_string(wb, "alpha", "this: \" is a double quote");
buffer_json_member_add_object(wb, "object1");
diff --git a/libnetdata/buffer/buffer.h b/libnetdata/buffer/buffer.h
index 907e586122..25ea0d188f 100644
--- a/libnetdata/buffer/buffer.h
+++ b/libnetdata/buffer/buffer.h
@@ -7,7 +7,7 @@
#define WEB_DATA_LENGTH_INCREASE_STEP 1024
-#define BUFFER_JSON_MAX_DEPTH 32
+#define BUFFER_JSON_MAX_DEPTH 32 // max is 255
extern const char hex_digits[16];
extern const char base64_digits[64];
@@ -71,7 +71,8 @@ typedef struct web_buffer {
struct {
char key_quote[BUFFER_QUOTE_MAX_SIZE + 1];
char value_quote[BUFFER_QUOTE_MAX_SIZE + 1];
- int depth;
+ int8_t depth;
+ bool minify;
BUFFER_JSON_NODE stack[BUFFER_JSON_MAX_DEPTH];
} json;
} BUFFER;
@@ -132,7 +133,9 @@ static inline void buffer_need_bytes(BUFFER *buffer, size_t needed_free_size) {
buffer_increase(buffer, needed_free_size + 1);
}
-void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth, bool add_anonymous_object);
+void buffer_json_initialize(BUFFER *wb, const char *key_quote, const char *value_quote, int depth,
+ bool add_anonymous_object, bool minify);
+
void buffer_json_finalize(BUFFER *wb);
static inline void _buffer_json_depth_push(BUFFER *wb, BUFFER_JSON_NODE_TYPE type) {
@@ -563,10 +566,12 @@ static inline void buffer_print_spaces(BUFFER *wb, size_t spaces) {
static inline void buffer_print_json_comma_newline_spacing(BUFFER *wb) {
if(wb->json.stack[wb->json.depth].count)
- buffer_fast_strcat(wb, ",\n", 2);
- else
- buffer_fast_strcat(wb, "\n", 1);
+ buffer_fast_strcat(wb, ",", 1);
+ if(wb->json.minify)
+ return;
+
+ buffer_fast_strcat(wb, "\n", 1);
buffer_print_spaces(wb, wb->json.depth + 1);
}
@@ -610,8 +615,10 @@ static inline void buffer_json_object_close(BUFFER *wb) {
assert(wb->json.depth >= 0 && "BUFFER JSON: nothing is open to close it");
assert(wb->json.stack[wb->json.depth].type == BUFFER_JSON_OBJECT && "BUFFER JSON: an object is not open to close it");
#endif
- buffer_fast_strcat(wb, "\n", 1);
- buffer_print_spaces(wb, wb->json.depth);
+ if(!wb->json.minify) {
+ buffer_fast_strcat(wb, "\n", 1);
+ buffer_print_spaces(wb, wb->json.depth);
+ }
buffer_fast_strcat(wb, "}", 1);
_buffer_json_depth_pop(wb);
}
@@ -717,6 +724,23 @@ static inline void buffer_json_add_array_item_uint64(BUFFER *wb, uint64_t value)
wb->json.stack[wb->json.depth].count++;
}
+static inline void buffer_json_add_array_item_time_t(BUFFER *wb, time_t value) {
+ if(wb->json.stack[wb->json.depth].count)
+ buffer_fast_strcat(wb, ",", 1);
+
+ buffer_print_int64(wb, value);
+ wb->json.stack[wb->json.depth].count++;
+}
+
+static inline void buffer_json_add_array_item_time_t2ms(BUFFER *wb, time_t value) {
+ if(wb->json.stack[wb->json.depth].count)
+ buffer_fast_strcat(wb, ",", 1);
+
+ buffer_print_int64(wb, value);
+ buffer_fast_strcat(wb, "000", 3);
+ wb->json.stack[wb->json.depth].count++;
+}
+
static inline void buffer_json_add_array_item_object(BUFFER *wb) {
if(wb->json.stack[wb->json.depth].count)
buffer_fast_strcat(wb, ",", 1);
@@ -736,6 +760,16 @@ static inline void buffer_json_member_add_time_t(BUFFER *wb, const char *key, ti
wb->json.stack[wb->json.depth].count++;
}
+static inline void buffer_json_member_add_time_t2ms(BUFFER *wb, const char *key, time_t value) {
+ buffer_print_json_comma_newline_spacing(wb);
+ buffer_print_json_key(wb, key);
+ buffer_fast_strcat(wb, ":", 1);
+ buffer_print_int64(wb, value);
+ buffer_fast_strcat(wb, "000", 3);
+
+ wb->json.stack[wb->json.depth].count++;
+}
+
static inline void buffer_json_member_add_uint64(BUFFER *wb, const char *key, uint64_t value) {
buffer_print_json_comma_newline_spacing(wb);
buffer_print_json_key(wb, key);
diff --git a/libnetdata/dictionary/dictionary.c b/libnetdata/dictionary/dictionary.c
index cb8aef9e08..e4128d01eb 100644
--- a/libnetdata/dictionary/dictionary.c
+++ b/libnetdata/dictionary/dictionary.c
@@ -344,7 +344,7 @@ size_t dictionary_version(DICTIONARY *dict) {
if(unlikely(!dict)) return 0;
// this is required for views to return the right number
- garbage_collect_pending_deletes(dict);
+ // garbage_collect_pending_deletes(dict);
return __atomic_load_n(&dict->version, __ATOMIC_RELAXED);
}
@@ -352,11 +352,10 @@ size_t dictionary_entries(DICTIONARY *dict) {
if(unlikely(!dict)) return 0;
// this is required for views to return the right number
- garbage_collect_pending_deletes(dict);
+ // garbage_collect_pending_deletes(dict);
long int entries = __atomic_load_n(&dict->entries, __ATOMIC_RELAXED);
- if(entries < 0)
- fatal("DICTIONARY: entries is negative: %ld", entries);
+ internal_fatal(entries < 0, "DICTIONARY: entries is negative: %ld", entries);
return entries;
}
@@ -3505,7 +3504,7 @@ size_t dictionary_unittest_views(void) {
fprintf(stderr, "\nPASS 2: Deleting master item:\n");
dictionary_del(master, "KEY 1");
- dictionary_version(view);
+ garbage_collect_pending_deletes(view);
errors += unittest_check_dictionary("master", master, 0, 0, 1, 1, 0);
errors += unittest_check_dictionary("view", view, 0, 0, 1, 1, 0);
errors += unittest_check_item("master", master, item1_on_master, "KEY 1", item1_on_master->shared->value, 1, ITEM_FLAG_DELETED, false, false, true);
diff --git a/libnetdata/health/health.c b/libnetdata/health/health.c
index c44ba08289..d5403cefa4 100644
--- a/libnetdata/health/health.c
+++ b/libnetdata/health/health.c
@@ -81,19 +81,19 @@ SILENCER *health_silencers_addparam(SILENCER *silencer, char *key, char *value)
if (hash == hash_alarm && !strcasecmp(key, HEALTH_ALARM_KEY)) {
silencer->alarms = strdupz(value);
- silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT);
+ silencer->alarms_pattern = simple_pattern_create(silencer->alarms, NULL, SIMPLE_PATTERN_EXACT, true);
} else if (hash == hash_chart && !strcasecmp(key, HEALTH_CHART_KEY)) {
silencer->charts = strdupz(value);
- silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT);
+ silencer->charts_pattern = simple_pattern_create(silencer->charts, NULL, SIMPLE_PATTERN_EXACT, true);
} else if (hash == hash_context && !strcasecmp(key, HEALTH_CONTEXT_KEY)) {
silencer->contexts = strdupz(value);
- silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT);
+ silencer->contexts_pattern = simple_pattern_create(silencer->contexts, NULL, SIMPLE_PATTERN_EXACT, true);
} else if (hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
silencer->hosts = strdupz(value);
- silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT);
+ silencer->hosts_pattern = simple_pattern_create(silencer->hosts, NULL, SIMPLE_PATTERN_EXACT, true);
} else if (hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
silencer->families = strdupz(value);
- silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT);
+ silencer->families_pattern = simple_pattern_create(silencer->families, NULL, SIMPLE_PATTERN_EXACT, true);
}
return silencer;
diff --git a/libnetdata/simple_pattern/simple_pattern.c b/libnetdata/simple_pattern/simple_pattern.c
index 81c2ed0b8c..39b9707619 100644
--- a/libnetdata/simple_pattern/simple_pattern.c
+++ b/libnetdata/simple_pattern/simple_pattern.c
@@ -4,17 +4,20 @@
struct simple_pattern {
const char *match;
- size_t len;
+ uint32_t len;
SIMPLE_PREFIX_MODE mode;
- char negative;
+ bool negative;
+ bool case_sensitive;
struct simple_pattern *child;
-
struct simple_pattern *next;
};
-static inline struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE default_mode) {
+static struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE default_mode, size_t count) {
+ if(unlikely(count >= 1000))
+ return NULL;
+
// fprintf(stderr, "PARSING PATTERN: '%s'\n", str);
SIMPLE_PREFIX_MODE mode;
@@ -31,7 +34,7 @@ static inline struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE
// do we have an asterisk in the middle?
if(*c == '*' && c[1] != '\0') {
// yes, we have
- child = parse_pattern(c, default_mode);
+ child = parse_pattern(c, default_mode, count + 1);
c[1] = '\0';
}
@@ -70,12 +73,12 @@ static inline struct simple_pattern *parse_pattern(char *str, SIMPLE_PREFIX_MODE
return m;
}
-SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode) {
+SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode, bool case_sensitive) {
struct simple_pattern *root = NULL, *last = NULL;
if(unlikely(!list || !*list)) return root;
- int isseparator[256] = {
+ char isseparator[256] = {
[' '] = 1 // space
, ['\t'] = 1 // tab
, ['\r'] = 1 // carriage return
@@ -96,14 +99,14 @@ SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators,
buf[0] = '\0';
char *c = buf;
- char negative = 0;
+ bool negative = false;
// skip all spaces
while(isseparator[(unsigned char)*s])
s++;
if(*s == '!') {
- negative = 1;
+ negative = true;
s++;
}
@@ -137,8 +140,9 @@ SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators,
continue;
// fprintf(stderr, "FOUND PATTERN: '%s'\n", buf);
- struct simple_pattern *m = parse_pattern(buf, default_mode);
+ struct simple_pattern *m = parse_pattern(buf, default_mode, 0);
m->negative = negative;
+ m->case_sensitive = case_sensitive;
// link it at the end
if(unlikely(!root))
@@ -174,70 +178,102 @@ static inline char *add_wildcarded(const char *matched, size_t matched_size, cha
return wildcarded;
}
-static inline int match_pattern(struct simple_pattern *m, const char *str, size_t len, char *wildcarded, size_t *wildcarded_size) {
+static inline int sp_strcmp(const char *s1, const char *s2, bool case_sensitive) {
+ if(case_sensitive)
+ return strcmp(s1, s2);
+
+ return strcasecmp(s1, s2);
+}
+
+static inline int sp_strncmp(const char *s1, const char *s2, size_t n, bool case_sensitive) {
+ if(case_sensitive)
+ return strncmp(s1, s2, n);
+
+ return strncasecmp(s1, s2, n);
+}
+
+static inline char *sp_strstr(const char *haystack, const char *needle, bool case_sensitive) {
+ if(case_sensitive)
+ return strstr(haystack, needle);
+
+ return strcasestr(haystack, needle);
+}
+
+static inline bool match_pattern(struct simple_pattern *m, const char *str, size_t len, char *wildcarded, size_t *wildcarded_size) {
char *s;
- if(m->len <= len) {
+ bool loop = true;
+ while(loop && m->len <= len) {
+ loop = false;
+
switch(m->mode) {
+ default:
+ case SIMPLE_PATTERN_EXACT:
+ if(unlikely(sp_strcmp(str, m->match, m->case_sensitive) == 0)) {
+ if(!m->child) return true;
+ return false;
+ }
+ break;
+
case SIMPLE_PATTERN_SUBSTRING:
- if(!m->len) return 1;
- if((s = strstr(str, m->match))) {
+ if(!m->len) return true;
+ if((s = sp_strstr(str, m->match, m->case_sensitive))) {
wildcarded = add_wildcarded(str, s - str, wildcarded, wildcarded_size);
if(!m->child) {
- wildcarded = add_wildcarded(&s[m->len], len - (&s[m->len] - str), wildcarded, wildcarded_size);
- return 1;
+ add_wildcarded(&s[m->len], len - (&s[m->len] - str), wildcarded, wildcarded_size);
+ return true;
+ }
+
+ // instead of recursion
+ {
+ len = len - (s - str) - m->len;
+ str = &s[m->len];
+ m = m->child;
+ loop = true;
+ // return match_pattern(m->child, &s[m->len], len - (s - str) - m->len, wildcarded, wildcarded_size);
}
- return match_pattern(m->child, &s[m->len], len - (s - str) - m->len, wildcarded, wildcarded_size);
}
break;
case SIMPLE_PATTERN_PREFIX:
- if(unlikely(strncmp(str, m->match, m->len) == 0)) {
+ if(unlikely(sp_strncmp(str, m->match, m->len, m->case_sensitive) == 0)) {
if(!m->child) {
- wildcarded = add_wildcarded(&str[m->len], len - m->len, wildcarded, wildcarded_size);
- return 1;
+ add_wildcarded(&str[m->len], len - m->len, wildcarded, wildcarded_size);
+ return true;
+ }
+ // instead of recursion
+ {
+ len = len - m->len;
+ str = &str[m->len];
+ m = m->child;
+ loop = true;
+ // return match_pattern(m->child, &str[m->len], len - m->len, wildcarded, wildcarded_size);
}
- return match_pattern(m->child, &str[m->len], len - m->len, wildcarded, wildcarded_size);
}
break;
case SIMPLE_PATTERN_SUFFIX:
- if(unlikely(strcmp(&str[len - m->len], m->match) == 0)) {
- wildcarded = add_wildcarded(str, len - m->len, wildcarded, wildcarded_size);
- if(!m->child) return 1;
- return 0;
- }
- break;
-
- case SIMPLE_PATTERN_EXACT:
- default:
- if(unlikely(strcmp(str, m->match) == 0)) {
- if(!m->child) return 1;
- return 0;
+ if(unlikely(sp_strcmp(&str[len - m->len], m->match, m->case_sensitive) == 0)) {
+ add_wildcarded(str, len - m->len, wildcarded, wildcarded_size);
+ if(!m->child) return true;
+ return false;
}
break;
}
}
- return 0;
+ return false;
}
-int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size) {
+static inline int simple_pattern_matches_extract_with_length(SIMPLE_PATTERN *list, const char *str, size_t len, char *wildcarded, size_t wildcarded_size) {
struct simple_pattern *m, *root = (struct simple_pattern *)list;
- if(unlikely(!root || !str || !*str)) return 0;
-
- size_t len = strlen(str);
for(m = root; m ; m = m->next) {
char *ws = wildcarded;
size_t wss = wildcarded_size;
if(unlikely(ws)) *ws = '\0';
if (match_pattern(m, str, len, ws, &wss)) {
-
- //if(ws && wss)
- // fprintf(stderr, "FINAL WILDCARDED '%s' of length %zu\n", ws, strlen(ws));
-
if (m->negative) return 0;
return 1;
}
@@ -246,6 +282,26 @@ int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *
return 0;
}
+int simple_pattern_matches_buffer_extract(SIMPLE_PATTERN *list, BUFFER *str, char *wildcarded, size_t wildcarded_size) {
+ if(!list || !str || buffer_strlen(str)) return 0;
+ return simple_pattern_matches_extract_with_length(list, buffer_tostring(str), buffer_strlen(str), wildcarded, wildcarded_size);
+}
+
+int simple_pattern_matches_string_extract(SIMPLE_PATTERN *list, STRING *str, char *wildcarded, size_t wildcarded_size) {
+ if(!list || !str) return 0;
+ return simple_pattern_matches_extract_with_length(list, string2str(str), string_strlen(str), wildcarded, wildcarded_size);
+}
+
+int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size) {
+ if(!list || !str || !*str) return 0;
+ return simple_pattern_matches_extract_with_length(list, str, strlen(str), wildcarded, wildcarded_size);
+}
+
+int simple_pattern_matches_length_extract(SIMPLE_PATTERN *list, const char *str, size_t len, char *wildcarded, size_t wildcarded_size) {
+ if(!list || !str || !*str || !len) return 0;
+ return simple_pattern_matches_extract_with_length(list, str, len, wildcarded, wildcarded_size);
+}
+
static inline void free_pattern(struct simple_pattern *m) {
if(!m) return;
diff --git a/libnetdata/simple_pattern/simple_pattern.h b/libnetdata/simple_pattern/simple_pattern.h
index 7282053e8b..135ac3b7c8 100644
--- a/libnetdata/simple_pattern/simple_pattern.h
+++ b/libnetdata/simple_pattern/simple_pattern.h
@@ -6,7 +6,7 @@
#include "../libnetdata.h"
-typedef enum {
+typedef enum __attribute__ ((__packed__)) {
SIMPLE_PATTERN_EXACT,
SIMPLE_PATTERN_PREFIX,
SIMPLE_PATTERN_SUFFIX,
@@ -18,13 +18,20 @@ typedef void SIMPLE_PATTERN;
// create a simple_pattern from the string given
// default_mode is used in cases where EXACT matches, without an asterisk,
// should be considered PREFIX matches.
-SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode);
+SIMPLE_PATTERN *simple_pattern_create(const char *list, const char *separators, SIMPLE_PREFIX_MODE default_mode, bool case_sensitive);
// test if string str is matched from the pattern and fill 'wildcarded' with the parts matched by '*'
int simple_pattern_matches_extract(SIMPLE_PATTERN *list, const char *str, char *wildcarded, size_t wildcarded_size);
+struct netdata_string;
+int simple_pattern_matches_string_extract(SIMPLE_PATTERN *list, struct netdata_string *str, char *wildcarded, size_t wildcarded_size);
+int simple_pattern_matches_buffer_extract(SIMPLE_PATTERN *list, BUFFER *str, char *wildcarded, size_t wildcarded_size);
+int simple_pattern_matches_length_extract(SIMPLE_PATTERN *list, const char *str, size_t len, char *wildcarded, size_t wildcarded_size);
+
// test if string str is matched from the pattern
#define simple_pattern_matches(list, str) simple_pattern_matches_extract(list, str, NULL, 0)
+#define simple_pattern_matches_string(list, str) simple_pattern_matches_string_extract(list, str, NULL, 0)
+#define simple_pattern_matches_buffer(list, str) simple_pattern_matches_buffer_extract(list, str, NULL, 0)
// free a simple_pattern that was created with simple_pattern_create()
// list can be NULL, in which case, this does nothing.
@@ -37,6 +44,11 @@ char *simple_pattern_iterate(SIMPLE_PATTERN **p);
// Auxiliary function to create a pattern
char *simple_pattern_trim_around_equal(char *src);
+#define SIMPLE_PATTERN_DEFAULT_WEB_SEPARATORS ",|\t\r\n\f\v"
+
#define is_valid_sp(x) ((x) && *(x) && !((x)[0] == '*' && (x)[1] == '\0'))
+#define string_to_simple_pattern(str) (is_valid_sp(str) ? simple_pattern_create(str, SIMPLE_PATTERN_DEFAULT_WEB_SEPARATORS, SIMPLE_PATTERN_EXACT, true) : NULL)
+#define string_to_simple_pattern_nocase(str) (is_valid_sp(str) ? simple_pattern_create(str, SIMPLE_PATTERN_DEFAULT_WEB_SEPARATORS, SIMPLE_PATTERN_EXACT, false) : NULL)
+
#endif //NETDATA_SIMPLE_PATTERN_H