639 lines
17 KiB
Lua
639 lines
17 KiB
Lua
-- Copyright (c) 2018-2021, OARC, Inc.
|
|
-- All rights reserved.
|
|
--
|
|
-- This file is part of dnsjit.
|
|
--
|
|
-- dnsjit is free software: you can redistribute it and/or modify
|
|
-- it under the terms of the GNU General Public License as published by
|
|
-- the Free Software Foundation, either version 3 of the License, or
|
|
-- (at your option) any later version.
|
|
--
|
|
-- dnsjit is distributed in the hope that it will be useful,
|
|
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
-- GNU General Public License for more details.
|
|
--
|
|
-- You should have received a copy of the GNU General Public License
|
|
-- along with dnsjit. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
-- dnsjit.core.log
|
|
-- Core logging facility
|
|
-- .SS Usage to control global log level
|
|
-- local log = require("dnsjit.core.log")
|
|
-- log.enable("all")
|
|
-- log.disable("debug")
|
|
-- .SS Usage to control module log level
|
|
-- local example = require("example") -- Example as below
|
|
-- example.log():enable("all")
|
|
-- example.log():disable("debug")
|
|
-- .SS Usage to control object instance log level
|
|
-- local example = require("example") -- Example as below
|
|
-- local obj = example.new()
|
|
-- obj:log():enable("all")
|
|
-- obj:log():disable("debug")
|
|
-- .SS Usage in C module
|
|
-- .B NOTE
|
|
-- naming of variables and module only globals are required to exactly as
|
|
-- described in order for the macros to work;
|
|
-- .B self
|
|
-- is the pointer to the object instance,
|
|
-- .B self->_log
|
|
-- is the object instance logging configuration struct,
|
|
-- .B _log
|
|
-- is the module logging configuration struct.
|
|
-- .LP
|
|
-- Include logging:
|
|
-- #include "core/log.h"
|
|
-- .LP
|
|
-- Add the logging struct to the module struct:
|
|
-- typedef struct example {
|
|
-- core_log_t _log;
|
|
-- ...
|
|
-- } example_t;
|
|
-- .LP
|
|
-- Add a module logging configuration and a struct default:
|
|
-- static core_log_t _log = LOG_T_INIT("example");
|
|
-- static example_t _defaults = {
|
|
-- LOG_T_INIT_OBJ("example"),
|
|
-- ...
|
|
-- };
|
|
-- .LP
|
|
-- Use new/free and/or init/destroy functions (depends if you create the
|
|
-- object in Lua or not):
|
|
-- example_t* example_new() {
|
|
-- example_t* self = calloc(1, sizeof(example_t));
|
|
-- .
|
|
-- *self = _defaults;
|
|
-- ldebug("new()");
|
|
-- .
|
|
-- return self;
|
|
-- }
|
|
-- .
|
|
-- void example_free(example_t* self) {
|
|
-- ldebug("free()");
|
|
-- free(self);
|
|
-- }
|
|
-- .
|
|
-- int example_init(example_t* self) {
|
|
-- *self = _defaults;
|
|
-- .
|
|
-- ldebug("init()");
|
|
-- .
|
|
-- return 0;
|
|
-- }
|
|
-- .
|
|
-- void example_destroy(example_t* self) {
|
|
-- ldebug("destroy()");
|
|
-- ...
|
|
-- }
|
|
-- .LP
|
|
-- In the Lua part of the C module you need to create a function that
|
|
-- returns either the object instance Log or the modules Log.
|
|
-- .LP
|
|
-- Add C function to get module only Log:
|
|
-- core_log_t* example_log() {
|
|
-- return &_log;
|
|
-- }
|
|
-- .LP
|
|
-- For the structures metatable add the following function:
|
|
-- local ffi = require("ffi")
|
|
-- local C = ffi.C
|
|
-- .
|
|
-- function Example:log()
|
|
-- if self == nil then
|
|
-- return C.example_log()
|
|
-- end
|
|
-- return self._log
|
|
-- end
|
|
-- .SS Usage in pure Lua module
|
|
-- local log = require("dnsjit.core.log")
|
|
-- local ffi = require("ffi")
|
|
-- local C = ffi.C
|
|
-- .
|
|
-- local Example = {}
|
|
-- local module_log = log.new("example")
|
|
-- .
|
|
-- function Example.new()
|
|
-- local self = setmetatable({
|
|
-- _log = log.new("example", module_log),
|
|
-- }, { __index = Example })
|
|
-- .
|
|
-- self._log:debug("new()")
|
|
-- .
|
|
-- return self
|
|
-- end
|
|
-- .
|
|
-- function Example:log()
|
|
-- if self == nil then
|
|
-- return module_log
|
|
-- end
|
|
-- return self._log
|
|
-- end
|
|
--
|
|
-- Core logging facility used by all modules.
|
|
-- .SS Log levels
|
|
-- .TP
|
|
-- all
|
|
-- Keyword to enable/disable all changeable log levels.
|
|
-- .TP
|
|
-- debug
|
|
-- Used for debug information.
|
|
-- .TP
|
|
-- info
|
|
-- Used for informational processing messages.
|
|
-- .TP
|
|
-- notice
|
|
-- Used for messages of that may have impact on processing.
|
|
-- .TP
|
|
-- warning
|
|
-- Used for messages that has impact on processing.
|
|
-- .TP
|
|
-- critical
|
|
-- Used for messages that have severe impact on processing, this level can
|
|
-- not be disabled.
|
|
-- .TP
|
|
-- fatal
|
|
-- Used to display a message before stopping all processing and existing,
|
|
-- this level can not be disabled.
|
|
-- .SS C macros
|
|
-- .TP
|
|
-- Object instance macros
|
|
-- The following macros uses
|
|
-- .IR &self->_log :
|
|
-- .BR ldebug(msg...) ,
|
|
-- .BR linfo(msg...) ,
|
|
-- .BR lnotice(msg...) ,
|
|
-- .BR lwarning(msg...) ,
|
|
-- .BR lcritical(msg...) ,
|
|
-- .BR lfatal(msg...) .
|
|
-- .TP
|
|
-- Object pointer instance macros
|
|
-- The following macros uses
|
|
-- .IR self->_log :
|
|
-- .BR lpdebug(msg...) ,
|
|
-- .BR lpinfo(msg...) ,
|
|
-- .BR lpnotice(msg...) ,
|
|
-- .BR lpwarning(msg...) ,
|
|
-- .BR lpcritical(msg...) ,
|
|
-- .BR lpfatal(msg...) .
|
|
-- .TP
|
|
-- Module macros
|
|
-- The following macros uses
|
|
-- .IR &_log :
|
|
-- .BR mldebug(msg...) ,
|
|
-- .BR mlinfo(msg...) ,
|
|
-- .BR mlnotice(msg...) ,
|
|
-- .BR mlwarning(msg...) ,
|
|
-- .BR mlcritical(msg...) ,
|
|
-- .BR mlfatal(msg...) .
|
|
-- .TP
|
|
-- Global macros
|
|
-- The following macros uses the global logging configuration:
|
|
-- .BR gldebug(msg...) ,
|
|
-- .BR glinfo(msg...) ,
|
|
-- .BR glnotice(msg...) ,
|
|
-- .BR glwarning(msg...) ,
|
|
-- .BR glcritical(msg...) ,
|
|
-- .BR glfatal(msg...) .
|
|
module(...,package.seeall)
|
|
|
|
require("dnsjit.core.log_h")
|
|
local ffi = require("ffi")
|
|
local C = ffi.C
|
|
local L = C.core_log_log()
|
|
|
|
local t_name = "core_log_t"
|
|
local core_log_t
|
|
local Log = {}
|
|
|
|
-- Create a new Log object with the given module
|
|
-- .I name
|
|
-- and an optional shared
|
|
-- .I module
|
|
-- Log object.
|
|
function Log.new(name, module)
|
|
local self
|
|
if ffi.istype(t_name, module) then
|
|
self = core_log_t({ is_obj = 1, module = module.settings })
|
|
else
|
|
self = core_log_t()
|
|
end
|
|
|
|
local len = #name
|
|
if len > 31 then
|
|
len = 31
|
|
end
|
|
ffi.copy(self.name, name, len)
|
|
self.name[len] = 0
|
|
|
|
return self
|
|
end
|
|
|
|
-- Enable specified log level.
|
|
function Log:enable(level)
|
|
if not ffi.istype(t_name, self) then
|
|
level = self
|
|
self = L
|
|
end
|
|
if level == "all" then
|
|
self.settings.debug = 3
|
|
self.settings.info = 3
|
|
self.settings.notice = 3
|
|
self.settings.warning = 3
|
|
elseif level == "debug" then
|
|
self.settings.debug = 3
|
|
elseif level == "info" then
|
|
self.settings.info = 3
|
|
elseif level == "notice" then
|
|
self.settings.notice = 3
|
|
elseif level == "warning" then
|
|
self.settings.warning = 3
|
|
else
|
|
error("invalid log level: "..level)
|
|
end
|
|
end
|
|
|
|
-- Disable specified log level.
|
|
function Log:disable(level)
|
|
if not ffi.istype(t_name, self) then
|
|
level = self
|
|
self = L
|
|
end
|
|
if level == "all" then
|
|
self.settings.debug = 2
|
|
self.settings.info = 2
|
|
self.settings.notice = 2
|
|
self.settings.warning = 2
|
|
elseif level == "debug" then
|
|
self.settings.debug = 2
|
|
elseif level == "info" then
|
|
self.settings.info = 2
|
|
elseif level == "notice" then
|
|
self.settings.notice = 2
|
|
elseif level == "warning" then
|
|
self.settings.warning = 2
|
|
else
|
|
error("invalid log level: "..level)
|
|
end
|
|
end
|
|
|
|
-- Clear specified log level, which means it will revert back to default
|
|
-- or inherited settings.
|
|
function Log:clear(level)
|
|
if not ffi.istype(t_name, self) then
|
|
level = self
|
|
self = L
|
|
end
|
|
if level == "all" then
|
|
self.settings.debug = 0
|
|
self.settings.info = 0
|
|
self.settings.notice = 0
|
|
self.settings.warning = 0
|
|
elseif level == "debug" then
|
|
self.settings.debug = 0
|
|
elseif level == "info" then
|
|
self.settings.info = 0
|
|
elseif level == "notice" then
|
|
self.settings.notice = 0
|
|
elseif level == "warning" then
|
|
self.settings.warning = 0
|
|
else
|
|
error("invalid log level: "..level)
|
|
end
|
|
end
|
|
|
|
-- Enable or disable the displaying of file and line for messages.
|
|
function Log:display_file_line(bool)
|
|
if not ffi.istype(t_name, self) then
|
|
bool = self
|
|
self = L
|
|
end
|
|
if bool == true then
|
|
self.settings.display_file_line = 3
|
|
else
|
|
self.settings.display_file_line = 0
|
|
end
|
|
end
|
|
|
|
-- Convert error number to its text representation.
|
|
function Log.errstr(errno)
|
|
return ffi.string(C.core_log_errstr(errno))
|
|
end
|
|
|
|
-- Generate a debug message.
|
|
function Log.debug(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
if not self then
|
|
if L.settings.debug ~= 3 then
|
|
return
|
|
end
|
|
else
|
|
if self.settings.debug ~= 0 then
|
|
if self.settings.debug ~= 3 then
|
|
return
|
|
end
|
|
elseif self.module ~= nil and self.module.debug ~= 0 then
|
|
if self.module.debug ~= 3 then
|
|
return
|
|
end
|
|
elseif L.settings.debug ~= 3 then
|
|
return
|
|
end
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_debug(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_debug(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_debug(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_debug(self, nil, 0, ...)
|
|
end
|
|
|
|
-- Generate an info message.
|
|
function Log.info(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
if not self then
|
|
if L.settings.info ~= 3 then
|
|
return
|
|
end
|
|
else
|
|
if self.settings.info ~= 0 then
|
|
if self.settings.info ~= 3 then
|
|
return
|
|
end
|
|
elseif self.module ~= nil and self.module.info ~= 0 then
|
|
if self.module.info ~= 3 then
|
|
return
|
|
end
|
|
elseif L.settings.info ~= 3 then
|
|
return
|
|
end
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_info(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_info(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_info(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_info(self, nil, 0, ...)
|
|
end
|
|
|
|
-- Generate a notice message.
|
|
function Log.notice(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
if not self then
|
|
if L.settings.notice ~= 3 then
|
|
return
|
|
end
|
|
else
|
|
if self.settings.notice ~= 0 then
|
|
if self.settings.notice ~= 3 then
|
|
return
|
|
end
|
|
elseif self.module ~= nil and self.module.notice ~= 0 then
|
|
if self.module.notice ~= 3 then
|
|
return
|
|
end
|
|
elseif L.settings.notice ~= 3 then
|
|
return
|
|
end
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_notice(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_notice(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_notice(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_notice(self, nil, 0, ...)
|
|
end
|
|
|
|
-- Generate a warning message.
|
|
function Log.warning(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
if not self then
|
|
if L.settings.warning ~= 3 then
|
|
return
|
|
end
|
|
else
|
|
if self.settings.warning ~= 0 then
|
|
if self.settings.warning ~= 3 then
|
|
return
|
|
end
|
|
elseif self.module ~= nil and self.module.warning ~= 0 then
|
|
if self.module.warning ~= 3 then
|
|
return
|
|
end
|
|
elseif L.settings.warning ~= 3 then
|
|
return
|
|
end
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_warning(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_warning(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_warning(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_warning(self, nil, 0, ...)
|
|
end
|
|
|
|
-- Generate a critical message.
|
|
function Log.critical(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_critical(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_critical(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_critical(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_critical(self, nil, 0, ...)
|
|
end
|
|
|
|
-- Generate a fatal message.
|
|
function Log.fatal(self, ...)
|
|
local format
|
|
if not ffi.istype(t_name, self) then
|
|
format = self
|
|
self = nil
|
|
end
|
|
while true do
|
|
if not self then
|
|
if L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
else
|
|
if self.settings.display_file_line ~= 0 then
|
|
if self.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif self.module ~= nil and self.module.display_file_line ~= 0 then
|
|
if self.module.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
elseif L.settings.display_file_line ~= 3 then
|
|
break
|
|
end
|
|
end
|
|
local info = debug.getinfo(2, "S")
|
|
if format then
|
|
C.core_log_fatal(self, info.source, info.linedefined, format, ...)
|
|
return
|
|
end
|
|
C.core_log_fatal(self, info.source, info.linedefined, ...)
|
|
return
|
|
end
|
|
|
|
if format then
|
|
C.core_log_fatal(self, nil, 0, format, ...)
|
|
return
|
|
end
|
|
C.core_log_fatal(self, nil, 0, ...)
|
|
end
|
|
|
|
core_log_t = ffi.metatype(t_name, { __index = Log })
|
|
|
|
return Log
|