Module/file/line for log message generated by a macro

I have a module which exports a macro that checks something, implemented in a function, and warns if an invariant is not maintained, via @warn.

I want to provide correct location information, but can’t figure it out: eg in the MWE

# save in Foo.jl
module Foo

export @bar

function _bar(_module, _file, _line, x)
    if x > 0
        @warn "you have been warned" _module = _module _file = _file _line = _line
    end
end

macro bar(x)
    quote _bar(@__MODULE__, @__FILE__, @__LINE__, $x) end
end

end # module

called as

# in /tmp/demo.jl
include("/tmp/Foo.jl")
using .Foo
@bar 1

I get

julia> @bar 1
┌ Warning: you have been warned
└ @ Main /tmp/Foo.jl:13

the module is correct, but the file name and the line number refer to the module code instead of the call site (I want /tmp/demo.jl:4).

You are looking for the implicit __source__ macro argument (and possibly __module__ if you also want the correct source module).

Foo.jl :

module Foo

export @bar

function _bar(_module, _file, _line, x)
    if x > 0
        @warn "you have been warned" _module = _module _file = _file _line = _line
    end
end

macro bar(x)
    file = String(__source__.file)
    line = __source__.line
    mod = String(__module__)
    quote
        _bar($mod, $file, $line, $x)
    end
end

end # module

demo.jl:

# in /tmp/demo.jl
include("Foo.jl")
using .Foo
@bar 1

This gives:

$ julia demo.jl 
┌ Warning: you have been warned
└ @ Main /tmp/demo.jl:4

This has documentation in Julia >= 1.7 JuliaLang/julia#38987.

2 Likes