dnsjit/src/core/log.lua
Daniel Baumann 8d1b12293d
Adding upstream version 1.1.0+debian.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-02-09 08:30:48 +01:00

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