Suppose one has code structured a bit like this (kinda exaggerated for clarity):
solvemyproblem(array) = map(solveone, array)
solveone(x) = ...stuff...
function somedeepdownfunction(x)
if nogood(x)
@warn "No good, using a worse method!"
return worse(x)
end
return better(x)
end
What is the best way to make sure the warning is only printed once even if array has alot of values which triggers the warning?
I think I can work it out using with_logger and a custom logger but perhaps there are better ways.
I’m not too concerned with speed and all code is in the same package.
You can write @warn "The message" maxlog=1, this should make the error appear only once (in each run I believe, could be different). Is that what you want?
Thanks, looks quite promising. Im away from the computer so I can’t check, but does it only reset when the session is restarted? It would need to be reset everytime solvemyproblem is called.
Hi, I just did a little code dive. Usually, the counter is only reset when you start a new session, but you can either replace the logger or reset the counter manually:
julia> function logtest()
x = rand()*rand()
@warn "Some message" maxlog=3
return x
end;
julia> function runlogtest(n)
for _ in 1:n
logtest()
end
end;
julia> runlogtest(10)
┌ Warning: Some message
└ @ Main REPL[14]:3
┌ Warning: Some message
└ @ Main REPL[14]:3
┌ Warning: Some message
└ @ Main REPL[14]:3
julia> runlogtest(10) # this does not log again
julia>
Here’s how to do it. I choose to reset the message_limits counter instead of replacing the entire logger. The key is, that every log message gets an id internally, which is relatively stable and is for example used to check against the maxlog limit. The id can easily be set by hand and the corresponding counter reset:
julia> using Logging
julia> function logtest_resettable()
a = rand()
@warn "This warning will be shown twice per run!" a=a maxlog=2 _id=:ResetMyCounter # write whatever you want here, but it should be a symbol
return a
end
logtest_resettable (generic function with 1 method)
julia> function runtest_and_reset(n)
for _ in 1:n
logtest_resettable()
end
Logging.current_logger().message_limits[:ResetMyCounter] = 2 # insert appropriate id here and maxlog number
end
runtest_and_reset (generic function with 1 method)
julia> runtest_and_reset(5)
┌ Warning: This warning will be shown twice per run!
│ a = 0.33945681655296056
└ @ Main REPL[21]:3
┌ Warning: This warning will be shown twice per run!
│ a = 0.835372097983738
└ @ Main REPL[21]:3
2
julia> runtest_and_reset(5)
┌ Warning: This warning will be shown twice per run!
│ a = 0.2205420236924749
└ @ Main REPL[21]:3
┌ Warning: This warning will be shown twice per run!
│ a = 0.5396194992303944
└ @ Main REPL[21]:3
2
And it indeed does log twice per run. I kinda believe there should be a package for that already, but as long as we don’t find it, this should do Have a nice day.
Edit: on second though, Logging. with_logger(myfunction, Logging.ConsoleLogger()) is probably easier and more stable. I’d advise on using that one
Using ConsoleLogger definitely looks easiest. When I tried in VS code I found that the logger was of a different kind though, current_logger() == VSCodeServer.VSCodeLogger() and it does not seem to be reset when recreated so the log is only printed once. It’s not perfectly clear if there are any adverse consequences of not using this logger in VS code but I can probably sort that out.
I realized that I might want to attach some metadata in the (near) top level so perhaps I’ll go with a custom logger after all, but the id makes it so much easier to do correctly and it should be possible to ‘latch on’ to the maxlog parameter so that things are more generic.
In either case, I’m satisfied with the answers. Thank you so much for your efforts!