I’m trying to implement a function tracing facility in Julia. Each time the designated function is called I want to log the parameters and return values.
I have something partially working that is checked in at
@trace
is defined at
It has two problems:
- it prints the parameter names rather than their values
- I’m using
println
because when I use Logging.@info I get the error “ERROR: LoadError: LoadError: MethodError: no method matching logmsg_code(::Module, ::String, ::Int64, ::Symbol)”.
using Pkg
Pkg.add(url="https://github.com/MarkNahabedian/NahaJuliaLib.jl")
using NahaJuliaLib
using MacroTools
@trace(trace_hanoi, function hanoi(from, to, other, count)
if count == 1
println("move 1 from $from to $to")
return
else
hanoi(from, other, to, count - 1)
println("move 1 from $from to $to")
hanoi(other, to, from, count - 1)
return (from, to) # arbitrary result to show
end
end)
hanoi (generic function with 1 method)
trace_hanoi = true
true
hanoi(:a, :b, :c, 2)
Trace Enter hanoi(from, to, other, count)
Trace Enter hanoi(from, to, other, count)
move 1 from a to c
Trace Exit nothing
move 1 from a to b
Trace Enter hanoi(from, to, other, count)
move 1 from c to b
Trace Exit nothing
Trace Exit (:a, :b)
Note the “Trace Enter” lines. I’d like the first one to say
Trace Enter hanoi(:a, :b, :c, 2)
instead but can’t get the code right.
I don’t see how I can “unquote” the expressions further than they’ve been quoted. Can someone sugguest how I can get the values rather than the names of the parameters printed? The values are available at runtime, so that is when the expression needs to be constructed.
Note that I will also need to make this work for functions that take keyword arguments as well. That is why I’m constructing a :call Expr and then serializing it, rather than constructing a String directly.
Here’s the macroexpansion
striplines(@macroexpand(@trace(trace_hanoi, function hanoi(from, to, other, count)
if count == 1
println("move 1 from $from to $to")
return
else
hanoi(from, other, to, count - 1)
println("move 1 from $from to $to")
hanoi(other, to, from, count - 1)
return (from, to) # arbitrary result to show
end
end)))
:($(Expr(:function, :(hanoi(from, to, other, count)), quote
function var"##bodyfunction#274"()
if count == 1
println("move 1 from $(from) to $(to)")
return
else
hanoi(from, other, to, count - 1)
println("move 1 from $(from) to $(to)")
hanoi(other, to, from, count - 1)
return (from, to)
end
end
if trace_hanoi
(println)("Trace Enter ", (string)($(Expr(:copyast, :($(QuoteNode(:(hanoi(from, to, other, count)))))))))
end
var"##result#273" = var"##bodyfunction#274"()
if trace_hanoi
(println)("Trace Exit ", var"##result#273")
end
end, Symbol("##result#273"))))
My problem is readily observable in the "Trace Enter " line. I don’t see how to get the values of the parameters rather than their names, given that their names are the result of calling map
at macroexpansion time.
Thanks.