--===========================================================================-- -- -- -- 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)