Improve formatting options for Logger

This commit is contained in:
Gabriel Tofvesson 2024-10-14 12:49:41 +02:00
parent f5ea075a37
commit b9ac063a35

View File

@ -52,8 +52,27 @@ function Logger:setIgnoreGlobals(ignoreGlobals)
self.ignoreGlobals = ignoreGlobals self.ignoreGlobals = ignoreGlobals
end end
local LogPlain = {}
function LogPlain.of(value, deep)
local obj = { value, deep = deep }
setmetatable(obj, LogPlain)
return obj
end
function LogPlain.is(value)
return type(value) == "table" and getmetatable(value) == LogPlain
end
function LogPlain.isDeep(value)
return LogPlain.is(value) and value.deep
end
function LogPlain.getValue(value)
return LogPlain.is(value) and value[1] or value
end
local RecursionSentinel = {} local RecursionSentinel = {}
function RecursionSentinel.make(table) function RecursionSentinel.make(table, index)
local obj = { table = table } local obj = { table = table }
setmetatable(obj, RecursionSentinel) setmetatable(obj, RecursionSentinel)
return obj return obj
@ -71,7 +90,8 @@ function RecursionSentinel.getSentinel(knownTables, value)
local sentinel = knownTables[value] local sentinel = knownTables[value]
if sentinel == nil then if sentinel == nil then
sentinel = knownTables[value] sentinel = knownTables[value]
knownTables[value] = RecursionSentinel.make(value) knownTables[#knownTables+1] = value
knownTables[value] = RecursionSentinel.make(value, #knownTables)
end end
return sentinel return sentinel
end end
@ -82,7 +102,9 @@ function RecursionSentinel.add(knownTables, value)
return sentinel return sentinel
end end
function RecursionSentinel.remove(knownTables, value) function RecursionSentinel.pop(knownTables)
local value = knownTables[#knownTables]
knownTables[#knownTables] = nil
knownTables[value] = nil knownTables[value] = nil
end end
@ -114,26 +136,40 @@ for k,v in pairs(_G) do
G_[v] = k G_[v] = k
end end
local function _simpleStringify(value, builder, ignoreGlobals, skipFunctions) local function _simpleStringify(inValue, builder, ignoreGlobals, skipFunctions, plain)
local value = LogPlain.getValue(inValue)
local isPlain = plain or LogPlain.is(inValue)
local isDeep = plain or LogPlain.isDeep(inValue)
if type(value) == "table" then if type(value) == "table" then
if not isPlain then
table.insert(builder, "<") table.insert(builder, "<")
end
if ignoreGlobals and G_[value] ~= nil then if ignoreGlobals and G_[value] ~= nil then
table.insert(builder, "_G.") table.insert(builder, "_G.")
table.insert(builder, G_[value]) table.insert(builder, G_[value])
elseif RecursionSentinel.isSentinel(value) then elseif RecursionSentinel.isSentinel(value) then
if isPlain then
table.insert(builder, "<recurse_")
table.insert(builder, tostring(value.index))
table.insert(builder, ">")
else
table.insert(builder, "recurse ") table.insert(builder, "recurse ")
table.insert(builder, tostring(value.value)) table.insert(builder, tostring(value.value))
end
else else
if not isPlain then
table.insert(builder, tostring(value)) table.insert(builder, tostring(value))
table.insert(builder, ">{") table.insert(builder, ">")
end
table.insert(builder, "{")
local first = true local first = true
for i,v in ipairs(value) do for _,v in ipairs(value) do
if not first then if not first then
table.insert(builder, ",") table.insert(builder, ",")
else else
first = false first = false
end end
_simpleStringify(v, builder, ignoreGlobals) _simpleStringify(v, builder, ignoreGlobals, skipFunctions, isDeep)
end end
first = #value == 0 first = #value == 0
for k,v in pairs(value) do for k,v in pairs(value) do
@ -142,32 +178,53 @@ local function _simpleStringify(value, builder, ignoreGlobals, skipFunctions)
else else
first = false first = false
end end
_simpleStringify(k, builder, ignoreGlobals) -- String key values are always plain-printed
_simpleStringify(k, builder, ignoreGlobals, skipFunctions, isDeep or type(k) == "string")
table.insert(builder, "=") table.insert(builder, "=")
_simpleStringify(v, builder, ignoreGlobals) _simpleStringify(v, builder, ignoreGlobals, skipFunctions, isDeep)
end end
table.insert(builder, "}") table.insert(builder, "}")
end end
if not isPlain then
table.insert(builder, ">") table.insert(builder, ">")
elseif not skipFunctions or type(value) ~= "function" then end
local isString = type(value) == "string" elseif type(value) == "string" then
if isString then if not isPlain then
table.insert(builder, "\"") table.insert(builder, "\"")
end end
table.insert(builder, tostring(value)) table.insert(builder, tostring(value))
if isString then if not isPlain then
table.insert(builder, "\"") table.insert(builder, "\"")
end end
elseif type(value) == "function" then
if not skipFunctions then
local info = debug.getinfo(value, "u")
if not isPlain then
table.insert(builder, tostring(value))
end end
table.insert(builder, "(")
table.insert(builder, tostring(info.nparams))
if info.isvararg then
table.insert(builder, "*")
end
table.insert(builder, ")")
end
elseif not skipFunctions or type(value) ~= "function" then
table.insert(builder, tostring(value))
end
end
local function deepStringify(value)
local collect = {}
_simpleStringify(cloneNonRecursive(value, {}), collect, false, false)
return table.concat(collect)
end end
function Logger:_doPrint(level, message, ...) function Logger:_doPrint(level, message, ...)
if LogLevel.isGreaterOrEqual(level, self.level) then if LogLevel.isGreaterOrEqual(level, self.level) then
local result = { tostring(LogLevel[level]), message } local result = { tostring(LogLevel[level]), deepStringify(message) }
for _,v in ipairs({...}) do for _,v in ipairs({...}) do
local collect = {} table.insert(result, deepStringify(v))
_simpleStringify(cloneNonRecursive(v, {}), collect)
table.insert(result, table.concat(collect))
end end
self.output(table.concat(result, " ")) self.output(table.concat(result, " "))
end end
@ -207,6 +264,10 @@ function Logger:setLevel(level)
end end
end end
function Logger.plain(value, deep)
return LogPlain.of(value, deep)
end
Logging.Logger = Logger Logging.Logger = Logger
Logging.LogLevel = LogLevel Logging.LogLevel = LogLevel