2016-06-17 4 views
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を使用しているのであれば、それは違いがあります。

+0

あなたのコードは機能するはずですが、機能名のアドレスではなく、機能のアドレスが表示されます。あなたが報告した失敗の例を示してください。 – lhf

+0

それは本当です、私はdebug.getinfo関数を試しましたが、それは役に立たなかった。それは無名関数のように扱われます。私は名前を渡すことができたと思う。今私は、コードを大幅に短縮するmetatableメソッドを使用しています。 – Matt

+0

Lua関数は、すべての値と同様、名前を持ちません。だからこそ@lhfは答えの関数値と文字列を関連付けました。 –

答えて

3

はLuaの中に簡単です:

local function wrap(f) 
    local function after(...) 
    -- code to execute *after* function call to f 
    print("return values:", ...) 
    return ... 
    end 
    return function(...) 
    -- code to execute *before* function call to f 
    print("arguments:", ...) 
    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) 

出力は次のようになります、ロギング/トレース用の

arguments: 1 2 3 
return values: 3 2 

1つの問題は、ルア値(関数を含む)には名前自体はありません。デバッグライブラリは、関数が呼び出される方法や格納されている場所を調べることによって関数の適切な名前を見つけようとしますが、確かめたい場合は自分で名前を指定する必要があります。

local function trace(name, value) 
    local t = type(value) 
    if t == "function" then -- do the wrapping 
    local function after(...) 
     print(name.." returns:", ...) 
     return ... 
    end 
    return function(...) 
     print("calling "..name..":", ...) 
     return after(value(...)) 
    end 
    elseif t == "table" then -- recurse into subtables 
    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 -- other values are ignored (returned as is) 
    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) 
:あなたの関数は(コメントで示されているように)(ネスト)のテーブルに格納されている場合は、あなたはそれが名前のように、テーブルのキーを使用して検出したすべての関数をネストした表を反復処理関数を記述し、ラップでした

出力は次のとおりです。

calling ftable.getPinId: 1 2 3 
ftable.getPinId returns: x 1 2 3 
calling ftable.nested.getPinId: 2 3 4 
ftable.nested.getPinId returns: y 2 3 4 

いくつかの注意すべき事柄:

  1. 表のキーは、任意のLuaの値ではなく、完全に印字可能な文字からなるだけで短い文字列ことができます。
  2. テーブルには循環参照を含めることができます。もしそうであれば、上記の素朴な実装はスタックのオーバーフローで消滅します。
2

__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) 
+0

のmetamethod __indexメソッドを使うと、それぞれのメソッドに明示的に型を入れる必要がないという点で非常に便利です。 2つを組み合わせる方法はありますか?つまり、__callメソッドを追加しますか? – Matt

+0

@Matt、 'setmetatable(ftable、{__ index = function(t、k)}ローカルf = trace(app [k]、k); t [k] = f; return f end})'を試してください。 – lhf

+0

ええと、私の場合はなぜ動作しないのかはわかりません。私のftableはもう少し複雑です。それはテーブルのテーブルを含んでいますが、私はそれをテーブルのテーブルに付けています。ああ、私はそれを別の日に残すつもりです。 – Matt

関連する問題