Skip to content

Commit 617229c

Browse files
committed
All the filtered loggers
1 parent 990cf1e commit 617229c

File tree

6 files changed

+86
-32
lines changed

6 files changed

+86
-32
lines changed

README.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,18 @@ logger = global_logger()
3636
# Loggers introduced by this package:
3737

3838

39-
This package introduces 3 new loggers.
40-
The `DemuxLogger`, the `FilteredLogger` and the `FileLogger`.
39+
This package introduces 5 new loggers.
40+
The `DemuxLogger`, the `FileLogger`, and 3 types of filtered logger.
4141
All of them just wrap existing loggers.
42-
The `DemuxLogger` sends the logs to multiple different loggers.
43-
The `FilteredLogger` lets you add rules to cause a logger to ignore some inputs.
42+
- The `DemuxLogger` sends the logs to multiple different loggers.
43+
- The `FileLogger` is a simple logger sink that writes to file.
44+
- The 3 filter loggers are used to control if a message is written or not
45+
- The `MinLevelLogger` only allowes messages to pass that are above a given level of severity
46+
- The `EarlyFilteredLogger` lets you write filter rules based on the `level`, `module`, `group` and `id` of the log message
47+
- The `ActiveFilteredLogger` lets you filter based on the full content
4448

4549

46-
By combining `DemuxLogger` with `FilteredLogger`s you can arbitrarily route log messages, wherever you want.
50+
By combining `DemuxLogger` with filter loggers you can arbitrarily route log messages, wherever you want.
4751

4852
The `FileLogger` is just a convience wrapper around the base julia `SimpleLogger`,
4953
to make it easier to pass in a filename, rather than a stream.
@@ -56,13 +60,13 @@ It takes a list of loggers.
5660
It also has the keyword argument `include_current_global`,
5761
to determine if you also want to log to the global logger.
5862

59-
It is up to those loggers to determine if they will accept it.\
63+
It is up to those loggers to determine if they will accept it.
6064
Which they do using their methods for `shouldlog` and `min_enabled_level`.
61-
Or you can do, by wrapping them in a `FilteredLogger` as discussed below.
65+
Or you can do, by wrapping them in a filtered logger as discussed below.
6266

6367
The `FileLogger` does logging to file.
6468
It is really simple.
65-
It takes a filename; and the minimum level it should log.
69+
It takes a filename.
6670

6771
### Demo
6872
We are going to log info and above to one file,
@@ -72,8 +76,8 @@ and warnings and above to another.
7276
julia> using Logging; using LoggingExtras;
7377
7478
julia> demux_logger = DemuxLogger(
75-
FileLogger("info.log", min_level=Logging.Info),
76-
FileLogger("warn.log", min_level=Logging.Warn),
79+
MinLevelLogger(FileLogger("info.log"), Logging.Info),
80+
MinLevelLogger(FileLogger("warn.log"), Logging.Warn),
7781
include_current_global=false
7882
);
7983

src/LoggingExtras.jl

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,33 @@ import Base.CoreLogging:
99
handle_message, shouldlog, min_enabled_level, catch_exceptions
1010

1111
export demux_global_logger,
12-
DemuxLogger, ActiveFilteredLogger, FileLogger
12+
DemuxLogger, FileLogger,
13+
ActiveFilteredLogger, EarlyFilteredLogger, MinLevelLogger
14+
15+
16+
######
17+
# Utilities for dealing with compositional loggers.
18+
# Since the logging system itself will not engage its checks
19+
# Once the first logger has started, any compositional logger needs to check
20+
# before passing anything on.
21+
22+
# For checking child logger, need to check both `min_enabled_level` and `shouldlog`
23+
function comp_shouldlog(logger, args...)
24+
level = first(args)
25+
min_enabled_level(logger) <= level && shouldlog(logger, args...)
26+
end
27+
28+
# For checking if child logger will take the message you are sending
29+
function comp_handle_message_check(logger, args...; kwargs...)
30+
level, message, _module, group, id, file, line = args
31+
return comp_shouldlog(logger, level, _module, group, id)
32+
end
33+
###############################
1334

1435
include("demuxlogger.jl")
1536
include("activefiltered.jl")
37+
include("earlyfiltered.jl")
38+
include("minlevelfiltered.jl")
1639
include("filelogger.jl")
1740

1841
end # module

src/activefiltered.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The `filter` should be a function that returns a boolean.
1717
`true` if the message should be logged and `false` if not.
1818
As input it will be given a named tuple with the following fields:
1919
`(level, message, _module, group, id, file, line, kwargs)`
20-
See `?LoggingExtra.HandleMessageArgs` for more information on what each is.
20+
See `?LoggingExtra.handle_message_ags` for more information on what each is.
2121
"""
2222
struct ActiveFilteredLogger{T <: AbstractLogger, F} <: AbstractLogger
2323
filter::F
@@ -26,25 +26,25 @@ end
2626

2727

2828
function handle_message(logger::ActiveFilteredLogger, args...; kwargs...)
29-
log_args = HandleMessageArgs(args...; kwargs...)
30-
if logger.filter(log_args)
31-
handle_message(logger.logger, args...; kwargs...)
32-
end
29+
log_args = handle_message_args(args...; kwargs...)
30+
if comp_handle_message_check(logger.logger, args...; kwargs...)
31+
if logger.filter(log_args)
32+
handle_message(logger.logger, args...; kwargs...)
33+
end
34+
end
3335
end
3436

35-
# As an optimisation, we query if the logger we are sending this to will accept
36-
# this log. If not then there is no point in us taking it
3737
function shouldlog(logger::ActiveFilteredLogger, args...)
38-
return shouldlog(logger.logger, args...)
38+
return comp_shouldlog(logger.logger, args...)
3939
end
4040

4141
min_enabled_level(logger::ActiveFilteredLogger) = min_enabled_level(logger.logger)
4242
catch_exceptions(logger::ActiveFilteredLogger) = catch_exceptions(logger.logger)
4343

4444
"""
45-
HandleMessageArgs
45+
handle_message_args
4646
47-
This is an alias for a NamedTuple containing all the arguments the logger gives
47+
This creates NamedTuple containing all the arguments the logger gives
4848
to `handle_message`
4949
It is the type pased to the active logger filter.
5050
These argument come from the logging macro (@info`, `@warn` etc).
@@ -62,7 +62,7 @@ These argument come from the logging macro (@info`, `@warn` etc).
6262
source location of a log message.
6363
* `kwargs...`: Any keyword or position arguments passed to the logging macro
6464
"""
65-
function HandleMessageArgs(args...; kwargs...)
65+
function handle_message_args(args...; kwargs...)
6666
fieldnames = (:level, :message, :_module, :group, :id, :file, :line, :kwargs)
6767
fieldvals = (args..., kwargs)
6868
return NamedTuple{fieldnames, typeof(fieldvals)}(fieldvals)

src/demuxlogger.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@ function DemuxLogger(loggers::Vararg{AbstractLogger}; include_current_global=tru
2121
DemuxLogger(loggers)
2222
end
2323

24-
function handle_message(demux::DemuxLogger, level, message, _module, group, id, file, line; kwargs...)
24+
function handle_message(demux::DemuxLogger, args...; kwargs...)
2525
for logger in demux.loggers
26-
if min_enabled_level(logger)<= level && shouldlog(logger, level, _module, group, id)
27-
# we bypassed those checks above, so we got to check them for each
28-
handle_message(logger, level, message, _module, group, id, file, line; kwargs...)
26+
if comp_handle_message_check(logger, args...; kwargs...)
27+
handle_message(logger, args...; kwargs...)
2928
end
3029
end
3130
end
3231

33-
function shouldlog(demux::DemuxLogger, level, _module, group, id)
34-
any(shouldlog(logger, level, _module, group, id) for logger in demux.loggers)
32+
function shouldlog(demux::DemuxLogger, args...)
33+
any(comp_shouldlog(logger, args...) for logger in demux.loggers)
3534
end
3635

3736
function min_enabled_level(demux::DemuxLogger)

src/filelogger.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
# TODO: Maybe this should just be a function
2-
# It is a super thing wrapper around a SimpleLogger
3-
4-
51
struct FileLogger <: AbstractLogger
62
logger::SimpleLogger
73
always_flush::Bool

test/runtests.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,35 @@ end
5252
end
5353
@test length(testlogger.logs) == 2
5454
end
55+
56+
@testset "Early Filter" begin
57+
testlogger = TestLogger()
58+
filtered_logger = EarlyFilteredLogger(testlogger) do logargs
59+
logargs.level == Info # Only exactly Info, nothing more nothing less
60+
end
61+
62+
with_logger(filtered_logger) do
63+
@info "info1"
64+
@warn "Yo Dawg! It is a warning"
65+
@info "info2"
66+
@info "Yo Dawg! It's all good"
67+
end
68+
@test length(testlogger.logs) == 3
69+
end
70+
71+
@testset "MinLevel Filter" begin
72+
testlogger = TestLogger()
73+
filtered_logger = MinLevelLogger(testlogger, Warn)
74+
75+
with_logger(filtered_logger) do
76+
@info "info1"
77+
@warn "Yo Dawg! It is a warning"
78+
@info "info2"
79+
@info "Yo Dawg! It's all good"
80+
@info "info 3"
81+
@error "MISTAKES WERE MADE"
82+
end
83+
@test length(testlogger.logs) == 2
84+
end
85+
86+

0 commit comments

Comments
 (0)