@@ -2,39 +2,64 @@ using Dates
22import Base: isless
33
44raw """
5- DatetimeRotatingFileLogger
5+ DatetimeRotatingFileLogger(dir, file_pattern; always_flush=true)
6+ DatetimeRotatingFileLogger(f::Function, dir, file_pattern; always_flush=true)
67
7- Constructs a FileLogger that rotates its file based on the current date.
8+ Construct a `DatetimeRotatingFileLogger` that rotates its file based on the current date.
9+ The constructor takes a log output directory, `dir`, and a filename pattern.
810The filename pattern given is interpreted through the `Dates.format()` string formatter,
911allowing for yearly all the way down to millisecond-level log rotation. Note that if you
1012wish to have a filename portion that is not interpreted as a format string, you may need
11- to escape portions of the filename, as shown below:
13+ to escape portions of the filename, as shown in the example below.
1214
13- Usage example:
15+ It is possible to pass a formatter function as the first argument to control the output.
16+ The formatting function should be of the form `f(io::IOContext, log_args::NamedTuple)`
17+ where `log_args` has the following fields:
18+ `(level, message, _module, group, id, file, line, kwargs)`.
19+ See `?LoggingExtra.handle_message_args` for more information about what each field represents.
1420
15- logger = DatetimeRotatingFileLogger(log_dir, raw"\a\c\c\e\s\s -YYYY-mm-dd.\l\o\g ")
21+ # Examples
22+
23+ ```julia
24+ # Logger that logs to a new file every day
25+ logger = DatetimeRotatingFileLogger(log_dir, raw"\a\c\c\e\s\s -yyyy-mm-dd.\l\o\g ")
26+
27+ # Logger with a formatter function that rotates the log file hourly
28+ logger = DatetimeRotatingFileLogger(log_dir, raw"yyyy-mm-dd-HH.\l\o\g ") do io, args
29+ println(io, args.level, " | ", args.message)
30+ end
1631"""
1732mutable struct DatetimeRotatingFileLogger <: AbstractLogger
18- logger:: SimpleLogger
33+ logger:: Union{ SimpleLogger,FormatLogger}
1934 dir:: String
2035 filename_pattern:: DateFormat
2136 next_reopen_check:: DateTime
2237 always_flush:: Bool
2338end
2439
2540function DatetimeRotatingFileLogger (dir, filename_pattern; always_flush= true )
26- format = DateFormat (filename_pattern)
27- return DatetimeRotatingFileLogger (
28- SimpleLogger (open (calc_logpath (dir, filename_pattern), " a" ), BelowMinLevel),
29- dir,
30- format,
31- next_datetime_transition (format),
32- always_flush,
33- )
41+ DatetimeRotatingFileLogger (nothing , dir, filename_pattern; always_flush= always_flush)
42+ end
43+ function DatetimeRotatingFileLogger (f:: Union{Function,Nothing} , dir, filename_pattern; always_flush= true )
44+ # Construct the backing logger with a temp IOBuffer that will be replaced
45+ # by the correct filestream in the call to reopen! below
46+ logger = if f === nothing
47+ SimpleLogger (IOBuffer (), BelowMinLevel)
48+ else # f isa Function
49+ FormatLogger (f, IOBuffer (); always_flush= false ) # no need to flush twice
50+ end
51+ # abspath in case user constructs the logger with a relative path and later cd's.
52+ drfl = DatetimeRotatingFileLogger (logger, abspath (dir),
53+ DateFormat (filename_pattern), now (), always_flush)
54+ reopen! (drfl)
55+ return drfl
3456end
3557
58+ similar_logger (:: SimpleLogger , io) = SimpleLogger (io, BelowMinLevel)
59+ similar_logger (l:: FormatLogger , io) = FormatLogger (l. f, io, l. always_flush)
3660function reopen! (drfl:: DatetimeRotatingFileLogger )
37- drfl. logger = SimpleLogger (open (calc_logpath (drfl. dir, drfl. filename_pattern), " a" ), BelowMinLevel)
61+ io = open (calc_logpath (drfl. dir, drfl. filename_pattern), " a" )
62+ drfl. logger = similar_logger (drfl. logger, io)
3863 drfl. next_reopen_check = next_datetime_transition (drfl. filename_pattern)
3964 return nothing
4065end
0 commit comments