diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2023-03-02 22:50:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-02 22:50:48 +0200 |
commit | 021e252fc5d18a7225c0f4c975b3281016861d3c (patch) | |
tree | 63f92adc27419ca9df464635cd85424f52c94179 /libnetdata | |
parent | c4d8d35b9f065f2a847f2780acb4342dabdfd34c (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.c | 14 | ||||
-rw-r--r-- | libnetdata/buffer/buffer.h | 50 | ||||
-rw-r--r-- | libnetdata/dictionary/dictionary.c | 9 | ||||
-rw-r--r-- | libnetdata/health/health.c | 10 | ||||
-rw-r--r-- | libnetdata/simple_pattern/simple_pattern.c | 140 | ||||
-rw-r--r-- | libnetdata/simple_pattern/simple_pattern.h | 16 |
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 |