@@ -7,7 +7,7 @@ using Logging
77
88import Logging: shouldlog, min_enabled_level, catch_exceptions, handle_message
99import Base: write, close, rawhandle
10- export RollingLogger, RollingFileWriter, postrotate
10+ export RollingLogger, RollingFileWriter, RollingFileWriterTee, postrotate
1111
1212const BUFFSIZE = 1024 * 16 # try and read 16K pages when possible
1313
@@ -28,12 +28,14 @@ mutable struct RollingFileWriter <: IO
2828 lck:: ReentrantLock
2929 procstream:: Union{Nothing,Pipe}
3030 procstreamer:: Union{Nothing,Task}
31+ procstreamteelogger:: Union{Nothing,AbstractLogger}
32+ assumed_level:: LogLevel
3133 postrotate:: Union{Nothing,Function}
3234
3335 function RollingFileWriter (filename:: String , sizelimit:: Int , nfiles:: Int )
3436 stream = open (filename, " a" )
3537 filesize = stat (stream). size
36- new (filename, sizelimit, nfiles, filesize, stream, ReentrantLock (), nothing , nothing , nothing )
38+ new (filename, sizelimit, nfiles, filesize, stream, ReentrantLock (), nothing , nothing , nothing , Logging . Info, nothing )
3739 end
3840end
3941
@@ -47,6 +49,15 @@ function postrotate(fn::Function, io::RollingFileWriter)
4749 nothing
4850end
4951
52+ """
53+ Tee all lines to the provided logger
54+ """
55+ function tee (io:: RollingFileWriter , logger:: AbstractLogger , level:: LogLevel )
56+ io. procstreamteelogger = logger
57+ io. assumed_level = level
58+ io
59+ end
60+
5061"""
5162Close any open file handle and streams.
5263A closed object must not be used again.
@@ -57,6 +68,7 @@ function close(io::RollingFileWriter)
5768 lock (io. lck) do
5869 io. procstream = nothing
5970 io. procstreamer = nothing
71+ io. procstreamteelogger = nothing
6072 end
6173 end
6274 close (io. stream)
@@ -128,6 +140,24 @@ function rotate_file(io::RollingFileWriter)
128140 nothing
129141end
130142
143+ """
144+ Tees raw log entries made a RollingFileWriter on to a provided Julia AbstractLogger.
145+
146+ Each line of text is taken as a single log message.
147+
148+ All log entries are made with the same log level, which can be provided during construction. It leaves
149+ further examination/parsing of log messages (to extract parameters, or detect exact log levels) to the
150+ downstream logger.
151+ """
152+ function RollingFileWriterTee (filename:: String , sizelimit:: Int , nfiles:: Int , logger:: AbstractLogger , assumed_level:: LogLevel = Logging. Info)
153+ io = RollingFileWriter (filename, sizelimit, nfiles)
154+ RollingFileWriterTee (io, logger, assumed_level)
155+ end
156+
157+ function RollingFileWriterTee (io:: RollingFileWriter , logger:: AbstractLogger , assumed_level:: LogLevel = Logging. Info)
158+ tee (io, logger, assumed_level)
159+ end
160+
131161"""
132162RollingLogger(filename, sizelimit, nfiles, min_level=Info; timestamp_identifier::Symbol=:time)
133163Log into a log file. Rotate log file based on file size. Compress rotated logs.
@@ -205,10 +235,15 @@ end
205235
206236function stream_process_logs (writer:: RollingFileWriter )
207237 try
208- bytes = readavailable (writer. procstream)
209- while ! isempty (bytes)
210- write (writer, bytes)
211- bytes = readavailable (writer. procstream)
238+ while true
239+ logline = readline (writer. procstream; keep= true )
240+ if ! isempty (logline)
241+ write (writer, logline)
242+ if writer. procstreamteelogger != = nothing
243+ @logmsg (writer. assumed_level, strip (logline))
244+ end
245+ end
246+ eof (writer. procstream) && break
212247 end
213248 finally
214249 close (writer. procstream)
@@ -225,7 +260,13 @@ function rawhandle(writer::RollingFileWriter)
225260 writer. procstream = Pipe ()
226261 Base. link_pipe! (writer. procstream)
227262 writer. procstreamer = @async begin
228- stream_process_logs (writer)
263+ if writer. procstreamteelogger != = nothing
264+ with_logger (writer. procstreamteelogger) do
265+ stream_process_logs (writer)
266+ end
267+ else
268+ stream_process_logs (writer)
269+ end
229270 end
230271 end
231272 return rawhandle (Base. pipe_writer (writer. procstream))
0 commit comments