如何为函数表实现跟踪功能?
2016-6-17 1:27:39
收藏:0
阅读:93
评论:2
我有一个如下所示的表
local ftable = {
getPinId = app.getPinId
}
ftable被传递到另一个函数中,该函数将其导出为RPC接口。 这个方法可行,但现在我想将函数调用跟踪添加到日志文件中。
简单的方法是
local ftable = {
getPinId = function(...) print("getPinId") app.getPinId(...) end
}
但是,这不是特别好的方法。 我希望像这样放置:
local trace = function(func, ...)
return function(...) print(func) func(...) end
end
local ftable = {
getPinId = trace(app.getPinId)
}
但是,这并不能产生完全预期的结果。参数没有被传递。
另一个选项是使用这样的元表:
local ftable = {}
setmetatable(ftable, {
__index = function(_, k)
printf("Call: app.%s\n", k) return app[k] end
})
这是有效的。但如果可能,我也希望能打印传递的参数。
有什么建议吗? 我只使用luajit,如果有什么不同之处,请告诉我。
点赞
用户3677376
在 Lua 中,包装函数调用很容易:
local function wrap( f )
local function after( ... )
-- 在函数调用 f 之后执行的代码
print( "返回值:", ... )
return ...
end
return function( ... )
-- 在函数调用 f 之前执行的代码
print( "参数:", ... )
return after( f( ... ) )
end
end
local function f( a, b, c )
return a+b, c-a
end
local f_wrapped = wrap( f )
f_wrapped( 1, 2, 3 )
输出为:
参数: 1 2 3
返回值: 3 2
日志和追踪的一个问题是,Lua 值(包括函数)本身没有名称。调试库会尝试通过检查函数的调用或存储位置来找到适当的名称,但如果你想确保,你必须自己提供名称。但是,如果您的函数存储在(嵌套的)表中(如注释中所示),您可以编写一个函数,遍历嵌套的表,并使用表键作为名称包装所有找到的函数:
local function trace( name, value )
local t = type( value )
if t == "function" then -- 进行包装
local function after( ... )
print( name .. " 返回值:", ... )
return ...
end
return function( ... )
print( "调用 " .. name .. ":", ... )
return after( value( ... ) )
end
elseif t == "table" then -- 递归进入子表
local copy = nil
for k,v in pairs( value ) do
local nv = trace( name.."."..tostring( k ), v )
if nv ~= v then
copy = copy or setmetatable( {}, { __index = value } )
copy[ k ] = nv
end
end
return copy or value
else -- 其他值被忽略(原样返回)
return value
end
end
local ftable = {
getPinId = function( ... ) return "x", ... end,
nested = {
getPinId = function( ... ) return "y", ... end
}
}
local ftableTraced = trace( "ftable", ftable )
ftableTraced.getPinId( 1, 2, 3 )
ftableTraced.nested.getPinId( 2, 3, 4 )
输出为:
调用 ftable.getPinId: 1 2 3
ftable.getPinId 返回值: x 1 2 3
调用 ftable.nested.getPinId: 2 3 4
ftable.nested.getPinId 返回值: y 2 3 4
需要注意一些事项:
- 表键可以是任意 Lua 值,而不仅仅是完全由可打印字符组成的短字符串。
- 表可以包含循环引用。如果包含循环引用,上面的朴素实现将因堆栈溢出而崩溃。
2016-06-17 04:35:09
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
使用
__call元方法:M = { __call = function (t, ...) print("calling ", t.name, ...) return t.func(...) end } trace = function(func, name) return setmetatable({func=func, name=name}, M) end function f(...) print("in f", ...) end g = trace(f, "f") g(10, 20, 30)