I’m currently trying to build a logging demonstration using the JuliaLogging components (standard library + a few seemingly very standard packages).
I may be wrong, however I think there are 3 parts to logging. This isn’t specific to Julia, this is more general and applies to any language, really.
- Log data capturing (sources)
- Log string (or otherwise - might be a binary string) formatting
- Log sinks
Sources/data capture are some statements in code which specify the inputs. It could be as simple as a log message string, or it might include metadata, such as a module name, line number, or other data.
Formatters are things which take data from a source and structure it into some human or machine readable string.
Log sinks are devices which can accept string formatted logs and write or store them somewhere. Files, the console, or databases could be examples of this.
This is, in an approximate sense, how most logging frameworks are structured.
Julia’s logging tools might be structured like this, or it might be a bit different. I don’t have a solid understanding of how everything fits together yet. Please do let me know if my mental model is wrong.
What is relatively easy to understand are the sources. (Because these are fixes for any application.)
We have the macros
@error
@warn
@info
@debug
These macros expect a string to follow and then optionally, metadata. Some additional metadata is automatically provided, such as the module name, function name and line number.
These macros are all provided by the Logging
package.
There are 11 other packages mentioned on JuliaLogging. This is where things get complicated. If I understand correctly, all of these things are supposed to interop together.
In regards to formatting, there is the LoggingFormats
package. However, this appears to contain a predefined set of formats, which includes a tool for formatting logs in JSON format. The more general purpose FormatLogger
is actually in LoggingExtras
.
In this package, we also find the FileLogger
, which is a sink.
Ok, so let’s accept that sources, formatting intermediaries and sinks are not separated into seperate packages but mixed together. Fine.
It seems I have all the pieces.
I want to be able to
@info "just a test!"
and have this write to a file, formatted using FormatLogger
.
I’m somewhat lost as to how to take these “individual pieces” and put them together to achieve this.
Here’s some snippets of code where I’ve been testing out a few things.
using Logging
using LoggingExtras
function (@main)(args)
println("hello world")
- Just the standard stdout/stderr default log sink and format.
@info "hello world - info"
@warn "hello world - warning"
It will give you
[ Info: hello world - info
┌ Warning: hello world - warning
└ @ Main ~/work/tmp/JuliaLogging/main.jl:9
- I managed to get logging to a file to work. For some reason, I needed a
SimpleLogger
?
io_stream = open("example-log-stream.txt", "a")
logger = SimpleLogger(io_stream, Debug)
with_logger(logger) do
@info "SimpleLogger info log"
@warn "SimpleLogger warning log"
end
This is the output
┌ Info: SimpleLogger info log
└ @ Main /home/user/work/tmp/JuliaLogging/main.jl:14
┌ Warning: SimpleLogger warning log
└ @ Main /home/user/work/tmp/JuliaLogging/main.jl:15
so I would guess that a SimpleLogger
is a type of FormatLogger
?
They both inherit from AbstractLogger
, so this doesn’t seem to check out exactly.
Maybe a SimpleLogger
is an alternative to a FormatLogger
and defines a fixed format for logging?
- I also managed to get
FileLogger
working. But this seems to be using theSimpleLogger
format, despite none of the code specifying this.
file_logger = FileLogger(io_stream)
with_logger(file_logger) do
@info "info to file_logger stream"
end
Here’s the output
┌ Info: info to file_logger stream
└ @ Main /home/user/work/tmp/JuliaLogging/main.jl:31
which is suspiciously similar to the above.
The code ends with a final end
for the end of function (@main)
end
The specific question I have is how do I plumb a FileLogger up to a FormatLogger?
To rephrase it slightly - how do I log to a file using a user-defined format?
More generally, I am somewhat lost when it comes to this (quite extensive) logging ecosystem. If anyone has any wisdom which can help me to understand it that would also be much appreciated.