From 6bcff2b5ffa48b96ff033cd1e0356c6dcba2eafc Mon Sep 17 00:00:00 2001
From: Roman Khabibov <roman.habibov@tarantool.org>
Date: Sat, 2 Mar 2019 20:12:11 +0300
Subject: [PATCH] say: fix assertion in log_format when called for boot or
 syslog logger

It's OK to use json format with the boot logger. As for syslog, let's
add a check to Lua's log_format() so that it fails gracefully rather
than raising an assertion.

Closes #3946
---
 extra/exports                |  1 +
 src/lib/core/say.c           | 10 +++++++---
 src/lib/core/say.h           |  7 +++++++
 src/lua/log.lua              | 15 +++++++++++++++
 test/app-tap/logger.test.lua |  6 +++++-
 5 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/extra/exports b/extra/exports
index d724211235..21fa9bf006 100644
--- a/extra/exports
+++ b/extra/exports
@@ -65,6 +65,7 @@ mp_encode_float
 mp_decode_double
 mp_decode_float
 
+log_type
 say_set_log_level
 say_logrotate
 say_set_log_format
diff --git a/src/lib/core/say.c b/src/lib/core/say.c
index 50ee556929..68aa92f611 100644
--- a/src/lib/core/say.c
+++ b/src/lib/core/say.c
@@ -161,6 +161,12 @@ level_to_syslog_priority(int level)
 	}
 }
 
+enum say_logger_type
+log_type()
+{
+	return log_default->type;
+}
+
 void
 log_set_level(struct log *log, enum say_level level)
 {
@@ -171,9 +177,7 @@ void
 log_set_format(struct log *log, log_format_func_t format_func)
 {
 	assert(format_func == say_format_plain ||
-	       log->type == SAY_LOGGER_STDERR ||
-	       log->type == SAY_LOGGER_PIPE || log->type == SAY_LOGGER_FILE);
-
+	       log->type != SAY_LOGGER_SYSLOG);
 	log->format_func = format_func;
 }
 
diff --git a/src/lib/core/say.h b/src/lib/core/say.h
index 70050362c3..d26c3ddefa 100644
--- a/src/lib/core/say.h
+++ b/src/lib/core/say.h
@@ -195,6 +195,13 @@ int
 log_say(struct log *log, int level, const char *filename,
 	int line, const char *error, const char *format, ...);
 
+/**
+ * Default logger type info.
+ * @retval say_logger_type.
+ */
+enum say_logger_type
+log_type();
+
 /**
  * Set log level. Can be used dynamically.
  *
diff --git a/src/lua/log.lua b/src/lua/log.lua
index 0ac0e8f261..312c14d5eb 100644
--- a/src/lua/log.lua
+++ b/src/lua/log.lua
@@ -4,6 +4,18 @@ local ffi = require('ffi')
 ffi.cdef[[
     typedef void (*sayfunc_t)(int level, const char *filename, int line,
                const char *error, const char *format, ...);
+
+    enum say_logger_type {
+        SAY_LOGGER_BOOT,
+        SAY_LOGGER_STDERR,
+        SAY_LOGGER_FILE,
+        SAY_LOGGER_PIPE,
+        SAY_LOGGER_SYSLOG
+    };
+
+    enum say_logger_type
+    log_type();
+
     void
     say_set_log_level(int new_level);
 
@@ -117,6 +129,9 @@ end
 
 local function log_format(format_name)
     if format_name == "json" then
+        if ffi.C.log_type() == ffi.C.SAY_LOGGER_SYSLOG then
+            error("log_format: 'json' can't be used with syslog logger")
+        end
         ffi.C.say_set_log_format(ffi.C.SF_JSON)
     elseif format_name == "plain" then
         ffi.C.say_set_log_format(ffi.C.SF_PLAIN)
diff --git a/test/app-tap/logger.test.lua b/test/app-tap/logger.test.lua
index 0c11702c8b..492d5ea0b4 100755
--- a/test/app-tap/logger.test.lua
+++ b/test/app-tap/logger.test.lua
@@ -3,6 +3,11 @@
 local test = require('tap').test('log')
 test:plan(24)
 
+-- gh-3946: Assertion failure when using log_format() before box.cfg()
+local log = require('log')
+log.log_format('json')
+log.log_format('plain')
+
 --
 -- Check that Tarantool creates ADMIN session for #! script
 --
@@ -12,7 +17,6 @@ box.cfg{
     log=filename,
     memtx_memory=107374182,
 }
-local log = require('log')
 local fio = require('fio')
 local json = require('json')
 local fiber = require('fiber')
-- 
GitLab