summaryrefslogtreecommitdiffstats
path: root/collectors/log2journal/log2journal.h
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/log2journal/log2journal.h')
-rw-r--r--collectors/log2journal/log2journal.h375
1 files changed, 242 insertions, 133 deletions
diff --git a/collectors/log2journal/log2journal.h b/collectors/log2journal/log2journal.h
index bea75f00ed..7ef805139b 100644
--- a/collectors/log2journal/log2journal.h
+++ b/collectors/log2journal/log2journal.h
@@ -15,31 +15,6 @@
#include <ctype.h>
#include <stdarg.h>
-#define XXH_INLINE_ALL
-#include "../../libnetdata/xxhash.h"
-
-#define PCRE2_CODE_UNIT_WIDTH 8
-#include <pcre2.h>
-
-#ifdef HAVE_LIBYAML
-#include <yaml.h>
-#endif
-
-
-#define MAX_OUTPUT_KEYS 1024
-#define OVECCOUNT (MAX_OUTPUT_KEYS * 3) // should be a multiple of 3
-#define MAX_LINE_LENGTH (1024 * 1024)
-#define MAX_KEY_DUPS (MAX_OUTPUT_KEYS / 2)
-#define MAX_INJECTIONS (MAX_OUTPUT_KEYS / 2)
-#define MAX_REWRITES (MAX_OUTPUT_KEYS / 2)
-#define MAX_RENAMES (MAX_OUTPUT_KEYS / 2)
-#define MAX_KEY_DUPS_KEYS 20
-
-#define MAX_KEY_LEN 64 // according to systemd-journald
-#define MAX_VALUE_LEN (48 * 1024) // according to systemd-journald
-
-#define LOG2JOURNAL_CONFIG_PATH LIBCONFIG_DIR "/log2journal.d"
-
// ----------------------------------------------------------------------------
// logging
@@ -65,6 +40,12 @@ static inline void *mallocz(size_t size) {
return ptr;
}
+static inline void *callocz(size_t elements, size_t size) {
+ void *ptr = mallocz(elements * size);
+ memset(ptr, 0, elements * size);
+ return ptr;
+}
+
static inline char *strdupz(const char *s) {
char *ptr = strdup(s);
if (!ptr) {
@@ -90,6 +71,38 @@ static inline void freez(void *ptr) {
// ----------------------------------------------------------------------------
+#define XXH_INLINE_ALL
+#include "../../libnetdata/xxhash.h"
+#include "../../libnetdata/simple_hashtable.h"
+
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
+#ifdef HAVE_LIBYAML
+#include <yaml.h>
+#endif
+
+#define MAX_OUTPUT_KEYS 1024
+#define MAX_LINE_LENGTH (1024 * 1024)
+#define MAX_KEY_DUPS (MAX_OUTPUT_KEYS / 2)
+#define MAX_INJECTIONS (MAX_OUTPUT_KEYS / 2)
+#define MAX_REWRITES (MAX_OUTPUT_KEYS / 2)
+#define MAX_RENAMES (MAX_OUTPUT_KEYS / 2)
+#define MAX_KEY_DUPS_KEYS 20
+
+#define JOURNAL_MAX_KEY_LEN 64 // according to systemd-journald
+#define JOURNAL_MAX_VALUE_LEN (48 * 1024) // according to systemd-journald
+
+#define LOG2JOURNAL_CONFIG_PATH LIBCONFIG_DIR "/log2journal.d"
+
+// ----------------------------------------------------------------------------
+// character conversion for journal keys
+
+extern const char journal_key_characters_map[256];
+
+// ----------------------------------------------------------------------------
+// copy to buffer, while ensuring there is no buffer overflow
+
static inline size_t copy_to_buffer(char *dst, size_t dst_size, const char *src, size_t src_len) {
if(dst_size < 2) {
if(dst_size == 1)
@@ -111,198 +124,294 @@ static inline size_t copy_to_buffer(char *dst, size_t dst_size, const char *src,
}
// ----------------------------------------------------------------------------
+// A dynamically sized, reusable text buffer,
+// allowing us to be fast (no allocations during iterations) while having the
+// smallest possible allocations.
typedef struct txt {
- char *s;
+ char *txt;
size_t size;
} TEXT;
-static inline void txt_replace(TEXT *txt, const char *s, size_t len) {
+static inline void txt_cleanup(TEXT *t) {
+ if(!t)
+ return;
+
+ if(t->txt)
+ freez(t->txt);
+
+ t->txt = NULL;
+ t->size = 0;
+}
+
+static inline void txt_replace(TEXT *t, const char *s, size_t len) {
if(!s || !*s || len == 0) {
s = "";
len = 0;
}
- if(len + 1 <= txt->size) {
+ if(len + 1 <= t->size) {
// the existing value allocation, fits our value
- memcpy(txt->s, s, len);
- txt->s[len] = '\0';
+ memcpy(t->txt, s, len);
+ t->txt[len] = '\0';
}
else {
// no existing value allocation, or too small for our value
+ // cleanup and increase the buffer
- if(txt->s)
- freez(txt->s);
+ txt_cleanup(t);
- txt->s = strndupz(s, len);
- txt->size = len + 1;
+ t->txt = strndupz(s, len);
+ t->size = len + 1;
}
}
// ----------------------------------------------------------------------------
-typedef struct key_value {
- char key[MAX_KEY_LEN + 1];
- TEXT value;
- bool on_unmatched;
-} KEY_VALUE;
+typedef enum __attribute__((__packed__)) {
+ HK_NONE = 0,
+ HK_ALLOCATED = (1 << 0),
+ HK_FILTERED = (1 << 1),
+ HK_FILTERED_INCLUDED = (1 << 2),
+ HK_COLLISION_CHECKED = (1 << 3),
+ HK_RENAMES_CHECKED = (1 << 4),
+ HK_HAS_RENAMES = (1 << 5),
+ HK_DUPS_CHECKED = (1 << 6),
+ HK_HAS_DUPS = (1 << 7),
+ HK_REWRITES_CHECKED = (1 << 8),
+ HK_HAS_REWRITES = (1 << 9),
+} HASHED_KEY_FLAGS;
+
+typedef struct hashed_key {
+ const char *key;
+ uint32_t len;
+ HASHED_KEY_FLAGS flags;
+ XXH64_hash_t hash;
+} HASHED_KEY;
+
+static inline void hashed_key_cleanup(HASHED_KEY *k) {
+ if(k->key) {
+ freez((void *)k->key);
+ k->key = NULL;
+ }
+}
+
+static inline void hashed_key_set(HASHED_KEY *k, const char *name) {
+ hashed_key_cleanup(k);
+
+ k->key = strdupz(name);
+ k->len = strlen(k->key);
+ k->hash = XXH3_64bits(k->key, k->len);
+ k->flags = HK_NONE;
+}
-static inline void key_value_replace(KEY_VALUE *kv, const char *key, size_t key_len, const char *value, size_t value_len) {
- copy_to_buffer(kv->key, sizeof(kv->key), key, key_len);
- txt_replace(&kv->value, value, value_len);
+static inline void hashed_key_len_set(HASHED_KEY *k, const char *name, size_t len) {
+ hashed_key_cleanup(k);
+
+ k->key = strndupz(name, len);
+ k->len = len;
+ k->hash = XXH3_64bits(k->key, k->len);
+ k->flags = HK_NONE;
}
// ----------------------------------------------------------------------------
-struct key_dup {
- XXH64_hash_t hash;
- char *target;
- char *keys[MAX_KEY_DUPS_KEYS];
- TEXT values[MAX_KEY_DUPS_KEYS];
- size_t used;
- bool exposed;
-};
+typedef struct search_pattern {
+ const char *pattern;
+ pcre2_code *re;
+ pcre2_match_data *match_data;
+ TEXT error;
+} SEARCH_PATTERN;
+
+void search_pattern_cleanup(SEARCH_PATTERN *sp);
+bool search_pattern_set(SEARCH_PATTERN *sp, const char *search_pattern, size_t search_pattern_len);
-struct key_rename {
- XXH64_hash_t new_hash;
- XXH64_hash_t old_hash;
- char *new_key;
- char *old_key;
-};
+static inline bool search_pattern_matches(SEARCH_PATTERN *sp, const char *value, size_t value_len) {
+ return pcre2_match(sp->re, (PCRE2_SPTR)value, value_len, 0, 0, sp->match_data, NULL) >= 0;
+}
+
+// ----------------------------------------------------------------------------
-struct replacement_node {
+typedef struct replacement_node {
+ HASHED_KEY name;
bool is_variable;
- const char *s;
- size_t len;
+ bool logged_error;
+
struct replacement_node *next;
-};
+} REPLACE_NODE;
-struct key_rewrite {
- XXH64_hash_t hash;
- char *key;
- char *search_pattern;
- char *replace_pattern;
- pcre2_code *re;
- pcre2_match_data *match_data;
- struct replacement_node *nodes;
-};
+void replace_node_free(REPLACE_NODE *rpn);
+
+typedef struct replace_pattern {
+ const char *pattern;
+ REPLACE_NODE *nodes;
+} REPLACE_PATTERN;
+
+void replace_pattern_cleanup(REPLACE_PATTERN *rp);
+bool replace_pattern_set(REPLACE_PATTERN *rp, const char *pattern);
+
+// ----------------------------------------------------------------------------
+
+typedef struct injection {
+ bool on_unmatched;
+ TEXT value;
+ HASHED_KEY key;
+} INJECTION;
+
+void injection_cleanup(INJECTION *inj);
+
+// ----------------------------------------------------------------------------
+
+typedef struct duplication {
+ HASHED_KEY target;
+ uint32_t used;
+ bool exposed;
+ HASHED_KEY keys[MAX_KEY_DUPS_KEYS];
+ TEXT values[MAX_KEY_DUPS_KEYS];
+} DUPLICATION;
+
+void duplication_cleanup(DUPLICATION *dp);
+
+// ----------------------------------------------------------------------------
-struct log_job {
+typedef struct key_rename {
+ HASHED_KEY new_key;
+ HASHED_KEY old_key;
+} RENAME;
+
+void rename_cleanup(RENAME *rn);
+
+// ----------------------------------------------------------------------------
+
+typedef struct key_rewrite {
+ HASHED_KEY key;
+ SEARCH_PATTERN search;
+ REPLACE_PATTERN replace;
+} REWRITE;
+
+void rewrite_cleanup(REWRITE *rw);
+
+// ----------------------------------------------------------------------------
+// A job configuration and runtime structures
+
+typedef struct log_job {
bool show_config;
const char *pattern;
const char *prefix;
+ SIMPLE_HASHTABLE hashtable;
+
+ struct {
+ SEARCH_PATTERN include;
+ SEARCH_PATTERN exclude;
+ } filter;
+
struct {
+ bool last_line_was_empty;
const char *key;
char current[FILENAME_MAX + 1];
- bool last_line_was_empty;
} filename;
struct {
- KEY_VALUE keys[MAX_INJECTIONS];
- size_t used;
+ uint32_t used;
+ INJECTION keys[MAX_INJECTIONS];
} injections;
struct {
const char *key;
struct {
- KEY_VALUE keys[MAX_INJECTIONS];
- size_t used;
+ uint32_t used;
+ INJECTION keys[MAX_INJECTIONS];
} injections;
} unmatched;
struct {
- struct key_dup array[MAX_KEY_DUPS];
- size_t used;
+ uint32_t used;
+ DUPLICATION array[MAX_KEY_DUPS];
} dups;
struct {
- struct key_rewrite array[MAX_REWRITES];
- size_t used;
+ uint32_t used;
+ REWRITE array[MAX_REWRITES];
} rewrites;
struct {
- struct key_rename array[MAX_RENAMES];
- size_t used;
+ uint32_t used;
+ RENAME array[MAX_RENAMES];
} renames;
-};
+} LOG_JOB;
-void jb_send_key_value_and_rewrite(struct log_job *jb, const char *key, XXH64_hash_t hash, const char *value, size_t len);
-void jb_send_duplications_for_key(struct log_job *jb, const char *key, XXH64_hash_t hash, const char *value, size_t value_len);
-void jb_send_extracted_key_value(struct log_job *jb, const char *key, const char *value, size_t len);
+// free all resources consumed by the log job
+void nd_log_cleanup(LOG_JOB *jb);
-struct key_dup *log_job_add_duplication_to_job(struct log_job *jb, const char *target, size_t target_len);
-bool log_job_add_key_to_duplication(struct key_dup *kd, const char *key, size_t key_len);
-bool log_job_add_filename_key(struct log_job *jb, const char *key, size_t key_len);
-bool log_job_add_key_prefix(struct log_job *jb, const char *prefix, size_t prefix_len);
-bool log_job_add_injection(struct log_job *jb, const char *key, size_t key_len, const char *value, size_t value_len, bool unmatched);
-bool log_job_add_rewrite(struct log_job *jb, const char *key, const char *search_pattern, const char *replace_pattern);
-bool log_job_add_rename(struct log_job *jb, const char *new_key, size_t new_key_len, const char *old_key, size_t old_key_len);
+// ----------------------------------------------------------------------------
-// entry point to parse command line parameters
-bool parse_log2journal_parameters(struct log_job *jb, int argc, char **argv);
+// the entry point to send key value pairs to the output
+// this implements the pipeline of processing renames, rewrites and duplications
+void log_job_send_extracted_key_value(LOG_JOB *jb, const char *key, const char *value, size_t len);
-void log2journal_command_line_help(const char *name);
+// ----------------------------------------------------------------------------
+// configuration related
+
+// management of configuration to set settings
+DUPLICATION *log_job_duplication_add(LOG_JOB *jb, const char *target, size_t target_len);
+bool log_job_duplication_key_add(DUPLICATION *kd, const char *key, size_t key_len);
+bool log_job_filename_key_set(LOG_JOB *jb, const char *key, size_t key_len);
+bool log_job_key_prefix_set(LOG_JOB *jb, const char *prefix, size_t prefix_len);
+bool log_job_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len);
+bool log_job_injection_add(LOG_JOB *jb, const char *key, size_t key_len, const char *value, size_t value_len, bool unmatched);
+bool log_job_rewrite_add(LOG_JOB *jb, const char *key, const char *search_pattern, const char *replace_pattern);
+bool log_job_rename_add(LOG_JOB *jb, const char *new_key, size_t new_key_len, const char *old_key, size_t old_key_len);
+bool log_job_include_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len);
+bool log_job_exclude_pattern_set(LOG_JOB *jb, const char *pattern, size_t pattern_len);
-// free all resources consumed by the log job
-void nd_log_destroy(struct log_job *jb);
+// entry point to parse command line parameters
+bool log_job_command_line_parse_parameters(LOG_JOB *jb, int argc, char **argv);
+void log_job_command_line_help(const char *name);
+
+// ----------------------------------------------------------------------------
+// YAML configuration related
#ifdef HAVE_LIBYAML
-bool yaml_parse_file(const char *config_file_path, struct log_job *jb);
-bool yaml_parse_config(const char *config_name, struct log_job *jb);
+bool yaml_parse_file(const char *config_file_path, LOG_JOB *jb);
+bool yaml_parse_config(const char *config_name, LOG_JOB *jb);
#endif
-void log_job_to_yaml(struct log_job *jb);
+void log_job_configuration_to_yaml(LOG_JOB *jb);
+
+// ----------------------------------------------------------------------------
+// JSON parser
typedef struct log_json_state LOG_JSON_STATE;
-LOG_JSON_STATE *json_parser_create(struct log_job *jb);
+LOG_JSON_STATE *json_parser_create(LOG_JOB *jb);
void json_parser_destroy(LOG_JSON_STATE *js);
const char *json_parser_error(LOG_JSON_STATE *js);
bool json_parse_document(LOG_JSON_STATE *js, const char *txt);
void json_test(void);
+// ----------------------------------------------------------------------------
+// logfmt parser
+
typedef struct logfmt_state LOGFMT_STATE;
-LOGFMT_STATE *logfmt_parser_create(struct log_job *jb);
+LOGFMT_STATE *logfmt_parser_create(LOG_JOB *jb);
void logfmt_parser_destroy(LOGFMT_STATE *lfs);
const char *logfmt_parser_error(LOGFMT_STATE *lfs);
bool logfmt_parse_document(LOGFMT_STATE *js, const char *txt);
void logfmt_test(void);
// ----------------------------------------------------------------------------
-// PCRE2 patters handling
-
-static inline pcre2_code *jb_compile_pcre2_pattern(const char *pattern) {
- int error_number;
- PCRE2_SIZE error_offset;
- PCRE2_SPTR pattern_ptr = (PCRE2_SPTR)pattern;
-
- pcre2_code *re = pcre2_compile(pattern_ptr, PCRE2_ZERO_TERMINATED, 0, &error_number, &error_offset, NULL);
- if (re == NULL) {
- PCRE2_UCHAR errbuf[1024];
- pcre2_get_error_message(error_number, errbuf, sizeof(errbuf));
- log2stderr("PCRE2 compilation failed at offset %d: %s", (int)error_offset, errbuf);
- log2stderr("Check for common regex syntax errors or unsupported PCRE2 patterns.");
- return NULL;
- }
-
- return re;
-}
+// pcre2 parser
-static inline bool jb_pcre2_match(pcre2_code *re, pcre2_match_data *match_data, char *line, size_t len, bool log) {
- int rc = pcre2_match(re, (PCRE2_SPTR)line, len, 0, 0, match_data, NULL);
- if(rc < 0) {
- PCRE2_UCHAR errbuf[1024];
- pcre2_get_error_message(rc, errbuf, sizeof(errbuf));
+typedef struct pcre2_state PCRE2_STATE;
+PCRE2_STATE *pcre2_parser_create(LOG_JOB *jb);
+void pcre2_parser_destroy(PCRE2_STATE *pcre2);
+const char *pcre2_parser_error(PCRE2_STATE *pcre2);
+bool pcre2_parse_document(PCRE2_STATE *pcre2, const char *txt, size_t len);
+bool pcre2_has_error(PCRE2_STATE *pcre2);
+void pcre2_test(void);
- if(log)
- log2stderr("PCRE2 error %d: %s on: %s", rc, errbuf, line);
-
- return false;
- }
-
- return true;
-}
+void pcre2_get_error_in_buffer(char *msg, size_t msg_len, int rc, int pos);
#endif //NETDATA_LOG2JOURNAL_H