From 2c3dcbde71d0f8b5785f25edbc669361dc7db23e Mon Sep 17 00:00:00 2001
From: Chris Rienzo <chris@signalwire.com>
Date: Thu, 30 Jul 2020 22:18:45 +0000
Subject: [PATCH] [core, mod_console, mod_graylog2] Add sequence to logs to
 preserve order when timestamp is not precise enough.

---
 src/include/switch_log.h                    | 3 +++
 src/mod/loggers/mod_console/mod_console.c   | 5 ++++-
 src/mod/loggers/mod_graylog2/mod_graylog2.c | 1 +
 src/switch_log.c                            | 6 ++++++
 4 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/src/include/switch_log.h b/src/include/switch_log.h
index 8fb0beae2a..40725a6cca 100644
--- a/src/include/switch_log.h
+++ b/src/include/switch_log.h
@@ -66,6 +66,8 @@ SWITCH_BEGIN_EXTERN_C
 	switch_text_channel_t channel;
 	switch_log_level_t slevel;
 	switch_event_t *tags;
+	/* Log sequence */
+	int64_t sequence;
 } switch_log_node_t;
 
 ///\{
@@ -94,6 +96,7 @@ typedef struct {
 	switch_log_json_format_item_t short_message;
 	const char *custom_field_prefix;
 	double timestamp_divisor;
+	switch_log_json_format_item_t sequence;
 } switch_log_json_format_t;
 
 typedef switch_status_t (*switch_log_function_t) (const switch_log_node_t *node, switch_log_level_t level);
diff --git a/src/mod/loggers/mod_console/mod_console.c b/src/mod/loggers/mod_console/mod_console.c
index 48647f8725..420bf795ab 100644
--- a/src/mod/loggers/mod_console/mod_console.c
+++ b/src/mod/loggers/mod_console/mod_console.c
@@ -77,7 +77,8 @@ static switch_log_json_format_t json_format = {
 	{ "message", NULL }, // full_message
 	{ NULL, NULL }, // short_message
 	"", // custom_field_prefix
-	0.0 // timestamp_divisor
+	0.0, // timestamp_divisor
+	{ "sequence", NULL } // sequence
 };
 
 static char *to_json_string(const switch_log_node_t *node)
@@ -177,6 +178,8 @@ static switch_status_t config_logger(void)
 				json_format.full_message.name = zstr(val) ? NULL : switch_core_strdup(module_pool, val);
 			} else if (!strcasecmp(var, "short-message")) {
 				json_format.short_message.name = zstr(val) ? NULL : switch_core_strdup(module_pool, val);
+			} else if (!strcasecmp(var, "sequence")) {
+				json_format.sequence.name = zstr(val) ? NULL : switch_core_strdup(module_pool, val);
 			}
 		}
 		for (param = switch_xml_child(settings, "config"); param; param = param->next) {
diff --git a/src/mod/loggers/mod_graylog2/mod_graylog2.c b/src/mod/loggers/mod_graylog2/mod_graylog2.c
index 7f46584a38..59fe1202a8 100644
--- a/src/mod/loggers/mod_graylog2/mod_graylog2.c
+++ b/src/mod/loggers/mod_graylog2/mod_graylog2.c
@@ -333,6 +333,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_graylog2_load)
 	globals.gelf_format.full_message.name = "full_message";
 	globals.gelf_format.short_message.name = "short_message";
 	globals.gelf_format.custom_field_prefix = "_";
+	globals.gelf_format.sequence.name = "_sequence";
 
 	switch_event_create_plain(&globals.session_fields, SWITCH_EVENT_CHANNEL_DATA);
 
diff --git a/src/switch_log.c b/src/switch_log.c
index 93fcc5ec37..054e728768 100644
--- a/src/switch_log.c
+++ b/src/switch_log.c
@@ -68,6 +68,8 @@ static int mods_loaded = 0;
 static int console_mods_loaded = 0;
 static switch_bool_t COLORIZE = SWITCH_FALSE;
 
+static int64_t log_sequence = 0;
+
 #ifdef WIN32
 static HANDLE hStdout;
 static WORD wOldColorAttrs;
@@ -144,6 +146,9 @@ SWITCH_DECLARE(cJSON *) switch_log_node_to_json(const switch_log_node_t *node, i
 	if (json_format->function.name && !zstr_buf(node->func)) {
 		cJSON_AddItemToObject(json, json_format->function.name, cJSON_CreateString(node->func));
 	}
+	if (json_format->sequence.name) {
+		cJSON_AddItemToObject(json, json_format->sequence.name, cJSON_CreateNumber(node->sequence));
+	}
 
 	/* skip initial space and new line */
 	if (*full_message == ' ') {
@@ -478,6 +483,7 @@ static void *SWITCH_THREAD_FUNC log_thread(switch_thread_t *t, void *obj)
 
 		node = (switch_log_node_t *) pop;
 		switch_mutex_lock(BINDLOCK);
+		node->sequence = ++log_sequence;
 		for (binding = BINDINGS; binding; binding = binding->next) {
 			if (binding->level >= node->level) {
 				binding->function(node, node->level);