using Logging
"""
@no_logging(code_to_execute)
Execute `code_to_execute` sending all logging to the [`Logging.NullLogger`](@ref).
"""
macro no_logging(code)
return :( with_logger(NullLogger()) do
$(esc(code))
end)
end
It seems to work almost as I want it to, the only problem that I have encountered is that it cannot handle assignments, e.g.
a = 0
@no_logging a = sin(8)
@assert a == sin(8)
would create a local variable a and which would go out of scope on the next line making the assertion fail. Is there a way to fix this?
Yes, that is how I deal with the issue now, but if @no_logging could handle any code then it could be offered as a contribution to a respected library like LoggingExtras.jl or maybe even the Logging standard library.
Depending on what pre-transformed code you want to support, this can go from fairly simple to frustratingly complex. If you only need to support the one assignment, then it’s just turning @no_logging a = sin(8) into a = with_logger(NullLogger()) do; sin(8) end, as with_logger returns the result of its input function call and the a assignment remains in the scope it occurs in.
However, things get more complicated with block expressions. A begin block could hold multiple assignments, so you’d have to make the with_logger call return multiple values for assignment to multiple variables a, b, c = with_logger(...). You’d generally want the block expression to remain outside the with_logger call so the assignment occurs where (let introduces a nested layer of local scope) and when (if makes code conditional) it should. However, that involves unintuitive rules about what part of the expression counts as code.
Implicit scope-introducing macros are generally this difficult; think of how the global scope evaluation of BenchmarkTools throws people off, and eval of the input expression in the global scope is already the simplest situation. You can save almost as much typing with a derivative higher-order function instead of a macro with specific rules:
null_log(f) = with_logger(f, NullLogger())
a = null_log() do; sin(8) end
which will be easier for users to control the scope of their variable assignments.