|
12 | 12 | for level in [:debug, :info, :warn, :error] |
13 | 13 | @eval begin |
14 | 14 | macro $(Symbol("safe_$level"))(ex...) |
15 | | - macrocall = :(@placeholder $(ex...)) |
| 15 | + macrocall = :(@placeholder $(ex...) _file=$(String(__source__.file)) _line=$(__source__.line)) |
16 | 16 | # NOTE: `@placeholder` in order to avoid hard-coding @__LINE__ etc |
17 | 17 | macrocall.args[1] = Symbol($"@$level") |
18 | 18 | quote |
19 | | - old_logger = global_logger() |
20 | 19 | io = IOContext(Core.stderr, :color=>get(stderr, :color, false)) |
21 | | - min_level = _invoked_min_enabled_level(old_logger) |
22 | | - global_logger(Logging.ConsoleLogger(io, min_level)) |
23 | | - ret = $(esc(macrocall)) |
24 | | - global_logger(old_logger) |
25 | | - ret |
| 20 | + # ideally we call Logging.shouldlog() here, but that is likely to yield, |
| 21 | + # so instead we rely on the min_enabled_level of the logger. |
| 22 | + # in the case of custom loggers that may be an issue, because, |
| 23 | + # they may expect Logging.shouldlog() getting called, so we use |
| 24 | + # the global_logger()'s min level which is more likely to be usable. |
| 25 | + min_level = _invoked_min_enabled_level(global_logger()) |
| 26 | + safe_logger = Logging.ConsoleLogger(io, min_level) |
| 27 | + # using with_logger would create a closure, which is incompatible with |
| 28 | + # generated functions, so instead we reproduce its implementation here |
| 29 | + safe_logstate = Base.CoreLogging.LogState(safe_logger) |
| 30 | + @static if VERSION < v"1.11-" |
| 31 | + t = current_task() |
| 32 | + old_logstate = t.logstate |
| 33 | + try |
| 34 | + t.logstate = safe_logstate |
| 35 | + $(esc(macrocall)) |
| 36 | + finally |
| 37 | + t.logstate = old_logstate |
| 38 | + end |
| 39 | + else |
| 40 | + Base.ScopedValues.@with( |
| 41 | + Base.CoreLogging.CURRENT_LOGSTATE => safe_logstate, $(esc(macrocall)) |
| 42 | + ) |
| 43 | + end |
26 | 44 | end |
27 | 45 | end |
28 | 46 | end |
|
0 commit comments