-- ------------------------------------------------------------------------------ -- -- TradeSkillMaster -- -- https://tradeskillmaster.com -- -- All Rights Reserved - Detailed license information included with addon. -- -- ------------------------------------------------------------------------------ -- local _, TSM = ... local Log = TSM.Init("Util.Log") local Debug = TSM.Include("Util.Debug") local Theme = TSM.Include("Util.Theme") local private = { severity = {}, location = {}, timeStr = {}, msg = {}, writeIndex = 1, len = 0, temp = {}, logToChat = TSM.__IS_TEST_ENV or false, currentThreadNameFunc = nil, stackLevel = 3, chatFrame = nil, } local MAX_ROWS = 200 local MAX_MSG_LEN = 150 local CHAT_LOG_COLOR_KEYS = { TRACE = "BLUE", INFO = "GREEN", WARN = "YELLOW", ERR = "RED", } -- ============================================================================ -- Module Functions -- ============================================================================ function Log.SetChatFrame(chatFrame) private.chatFrame = strlower(chatFrame) end function Log.SetLoggingToChatEnabled(enabled) if TSM.__IS_TEST_ENV then enabled = true end if private.logToChat == enabled then return end private.logToChat = enabled if enabled then -- dump our buffer local len = Log.Length() print(format("Printing %d buffered logs:", len)) for i = 1, len do private.LogToChat(Log.Get(i)) end end end function Log.SetCurrentThreadNameFunction(func) private.currentThreadNameFunc = func end function Log.Length() return private.len end function Log.Get(index) assert(index <= private.len) local readIndex = (private.writeIndex - private.len + index - 2) % MAX_ROWS + 1 return private.severity[readIndex], private.location[readIndex], private.timeStr[readIndex], private.msg[readIndex] end function Log.RaiseStackLevel() private.stackLevel = private.stackLevel + 1 end function Log.LowerStackLevel() private.stackLevel = private.stackLevel - 1 end function Log.StackTrace() Log.RaiseStackLevel() Log.Trace("Stack Trace:") local level = 2 local line = Debug.GetStackLevelLocation(level) while line do Log.Trace(" " .. line) level = level + 1 line = Debug.GetStackLevelLocation(level) end Log.LowerStackLevel() end function Log.Trace(...) private.Log("TRACE", ...) end function Log.Info(...) private.Log("INFO", ...) end function Log.Warn(...) private.Log("WARN", ...) end function Log.Err(...) private.Log("ERR", ...) end function Log.PrintUserRaw(str) private.GetChatFrame():AddMessage(str) end function Log.PrintfUserRaw(...) Log.PrintUserRaw(format(...)) end function Log.PrintUser(str) Log.PrintUserRaw(Theme.GetColor("INDICATOR"):ColorText("TSM")..": "..str) end function Log.PrintfUser(...) Log.PrintUser(format(...)) end function Log.ColorUserAccentText(text) return Theme.GetColor("INDICATOR_ALT"):ColorText(text) end -- ============================================================================ -- Private Helper Functions -- ============================================================================ function private.GetChatFrame() for i = 1, NUM_CHAT_WINDOWS do local name = strlower(GetChatWindowInfo(i) or "") if name ~= "" and name == private.chatFrame then return _G["ChatFrame" .. i] end end return DEFAULT_CHAT_FRAME end function private.Log(severity, fmtStr, ...) assert(type(fmtStr) == "string" and CHAT_LOG_COLOR_KEYS[severity]) wipe(private.temp) for i = 1, select("#", ...) do local arg = select(i, ...) if type(arg) == "boolean" then arg = arg and "T" or "F" elseif type(arg) ~= "string" and type(arg) ~= "number" then arg = tostring(arg) end private.temp[i] = arg end -- ignore anything after a newline in the log message local msg = strsplit("\n", format(fmtStr, unpack(private.temp))) if #msg > MAX_MSG_LEN then msg = strsub(msg, 1, -4).."..." end local location = Debug.GetStackLevelLocation(private.stackLevel) location = location and strmatch(location, "([^\\/]+%.lua:[0-9]+)") or "?:?" local threadName = private.currentThreadNameFunc and private.currentThreadNameFunc() or nil if threadName then location = location.."|"..threadName end local timeMs = Debug.GetTimeMilliseconds() local timeStr = format("%s.%03d", date("%H:%M:%S", floor(timeMs / 1000)), timeMs % 1000) -- append the log private.severity[private.writeIndex] = severity private.location[private.writeIndex] = location private.timeStr[private.writeIndex] = timeStr private.msg[private.writeIndex] = msg private.writeIndex = (private.writeIndex < MAX_ROWS) and (private.writeIndex + 1) or 1 private.len = min(private.len + 1, MAX_ROWS) if private.logToChat then private.LogToChat(severity, location, timeStr, msg) end end function private.LogToChat(severity, location, timeStr, msg) print(strjoin(" ", timeStr, Theme.GetFeedbackColor(CHAT_LOG_COLOR_KEYS[severity]):ColorText("{"..location.."}"), msg)) end