You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
7.3 KiB

--===========================================================================--
-- --
-- System.Logger --
-- --
--===========================================================================--
--===========================================================================--
-- Author : kurapica125@outlook.com --
-- URL : http://github.com/kurapica/PLoop --
-- Create Date : 2011/02/28 --
-- Update Date : 2018/03/15 --
-- Version : 1.0.0 --
--===========================================================================--
PLoop(function(_ENV)
namespace "System"
--- Logger is used to distribute log message.
-- Logger object can use 'logObject(logLevel, logMessage, ...)' for short to send out log messages.
__Sealed__()
class "Logger" (function(_ENV)
export {
type = type,
error = error,
select = select,
pairs = pairs,
strformat = string.format,
tblconcat = table.concat,
rawset = rawset,
pcall = pcall,
tostring = tostring,
throw = throw,
Toolset = Toolset,
isValidValue = Struct.ValidateValue,
Serialization.Serializable
}
export { Logger }
--- Represents the log levels
__Sealed__() __AutoIndex__()
enum "LogLevel" { "Trace", "Debug", "Info", "Warn", "Error", "Fatal" }
local date = _G.os and os.date or _G.date
local regLogger = setmetatable({}, {__mode="v"})
-----------------------------------------------------------
-- method --
-----------------------------------------------------------
--- log out message for log level
-- @format (logLevel, message[, ...])
-- @param logLevel the message's log level, if lower than object.LogLevel, the message will be discarded
-- @param message the send out message, can be a formatted string
-- @param ... the list values to be included into the formatted string
__Arguments__{ LogLevel, String, Any * 0 }:Throwable()
function Log(self, logLvl, msg, ...)
if logLvl >= self.LogLevel then
-- Prefix and TimeStamp
local tfmt = self.UseTimeFormat and self.TimeFormat
if select("#", ...) > 0 then
local ok, r = pcall(strformat, msg, Toolset.tostringall(...))
if not ok then throw(r) end
msg = r
end
msg = (tfmt and date and date(tfmt) or "") ..
(self.__Prefix[logLvl] or "") ..
msg
-- Send message to handlers
for handler, lvl in pairs(self.__Handler) do
if lvl == true or lvl == logLvl then
pcall(handler, msg)
end
end
end
end
--- Add a log handler, when Logger object send out log messages, the handler will receive the message as it's first argument
-- @format (handler[, loglvl])
-- @param handler the log handler
-- @param loglvl the handler only receive this level's message if setted, or receive all level's message if keep nil
__Arguments__{ Callable, LogLevel/nil }
function AddHandler(self, handler, loglevel)
if not self.__Handler[handler] then
self.__Handler[handler] = loglevel or true
end
end
--- Remove a log handler
-- @param handler the log handler to be removed
__Arguments__{ Callable }
function RemoveHandler(self, handler)
if self.__Handler[handler] then
self.__Handler[handler] = nil
end
end
--- Set a prefix for a log level, thre prefix will be added to the message when the message is with the same log level
-- @param logLevel the log level
-- @param prefix the prefix string
__Arguments__{ LogLevel, String/nil }
function SetPrefix(self, loglvl, prefix)
self.__Prefix[loglvl] = prefix
return self[loglvl]
end
-----------------------------------------------------------
-- property --
-----------------------------------------------------------
--- the log level
property "LogLevel" { type = LogLevel, default = LogLevel.Info }
--- if the timeformat is setted, the log message will add a timestamp at the header
property "TimeFormat" { type = TimeFormat, default = "[%c]" }
--- whether use the time format
property "UseTimeFormat"{ type = Boolean, default = true }
--- The system default logger
__Static__()
property "Default" { set = false, default = function() return Logger() end }
-----------------------------------------------------------
-- constructor --
-----------------------------------------------------------
__Arguments__{ String/nil }
function __exist(_, name) return regLogger[name] end
function __new() return { __Handler = {}, __Prefix = {} } end
__Arguments__{ String/nil }
function __ctor(self, name)
if name then regLogger[name] = self end
end
-----------------------------------------------------------
-- meta-method --
-----------------------------------------------------------
__call = Log
--- get a function for special log level to send the messages
__Arguments__{ LogLevel }
function __index(self, loglvl)
local func = function(msg, ...) if loglvl >= self.LogLevel then return self(loglvl, msg, ...) end end
rawset(self, loglvl, func)
return func
end
end)
-----------------------------------------------------------
-- the default logger --
-----------------------------------------------------------
Logger.Default:SetPrefix(Logger.LogLevel.Trace, "[Trace]")
Logger.Default:SetPrefix(Logger.LogLevel.Debug, "[Debug]")
Logger.Default:SetPrefix(Logger.LogLevel.Info, "[Info]")
Logger.Default:SetPrefix(Logger.LogLevel.Warn, "[Warn]")
Logger.Default:SetPrefix(Logger.LogLevel.Error, "[Error]")
Logger.Default:SetPrefix(Logger.LogLevel.Fatal, "[Fatal]")
Logger.Default.LogLevel = Logger.LogLevel.Info
end)