<aside> 💡 Beautiful, elegant, most importantly readable! Let’s make logs looking great again!
</aside>
为了让 Lua 日志看起来更简洁更直观,于是对日志做了一点点🤏小小的修改。
第一步,先把需要用的接口写好,很简单,分别对应的是 info, warning, error 等级的日志:
local traceback = debug.traceback
function log.info(...)
---为了避免性能,可以添加一些开关
if not UNITY_EDITOR and not _log_info_enabled then return end
CSGame.Log(get_output(...), traceback())
end
function log.warning(...)
CSGame.LogWarning(get_output(...), traceback())
end
function log.error(...)
CSGame.LogError(get_output(...), traceback())
end
备注:CSGame.Log,CSGame.LogWarning, CSGame.LogError 是封装的 Lua 调用的 CS 接口,其中 CSGame 即 CS.Export2Lua.CSGame 类,为 xLua 导出接口的类,项目中对所有接口进行了分类,统一位于 Export2Lua 命名空间下。
备注2:接口里添加的 traceback() 是额外附加了了当前的调用堆栈信息,有助于 debug 时提供更多信息。
上文中预留的一个函数 get_output(...) 要怎么实现呢?
C# 在在打印日志时,比较麻烦的就是一条日志需要打印多个变量的值时,要是用格式化字符串,虽然使用的是 $"this is a {param}" 这样的字符串,但仍然略显麻烦。所以 lua 函数的不定参数数量的优势,可以直接无脑的传入一个或者一堆变量,然后一次性打印出来。
将多个参数的结果拼接起来:
local function get_output(...)
local content = get_content(...)
return table.concat(content, ', ')
end
判断参数的数量,get_content() 接口用来实现将获得变量要打印出来的字符串:
local function get_content(...)
local args = {...}
if #args == 0 then
return { 'nil' }
elseif #args == 1 then
return { get_content_str(args[1]) }
else
local tbl = {}
for k, v in ipairs(args) do
tbl[k] = get_content_str(v)
end
return tbl
end
end
美观优雅的日志,主要取决于 table 是否能够美观优雅的打印出来。这里示例的打印格式为 {k1: v1, k2:v2},也可以自行添加换行、缩进,甚至对 table 进行排序后再打印等各种更浪费性能有助于方便查看的格式。
上文中的 get_content_str() 为转换的具体实现,根据参数类型进行打印。特别要注意的是 table 嵌套的情况:
local function get_content_str(content)
if content == nil then
return 'nil'
elseif UNITY_EDITOR and type(content) == 'userdata' then
return '[' .. CSGame.GetTypeName(content) .. ']' .. tostring(content)
elseif type(content) ~= 'table' then
return tostring(content)
else
return table.tostring(content)
end
end
table.tostring 的具体实现:
function table.tostring(tbl, key, lines)
---将table中的元素以k:v的格式记录下来
key = key and key..':' or ''
lines = lines or {}
lines[#lines + 1] = key .. '{'
for k, v in pairs(tbl) do
if type(v) == 'table' then
table.tostring(v, k, lines)
else
lines[#lines + 1] = tostring(k) .. ':' .. tostring(v)
end
end
lines[#lines + 1] = '}'
return table.concat(lines, ' ')
end
出了三个等级的日志打印接口,还有一些常用的其他接口,可以进行扩展:
指定上下文 Object
function log.object_info(object, ...)
if not UNITY_EDITOR and not _log_info_enabled then return end
CSGame.Log(object, get_output(...), traceback())
end
function log.object_error(object, ...)
CSGame.LogError(object, get_output(...), traceback())
end