Tarantool development patches archive
 help / color / mirror / Atom feed
From: Ilya Konyukhov <runsfor@gmail.com>
To: tarantool-patches@freelists.org
Cc: Ilya Konyukhov <runsfor@gmail.com>
Subject: [tarantool-patches] [PATCH] Expose log.init function from log module
Date: Tue, 27 Aug 2019 18:46:42 +0300	[thread overview]
Message-ID: <20190827154640.48315-1-runsfor@gmail.com> (raw)

This now allows to initialize logging subsystem without calling box.cfg.
This is helpful when you want to do something before database
initialization (i.e. setup cluster connections)

Related PR: https://github.com/tarantool/tarantool/pull/4406/files

---
 extra/exports                     |  2 ++
 src/box/lua/load_cfg.lua          | 30 +++++++++++++---
 src/lib/core/say.c                |  3 ++
 src/lib/core/say.h                |  1 +
 src/lua/log.lua                   | 60 +++++++++++++++++++++++++++++++
 test/app-tap/logger_init.test.lua | 42 ++++++++++++++++++++++
 6 files changed, 133 insertions(+), 5 deletions(-)
 create mode 100755 test/app-tap/logger_init.test.lua

diff --git a/extra/exports b/extra/exports
index 7b84a1452..90d690b9c 100644
--- a/extra/exports
+++ b/extra/exports
@@ -52,6 +52,7 @@ tt_uuid_is_equal
 tt_uuid_is_nil
 tt_uuid_bswap
 tt_uuid_from_string
+log_initialized
 log_level
 log_format
 uri_parse
@@ -73,6 +74,7 @@ log_type
 say_set_log_level
 say_logrotate
 say_set_log_format
+say_logger_init
 tarantool_uptime
 tarantool_exit
 log_pid
diff --git a/src/box/lua/load_cfg.lua b/src/box/lua/load_cfg.lua
index d402468ab..175191a8a 100644
--- a/src/box/lua/load_cfg.lua
+++ b/src/box/lua/load_cfg.lua
@@ -6,6 +6,10 @@ local private = require('box.internal')
 local urilib = require('uri')
 local math = require('math')
 local fiber = require('fiber')
+local ffi = require('ffi')
+ffi.cdef[[
+    extern bool log_initialized;
+]]
 
 -- Function decorator that is used to prevent box.cfg() from
 -- being called concurrently by different fibers.
@@ -45,10 +49,6 @@ local default_cfg = {
     vinyl_range_size          = nil, -- set automatically
     vinyl_page_size           = 8 * 1024,
     vinyl_bloom_fpr           = 0.05,
-    log                 = nil,
-    log_nonblock        = nil,
-    log_level           = 5,
-    log_format          = "plain",
     io_collect_interval = nil,
     readahead           = 16320,
     snap_io_rate_limit  = nil, -- no limit
@@ -84,6 +84,13 @@ local default_cfg = {
     net_msg_max           = 768,
 }
 
+local default_log_cfg = {
+    log                 = nil,
+    log_nonblock        = nil,
+    log_level           = 5,
+    log_format          = "plain",
+}
+
 -- types of available options
 -- could be comma separated lua types or 'any' if any type is allowed
 local template_cfg = {
@@ -389,6 +396,17 @@ local function apply_default_cfg(cfg, default_cfg)
     end
 end
 
+local function apply_default_log_cfg(cfg, default_cfg)
+    if not ffi.C.log_initialized then
+        apply_default_cfg(cfg, default_cfg)
+    else
+        cfg.log = log.cfg.init_str
+        cfg.log_level = log.level()
+        cfg.log_format = log.log_format()
+        cfg.log_nonblock = log.cfg.nonblock
+    end
+end
+
 -- Return true if two configurations are equivalent.
 local function compare_cfg(cfg1, cfg2)
     if type(cfg1) ~= type(cfg2) then
@@ -469,7 +487,9 @@ setmetatable(box, {
 local function load_cfg(cfg)
     cfg = upgrade_cfg(cfg, translate_cfg)
     cfg = prepare_cfg(cfg, default_cfg, template_cfg, modify_cfg)
-    apply_default_cfg(cfg, default_cfg);
+    apply_default_cfg(cfg, default_cfg)
+    apply_default_log_cfg(cfg, default_log_cfg)
+
     -- Save new box.cfg
     box.cfg = cfg
     if not pcall(private.cfg_check)  then
diff --git a/src/lib/core/say.c b/src/lib/core/say.c
index 64a637c58..fe8592761 100644
--- a/src/lib/core/say.c
+++ b/src/lib/core/say.c
@@ -50,6 +50,8 @@
 
 pid_t log_pid = 0;
 int log_level = S_INFO;
+bool log_initialized = false;
+
 enum say_format log_format = SF_PLAIN;
 enum { SAY_SYSLOG_DEFAULT_PORT = 512 };
 
@@ -701,6 +703,7 @@ say_logger_init(const char *init_str, int level, int nonblock,
 			dup2(log_default->fd, STDOUT_FILENO);
 		}
 	}
+	log_initialized = true;
 	return;
 fail:
 	diag_log();
diff --git a/src/lib/core/say.h b/src/lib/core/say.h
index d26c3ddef..16e3bc0b6 100644
--- a/src/lib/core/say.h
+++ b/src/lib/core/say.h
@@ -69,6 +69,7 @@ enum say_format {
 };
 
 extern int log_level;
+extern bool log_initialized;
 
 static inline bool
 say_log_level_is_enabled(int level)
diff --git a/src/lua/log.lua b/src/lua/log.lua
index 312c14d5e..d419119d7 100644
--- a/src/lua/log.lua
+++ b/src/lua/log.lua
@@ -22,6 +22,9 @@ ffi.cdef[[
     void
     say_set_log_format(enum say_format format);
 
+    void
+    say_logger_init(const char *init_str, int level, int nonblock,
+        const char *format, int background);
 
     extern sayfunc_t _say;
     extern struct ev_loop;
@@ -64,6 +67,12 @@ json.cfg{
     encode_invalid_as_nil  = true,
 }
 
+local cfg = setmetatable({}, {
+    __newindex = function()
+        error('Attempt to modify a read-only table')
+    end,
+})
+
 local special_fields = {
     "file",
     "level",
@@ -124,10 +133,25 @@ local function log_rotate()
 end
 
 local function log_level(level)
+    if level == nil then
+        return ffi.C.log_level
+    end
+    rawset(cfg, 'level', level)
+
     return ffi.C.say_set_log_level(level)
 end
 
 local function log_format(format_name)
+    if format_name == nil then
+        if ffi.C.log_format == ffi.C.SF_PLAIN then
+            return 'plain'
+        elseif ffi.C.log_format == ffi.C.SF_JSON then
+            return 'json'
+        else
+            return
+        end
+    end
+
     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")
@@ -138,6 +162,8 @@ local function log_format(format_name)
     else
         error("log_format: expected 'json' or 'plain'")
     end
+
+    rawset(cfg, 'format', format_name)
 end
 
 local function log_pid()
@@ -155,6 +181,38 @@ local compat_v16 = {
     end;
 }
 
+local function init(args)
+    args = args or {}
+    assert(type(args) == 'table', "init(args): expected 'args' to be a 'table'")
+
+    assert(type(args.init_str) == 'nil' or type(args.init_str) == 'string',
+        "init(args): expected 'args.init_str' to be either 'nil' or 'string'")
+
+    args.format = args.format or "plain"
+    assert(type(args.format) == 'string',
+        "init(args): expected 'args.format' to be a 'string'")
+
+    args.level = args.level or 5
+    assert(type(args.level) == 'number',
+        "init(args): expected 'args.level' to be a 'number'")
+
+    args.background = args.background or false
+    assert(type(args.background) == 'boolean',
+        "init(args): expected 'args.background' to be a 'boolean'")
+
+    args.nonblock = args.nonblock or false
+    assert(type(args.nonblock) == 'boolean',
+        "init(args): expected 'args.nonblock' to be a 'boolean'")
+
+    ffi.C.say_logger_init(args.init_str, args.level, args.nonblock, args.format, args.background)
+
+    rawset(cfg, 'init_str', args.init_str)
+    rawset(cfg, 'format', args.format)
+    rawset(cfg, 'level', args.level)
+    rawset(cfg, 'background', args.background)
+    rawset(cfg, 'nonblock', args.nonblock)
+end
+
 return setmetatable({
     warn = say_closure(S_WARN);
     info = say_closure(S_INFO);
@@ -165,6 +223,8 @@ return setmetatable({
     pid = log_pid;
     level = log_level;
     log_format = log_format;
+    init = init;
+    cfg = cfg;
 }, {
     __index = compat_v16;
 })
diff --git a/test/app-tap/logger_init.test.lua b/test/app-tap/logger_init.test.lua
new file mode 100755
index 000000000..742dbdf04
--- /dev/null
+++ b/test/app-tap/logger_init.test.lua
@@ -0,0 +1,42 @@
+#!/usr/bin/env tarantool
+
+local test = require('tap').test('log')
+test:plan(4)
+
+local filename = "1.log"
+local message = "Hello, World!"
+
+local log = require('log')
+log.init({init_str = filename})
+
+local file = io.open(filename)
+
+while file:read() do
+end
+
+log.info(message)
+test:is(file:read():match('I>%s+(.*)'), message, 'logging works without box.cfg{}')
+
+log.verbose(message)
+test:isnil(file:read(), 'Default log level is 5 (INFO)')
+
+log.level(6)
+
+message = 'updates log level works'
+log.verbose(message)
+test:is(file:read():match('V>%s+(.*)'), message, 'verbose logging')
+
+box.cfg{
+	memtx_memory=107374182
+}
+
+while file:read() do
+end
+
+message = 'calling box.cfg does not reset logging level'
+log.verbose(message)
+test:is(file:read():match('V>%s+(.*)'), message, 'verbose logging after box.cfg')
+
+file:close()
+test:check()
+os.exit()
-- 
2.20.1 (Apple Git-117)

                 reply	other threads:[~2019-08-27 15:47 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190827154640.48315-1-runsfor@gmail.com \
    --to=runsfor@gmail.com \
    --cc=tarantool-patches@freelists.org \
    --subject='Re: [tarantool-patches] [PATCH] Expose log.init function from log module' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox