@@ -2,39 +2,64 @@ using Dates
2
2
import Base: isless
3
3
4
4
raw """
5
- DatetimeRotatingFileLogger
5
+ DatetimeRotatingFileLogger(dir, file_pattern; always_flush=true)
6
+ DatetimeRotatingFileLogger(f::Function, dir, file_pattern; always_flush=true)
6
7
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.
8
10
The filename pattern given is interpreted through the `Dates.format()` string formatter,
9
11
allowing for yearly all the way down to millisecond-level log rotation. Note that if you
10
12
wish 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.
12
14
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.
14
20
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
16
31
"""
17
32
mutable struct DatetimeRotatingFileLogger <: AbstractLogger
18
- logger:: SimpleLogger
33
+ logger:: Union{ SimpleLogger,FormatLogger}
19
34
dir:: String
20
35
filename_pattern:: DateFormat
21
36
next_reopen_check:: DateTime
22
37
always_flush:: Bool
23
38
end
24
39
25
40
function 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
34
56
end
35
57
58
+ similar_logger (:: SimpleLogger , io) = SimpleLogger (io, BelowMinLevel)
59
+ similar_logger (l:: FormatLogger , io) = FormatLogger (l. f, io, l. always_flush)
36
60
function 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)
38
63
drfl. next_reopen_check = next_datetime_transition (drfl. filename_pattern)
39
64
return nothing
40
65
end
0 commit comments