// Dlog
#include "deduplicate.h"
#include "hash.h"
+#include "logcommon.h"
+#include "parsers.h"
-bool (*deduplicate_func)(const char *, size_t, struct timespec *);
+#define WARNING_STRING " LOG DUPLICATED %d TIMES"
+#define WARNING_MAX sizeof(" LOG DUPLICATED " STRINGIFY(INT32_MAX) " TIMES")
+
+typedef struct deduplicate_log {
+ uint32_t hash;
+ size_t quantity;
+} deduplicate_log;
+
+dlog_deduplicate_e (*deduplicate_func)(const char *, size_t, struct timespec *);
-static uint32_t basic_hash;
static long last_millisec;
static long interval_millisec;
static int known_hashes_capacity;
-static uint32_t *known_hashes_vector;
+static deduplicate_log *known_hashes_vector;
static int known_hashes_size = 0;
static pthread_mutex_t deduplication_lock = PTHREAD_MUTEX_INITIALIZER;
+static int warn_quantity;
+static int warning_size;
+static char warning_content[WARNING_MAX];
+static deduplicate_log basic_log;
static void refresh_deduplication_limits()
{
known_hashes_size = 0;
}
-static bool is_hash_known(const uint32_t new_hash)
+static size_t *known_hash_count(const uint32_t new_hash)
{
for (size_t i = 0; i < known_hashes_size; i++)
- if (known_hashes_vector[i] == new_hash)
- return true;
+ if (known_hashes_vector[i].hash == new_hash)
+ return &known_hashes_vector[i].quantity;
- return false;
+ return NULL;
}
static bool compare_milli(struct timespec *tp)
return false;
}
-static bool basic_deduplicate(const char *msg, size_t len, struct timespec *tp)
+static dlog_deduplicate_e basic_deduplicate(const char *msg, size_t len, struct timespec *tp)
{
const uint32_t new_hash = create_hash(msg, len);
- bool compare_hash = (basic_hash == new_hash);
- basic_hash = new_hash;
+ bool compare_hash = (basic_log.hash == new_hash);
bool compare_milisec = compare_milli(tp);
- return compare_hash && compare_milisec;
+ if (compare_hash && compare_milisec) {
+ basic_log.quantity++;
+ if (warn_quantity != 0 && (basic_log.quantity % warn_quantity == 0))
+ return DLOG_DO_NOT_DEDUPLICATE_BUT_WARN;
+ return DLOG_DEDUPLICATE;
+ } else {
+ basic_log.quantity = 1;
+ basic_log.hash = new_hash;
+ }
+
+ return DLOG_DO_NOT_DEDUPLICATE;
}
static bool add_known_hash(uint32_t new_hash)
known_hashes_capacity *= 2;
known_hashes_vector = temp;
}
- known_hashes_vector[known_hashes_size] = new_hash;
+ known_hashes_vector[known_hashes_size].hash = new_hash;
+ known_hashes_vector[known_hashes_size].quantity = 1;
known_hashes_size++;
return true;
}
-static bool advanced_deduplicate(const char *msg, size_t len, struct timespec *tp)
+static dlog_deduplicate_e advanced_deduplicate(const char *msg, size_t len, struct timespec *tp)
{
pthread_mutex_lock(&deduplication_lock);
bool compare_milisec = compare_milli(tp);
uint32_t new_hash = create_hash(msg, len);
- int ret = false;
-
- if (compare_milisec)
- ret = is_hash_known(new_hash);
- else
+ size_t *quantity_ptr = NULL;
+ dlog_deduplicate_e output = DLOG_DO_NOT_DEDUPLICATE;
+
+ if (compare_milisec) {
+ quantity_ptr = known_hash_count(new_hash);
+ if (quantity_ptr != NULL) {
+ *quantity_ptr += 1;
+ output = DLOG_DEDUPLICATE;
+ if (warn_quantity != 0 && (*quantity_ptr % warn_quantity == 0))
+ output = DLOG_DO_NOT_DEDUPLICATE_BUT_WARN;
+ }
+ } else {
refresh_deduplication_limits();
+ }
- if (ret == false)
+ if (quantity_ptr == NULL)
add_known_hash(new_hash);
pthread_mutex_unlock(&deduplication_lock);
- return ret;
+ return output;
+}
+
+void deduplicate_warn(char *buf, size_t size, size_t len)
+{
+ assert(size > warning_size);
+
+ if (len + warning_size < size)
+ strncpy(buf + len, warning_content, size - len);
+ else
+ strncpy(buf + size - warning_size - 1, warning_content, warning_size + 1);
}
void __configure_deduplicate(struct log_config *config)
const char *const value = log_config_get(config, "deduplicate_method");
interval_millisec = log_config_get_int(config, "deduplicate_interval_ms", 1);
+ const char *warn_quant_str = log_config_get(config, "deduplicate_warn_quantity");
+ if (!warn_quant_str)
+ warn_quantity = 10;
+ else if (parse_number(&warn_quant_str, &warn_quantity) < 0 || (warn_quantity < 0))
+ warn_quantity = 0;
+
+ warning_size = snprintf(warning_content, sizeof warning_content, WARNING_STRING, warn_quantity);
+ assert(warning_size < (sizeof warning_content));
+ if (warning_size < 0)
+ return;
+
if (!value) {
return;
} else if (strcmp(value, "only_identical_neighbours") == 0) {
deduplicate_func = basic_deduplicate;
} else if (strcmp(value, "all_identical_logs") == 0) {
known_hashes_capacity = 4;
- known_hashes_vector = (uint32_t *) calloc(known_hashes_capacity, sizeof *known_hashes_vector);
+ known_hashes_vector = (deduplicate_log *) calloc(known_hashes_capacity, sizeof *known_hashes_vector);
if (!known_hashes_vector)
return;
deduplicate_func = advanced_deduplicate;
#include "libdlog.h"
#include "logconfig.h"
+#define DEDUPLICATE 0
+#define WARN 0xBA5EBALL
+#define PRINT 0xC0FFEE
+
long milliseconds;
const char *local_advanced;
const char *local_time_ms;
+const char *local_warn_quantity;
+bool deduplicate_warning = false;
+
+static int use_real_deduplicate_warn = false;
+void __real_deduplicate_warn(char *buf, size_t size, size_t len);
+void __wrap_deduplicate_warn(char *buf, size_t size, size_t len)
+{
+ if (use_real_deduplicate_warn)
+ __real_deduplicate_warn(buf, size, len);
+ else
+ deduplicate_warning = true;
+}
int __wrap_clock_gettime(clockid_t clk_id, struct timespec *tp)
{
int log_handler(log_id_t buf_id, log_priority pri, const char *tag, const char *msg, struct timespec *tp)
{
- return 0xC0FFEE;
+ if (deduplicate_warning) {
+ deduplicate_warning = false;
+ return WARN;
+ }
+
+ return PRINT;
}
void __dlog_init_pipe(const struct log_config *conf)
log_config_set(config, "debugmode", "1");
log_config_set(config, "deduplicate_method", local_advanced);
log_config_set(config, "deduplicate_interval_ms", local_time_ms);
+ log_config_set(config, "deduplicate_warn_quantity", local_warn_quantity);
return 0;
}
{
local_advanced = "only_identical_neighbours";
local_time_ms = "1";
+ local_warn_quantity = "0";
milliseconds = 123;
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("B", 0);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("C", 0xC0FFEE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
milliseconds = 124;
- check_assertion("C", 0xC0FFEE);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("C", 0xC0FFEE);
- check_assertion("C", 0);
- check_assertion("C", 0);
+ check_assertion("C", PRINT);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
__dlog_fini();
}
{
local_advanced = "only_identical_neighbours";
local_time_ms = "10";
+ local_warn_quantity = "0";
milliseconds = 123;
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("B", 0);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("C", 0xC0FFEE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
milliseconds = 124;
- check_assertion("C", 0);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("C", 0xC0FFEE);
- check_assertion("C", 0);
- check_assertion("C", 0);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
milliseconds = 133;
- check_assertion("C", 0xC0FFEE);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("C", 0xC0FFEE);
- check_assertion("C", 0);
- check_assertion("C", 0);
+ check_assertion("C", PRINT);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+
+ __dlog_fini();
+}
+
+void test_basic_1ms_interval_warning()
+{
+ local_advanced = "only_identical_neighbours";
+ local_time_ms = "10";
+ local_warn_quantity = "10";
+ milliseconds = 123;
+ check_assertion("A", PRINT);
+ for (int i = 0; i < 29; ++i) {
+ if (i == 0)
+ check_assertion("B", PRINT);
+ else if ((i + 1) % atoi(local_warn_quantity) == 0)
+ check_assertion("B", WARN);
+ else
+ check_assertion("B", DEDUPLICATE);
+ }
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("C", PRINT);
__dlog_fini();
}
{
local_advanced = "all_identical_logs";
local_time_ms = "1";
+ local_warn_quantity = "0";
milliseconds = 123;
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("B", 0);
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("C", 0xC0FFEE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", PRINT);
milliseconds = 124;
- check_assertion("C", 0xC0FFEE);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("A", 0);
- check_assertion("C", 0);
- check_assertion("C", 0);
+ check_assertion("C", PRINT);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
__dlog_fini();
}
{
local_advanced = "all_identical_logs";
local_time_ms = "10";
+ local_warn_quantity = "0";
+ milliseconds = 123;
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", PRINT);
+
+ milliseconds = 124;
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+
+ milliseconds = 132;
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+
+ milliseconds = 133;
+ check_assertion("C", PRINT);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+
+ __dlog_fini();
+}
+
+void test_advanced_10ms_interval_warning()
+{
+ local_advanced = "all_identical_logs";
+ local_time_ms = "10";
+ local_warn_quantity = "5";
milliseconds = 123;
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("B", 0);
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("C", 0xC0FFEE);
+ check_assertion("A", PRINT);
+ check_assertion("B", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", PRINT);
milliseconds = 124;
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("B", 0);
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("C", 0);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", WARN);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
milliseconds = 132;
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("B", 0);
- check_assertion("A", 0);
- check_assertion("B", 0);
- check_assertion("C", 0);
+ check_assertion("A", WARN);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", WARN);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", WARN);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
milliseconds = 133;
- check_assertion("C", 0xC0FFEE);
- check_assertion("A", 0xC0FFEE);
- check_assertion("B", 0xC0FFEE);
- check_assertion("A", 0);
- check_assertion("C", 0);
- check_assertion("C", 0);
+ check_assertion("B", PRINT);
+ check_assertion("A", PRINT);
+ check_assertion("C", PRINT);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", WARN);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("B", DEDUPLICATE);
+ check_assertion("A", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
+ check_assertion("C", DEDUPLICATE);
__dlog_fini();
}
{
local_advanced = "all_identical_logs";
local_time_ms = "1";
+ local_warn_quantity = "0";
milliseconds = 123;
char word[3] = {'\0'};
for (char first = 'A'; first <= 'Z'; ++first) {
word[0] = first;
for (char second = 'A'; second <= 'Z'; ++second) {
word[1] = second;
- check_assertion(word, 0xC0FFEE);
+ check_assertion(word, PRINT);
}
}
{
local_advanced = "all_identical_logs";
local_time_ms = "1";
+ local_warn_quantity = "0";
char msg[4];
for (milliseconds = 500; milliseconds < 900; milliseconds += 50) {
for (int i = 0; i < 1500; ++i) {
int index = random() % 1000;
snprintf(msg, sizeof msg, "%d", index);
- check_assertion(msg, already_used[index] ? 0 : 0xC0FFEE);
+ check_assertion(msg, already_used[index] ? 0 : PRINT);
already_used[index] = true;
}
}
__dlog_fini();
}
+void test_deduplicate_warn()
+{
+ use_real_deduplicate_warn = true;
+ local_warn_quantity = "11";
+ __configure();
+ char basic_log[25] = "This is a log,";
+ deduplicate_warn(basic_log, sizeof basic_log, strlen(basic_log));
+ assert(strcmp(basic_log, " LOG DUPLICATED 11 TIMES") == 0);
+ __dlog_fini();
+
+ local_warn_quantity = "17";
+ __configure();
+ char basic_log2[37] = "A completely different message,";
+ deduplicate_warn(basic_log2, sizeof basic_log2, strlen(basic_log2));
+ assert(strcmp(basic_log2, "A completely LOG DUPLICATED 17 TIMES") == 0);
+ __dlog_fini();
+
+ local_warn_quantity = "7";
+ __configure();
+ char basic_log3[31] = "This is a very long log,";
+ deduplicate_warn(basic_log3, sizeof basic_log3, strlen(basic_log3));
+ assert(strcmp(basic_log3, "This is LOG DUPLICATED 7 TIMES") == 0);
+ __dlog_fini();
+
+ local_warn_quantity = "14";
+ __configure();
+ char basic_log4[100] = "This is a log,";
+ deduplicate_warn(basic_log4, sizeof basic_log4, strlen(basic_log4));
+ assert(strcmp(basic_log4, "This is a log, LOG DUPLICATED 14 TIMES") == 0);
+
+ local_warn_quantity = "xyz";
+ __configure();
+ for (int i = 0; i < 12; ++i) {
+ if (i == 0)
+ check_assertion("B", PRINT);
+ else
+ check_assertion("B", DEDUPLICATE);
+ }
+
+ local_warn_quantity = "-1";
+ __configure();
+ for (int i = 0; i < 12; ++i) {
+ if (i == 0)
+ check_assertion("B", PRINT);
+ else
+ check_assertion("B", DEDUPLICATE);
+ }
+
+ local_warn_quantity = "";
+ __configure();
+ for (int i = 0; i < 12; ++i) {
+ if (i == 0)
+ check_assertion("B", PRINT);
+ else
+ check_assertion("B", DEDUPLICATE);
+ }
+
+ use_real_deduplicate_warn = false;
+ __dlog_fini();
+}
+
+void test_deduplicate_warn_random()
+{
+ use_real_deduplicate_warn = false;
+ local_advanced = "only_identical_neighbours";
+ local_time_ms = "10";
+ local_warn_quantity = "10";
+ milliseconds = 123;
+
+ srand(time(NULL));
+
+ for (int i = 0; i < 10; ++i) {
+ milliseconds++;
+ for (char c = 'A'; c <= 'Z'; ++c) {
+ int limit = rand() % 34 + 2;
+ for (int j = 0; j < limit; ++j) {
+ char log_text[2];
+ log_text[0] = c;
+ log_text[1] = '\0';
+ if (j == 0)
+ check_assertion(log_text, PRINT);
+ else if ((j + 1) % atoi(local_warn_quantity) == 0)
+ check_assertion(log_text, WARN);
+ else
+ check_assertion(log_text, DEDUPLICATE);
+ }
+ }
+ }
+
+ __dlog_fini();
+}
+
int main()
{
test_basic_1ms_interval();
test_basic_10ms_interval();
+ test_basic_1ms_interval_warning();
test_advanced_1ms_interval();
test_advanced_10ms_interval();
+ test_advanced_10ms_interval_warning();
test_advanced_many_hashes();
test_advanced_many_millisec();
+ test_deduplicate_warn();
+ test_deduplicate_warn_random();
return 0;
}