123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404 |
- // SPDX-License-Identifier: GPL-3.0-or-later
- #include "log2journal.h"
- // ----------------------------------------------------------------------------
- void log_job_init(LOG_JOB *jb) {
- memset(jb, 0, sizeof(*jb));
- simple_hashtable_init_KEY(&jb->hashtable, 32);
- hashed_key_set(&jb->line.key, "LINE");
- }
- static void simple_hashtable_cleanup_allocated_keys(SIMPLE_HASHTABLE_KEY *ht) {
- SIMPLE_HASHTABLE_FOREACH_READ_ONLY(ht, sl, _KEY) {
- HASHED_KEY *k = SIMPLE_HASHTABLE_FOREACH_READ_ONLY_VALUE(sl);
- if(k && k->flags & HK_HASHTABLE_ALLOCATED) {
- // the order of these statements is important!
- simple_hashtable_del_slot_KEY(ht, sl); // remove any references to n
- hashed_key_cleanup(k); // cleanup the internals of n
- freez(k); // free n
- }
- }
- }
- void log_job_cleanup(LOG_JOB *jb) {
- hashed_key_cleanup(&jb->line.key);
- if(jb->prefix) {
- freez((void *) jb->prefix);
- jb->prefix = NULL;
- }
- if(jb->pattern) {
- freez((void *) jb->pattern);
- jb->pattern = NULL;
- }
- for(size_t i = 0; i < jb->injections.used ;i++)
- injection_cleanup(&jb->injections.keys[i]);
- for(size_t i = 0; i < jb->unmatched.injections.used ;i++)
- injection_cleanup(&jb->unmatched.injections.keys[i]);
- for(size_t i = 0; i < jb->renames.used ;i++)
- rename_cleanup(&jb->renames.array[i]);
- for(size_t i = 0; i < jb->rewrites.used; i++)
- rewrite_cleanup(&jb->rewrites.array[i]);
- txt_cleanup(&jb->rewrites.tmp);
- txt_cleanup(&jb->filename.current);
- simple_hashtable_cleanup_allocated_keys(&jb->hashtable);
- simple_hashtable_destroy_KEY(&jb->hashtable);
- // remove references to everything else, to reveal them in valgrind
- memset(jb, 0, sizeof(*jb));
- }
- // ----------------------------------------------------------------------------
- bool log_job_filename_key_set(LOG_JOB *jb, const char *key, size_t key_len) {
- if(!key || !*key) {
- log2stderr("filename key cannot be empty.");
- return false;
- }
- hashed_key_len_set(&jb->filename.key, key, key_len);
- return true;
- }
- bool log_job_key_prefix_set(LOG_JOB *jb, const char *prefix, size_t prefix_len) {
- if(!prefix || !*prefix) {
- log2stderr("filename key cannot be empty.");
- return false;
- }
- if(jb->prefix)
- freez((char*)jb->prefix);
- jb->prefix = strndupz(prefix, prefix_len);
- return true;
- }
- bool log_job_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len) {
- if(!pattern || !*pattern) {
- log2stderr("filename key cannot be empty.");
- return false;
- }
- if(jb->pattern)
- freez((char*)jb->pattern);
- jb->pattern = strndupz(pattern, pattern_len);
- return true;
- }
- bool log_job_include_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len) {
- if(jb->filter.include.re) {
- log2stderr("FILTER INCLUDE: there is already an include filter set");
- return false;
- }
- if(!search_pattern_set(&jb->filter.include, pattern, pattern_len)) {
- log2stderr("FILTER INCLUDE: failed: %s", jb->filter.include.error.txt);
- return false;
- }
- return true;
- }
- bool log_job_exclude_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len) {
- if(jb->filter.exclude.re) {
- log2stderr("FILTER INCLUDE: there is already an exclude filter set");
- return false;
- }
- if(!search_pattern_set(&jb->filter.exclude, pattern, pattern_len)) {
- log2stderr("FILTER EXCLUDE: failed: %s", jb->filter.exclude.error.txt);
- return false;
- }
- return true;
- }
- // ----------------------------------------------------------------------------
- static bool parse_rename(LOG_JOB *jb, const char *param) {
- // Search for '=' in param
- const char *equal_sign = strchr(param, '=');
- if (!equal_sign || equal_sign == param) {
- log2stderr("Error: Invalid rename format, '=' not found in %s", param);
- return false;
- }
- const char *new_key = param;
- size_t new_key_len = equal_sign - new_key;
- const char *old_key = equal_sign + 1;
- size_t old_key_len = strlen(old_key);
- return log_job_rename_add(jb, new_key, new_key_len, old_key, old_key_len);
- }
- static bool is_symbol(char c) {
- return !isalpha(c) && !isdigit(c) && !iscntrl(c);
- }
- struct {
- const char *keyword;
- int action;
- RW_FLAGS flag;
- } rewrite_flags[] = {
- {"match", 1, RW_MATCH_PCRE2},
- {"match", 0, RW_MATCH_NON_EMPTY},
- {"regex", 1, RW_MATCH_PCRE2},
- {"regex", 0, RW_MATCH_NON_EMPTY},
- {"pcre2", 1, RW_MATCH_PCRE2},
- {"pcre2", 0, RW_MATCH_NON_EMPTY},
- {"non_empty", 1, RW_MATCH_NON_EMPTY},
- {"non_empty", 0, RW_MATCH_PCRE2},
- {"non-empty", 1, RW_MATCH_NON_EMPTY},
- {"non-empty", 0, RW_MATCH_PCRE2},
- {"not_empty", 1, RW_MATCH_NON_EMPTY},
- {"not_empty", 0, RW_MATCH_PCRE2},
- {"not-empty", 1, RW_MATCH_NON_EMPTY},
- {"not-empty", 0, RW_MATCH_PCRE2},
- {"stop", 0, RW_DONT_STOP},
- {"no-stop", 1, RW_DONT_STOP},
- {"no_stop", 1, RW_DONT_STOP},
- {"dont-stop", 1, RW_DONT_STOP},
- {"dont_stop", 1, RW_DONT_STOP},
- {"continue", 1, RW_DONT_STOP},
- {"inject", 1, RW_INJECT},
- {"existing", 0, RW_INJECT},
- };
- RW_FLAGS parse_rewrite_flags(const char *options) {
- RW_FLAGS flags = RW_MATCH_PCRE2; // Default option
- // Tokenize the input options using ","
- char *token;
- char *optionsCopy = strdup(options); // Make a copy to avoid modifying the original
- token = strtok(optionsCopy, ",");
- while (token != NULL) {
- // Find the keyword-action mapping
- bool found = false;
- for (size_t i = 0; i < sizeof(rewrite_flags) / sizeof(rewrite_flags[0]); i++) {
- if (strcmp(token, rewrite_flags[i].keyword) == 0) {
- if (rewrite_flags[i].action == 1) {
- flags |= rewrite_flags[i].flag; // Set the flag
- } else {
- flags &= ~rewrite_flags[i].flag; // Unset the flag
- }
- found = true;
- }
- }
- if(!found)
- log2stderr("Warning: rewrite options '%s' is not understood.", token);
- // Get the next token
- token = strtok(NULL, ",");
- }
- free(optionsCopy); // Free the copied string
- return flags;
- }
- static bool parse_rewrite(LOG_JOB *jb, const char *param) {
- // Search for '=' in param
- const char *equal_sign = strchr(param, '=');
- if (!equal_sign || equal_sign == param) {
- log2stderr("Error: Invalid rewrite format, '=' not found in %s", param);
- return false;
- }
- // Get the next character as the separator
- char separator = *(equal_sign + 1);
- if (!separator || !is_symbol(separator)) {
- log2stderr("Error: rewrite separator not found after '=', or is not one of /\\|-# in: %s", param);
- return false;
- }
- // Find the next occurrence of the separator
- const char *second_separator = strchr(equal_sign + 2, separator);
- if (!second_separator) {
- log2stderr("Error: rewrite second separator not found in: %s", param);
- return false;
- }
- // Check if the search pattern is empty
- if (equal_sign + 1 == second_separator) {
- log2stderr("Error: rewrite search pattern is empty in: %s", param);
- return false;
- }
- // Check if the replacement pattern is empty
- if (*(second_separator + 1) == '\0') {
- log2stderr("Error: rewrite replacement pattern is empty in: %s", param);
- return false;
- }
- RW_FLAGS flags = RW_MATCH_PCRE2;
- const char *third_separator = strchr(second_separator + 1, separator);
- if(third_separator)
- flags = parse_rewrite_flags(third_separator + 1);
- // Extract key, search pattern, and replacement pattern
- char *key = strndupz(param, equal_sign - param);
- char *search_pattern = strndupz(equal_sign + 2, second_separator - (equal_sign + 2));
- char *replace_pattern = third_separator ? strndup(second_separator + 1, third_separator - (second_separator + 1)) : strdupz(second_separator + 1);
- if(!*search_pattern)
- flags &= ~RW_MATCH_PCRE2;
- bool ret = log_job_rewrite_add(jb, key, flags, search_pattern, replace_pattern);
- freez(key);
- freez(search_pattern);
- freez(replace_pattern);
- return ret;
- }
- static bool parse_inject(LOG_JOB *jb, const char *value, bool unmatched) {
- const char *equal = strchr(value, '=');
- if (!equal) {
- log2stderr("Error: injection '%s' does not have an equal sign.", value);
- return false;
- }
- const char *key = value;
- const char *val = equal + 1;
- log_job_injection_add(jb, key, equal - key, val, strlen(val), unmatched);
- return true;
- }
- bool log_job_command_line_parse_parameters(LOG_JOB *jb, int argc, char **argv) {
- for (int i = 1; i < argc; i++) {
- char *arg = argv[i];
- if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
- log_job_command_line_help(argv[0]);
- exit(0);
- }
- #if defined(NETDATA_DEV_MODE) || defined(NETDATA_INTERNAL_CHECKS)
- else if(strcmp(arg, "--test") == 0) {
- // logfmt_test();
- json_test();
- exit(1);
- }
- #endif
- else if (strcmp(arg, "--show-config") == 0) {
- jb->show_config = true;
- }
- else {
- char buffer[1024];
- char *param = NULL;
- char *value = NULL;
- char *equal_sign = strchr(arg, '=');
- if (equal_sign) {
- copy_to_buffer(buffer, sizeof(buffer), arg, equal_sign - arg);
- param = buffer;
- value = equal_sign + 1;
- }
- else {
- param = arg;
- if (i + 1 < argc) {
- value = argv[++i];
- }
- else {
- if (!jb->pattern) {
- log_job_pattern_set(jb, arg, strlen(arg));
- continue;
- } else {
- log2stderr("Error: Multiple patterns detected. Specify only one pattern. The first is '%s', the second is '%s'", jb->pattern, arg);
- return false;
- }
- }
- }
- if (strcmp(param, "--filename-key") == 0) {
- if(!log_job_filename_key_set(jb, value, value ? strlen(value) : 0))
- return false;
- }
- else if (strcmp(param, "--prefix") == 0) {
- if(!log_job_key_prefix_set(jb, value, value ? strlen(value) : 0))
- return false;
- }
- #ifdef HAVE_LIBYAML
- else if (strcmp(param, "-f") == 0 || strcmp(param, "--file") == 0) {
- if (!yaml_parse_file(value, jb))
- return false;
- }
- else if (strcmp(param, "-c") == 0 || strcmp(param, "--config") == 0) {
- if (!yaml_parse_config(value, jb))
- return false;
- }
- #endif
- else if (strcmp(param, "--unmatched-key") == 0)
- hashed_key_set(&jb->unmatched.key, value);
- else if (strcmp(param, "--inject") == 0) {
- if (!parse_inject(jb, value, false))
- return false;
- }
- else if (strcmp(param, "--inject-unmatched") == 0) {
- if (!parse_inject(jb, value, true))
- return false;
- }
- else if (strcmp(param, "--rewrite") == 0) {
- if (!parse_rewrite(jb, value))
- return false;
- }
- else if (strcmp(param, "--rename") == 0) {
- if (!parse_rename(jb, value))
- return false;
- }
- else if (strcmp(param, "--include") == 0) {
- if (!log_job_include_pattern_set(jb, value, strlen(value)))
- return false;
- }
- else if (strcmp(param, "--exclude") == 0) {
- if (!log_job_exclude_pattern_set(jb, value, strlen(value)))
- return false;
- }
- else {
- i--;
- if (!jb->pattern) {
- log_job_pattern_set(jb, arg, strlen(arg));
- continue;
- } else {
- log2stderr("Error: Multiple patterns detected. Specify only one pattern. The first is '%s', the second is '%s'", jb->pattern, arg);
- return false;
- }
- }
- }
- }
- // Check if a pattern is set and exactly one pattern is specified
- if (!jb->pattern) {
- log2stderr("Warning: pattern not specified. Try the default config with: -c default");
- log_job_command_line_help(argv[0]);
- return false;
- }
- return true;
- }
|