The log
crate
Coupling
println!
and its sibling eprintln!
can get you started, but they won't get you very far.
Our ultimate goal is to monitor our applications in production environments. Each production
environment is its own little world, with its own constraints and requirements. In particular,
expectations around log data vary wildly: some environments expect logs to be written to
stdout
, others to stderr
, others to a file, others to a socket, and so on.
println!
breaks down quickly in the face of such requirements: it couples together the
information that we want to log (i.e. the message) with the way we want to log it (i.e. the
destination, stdout
).
To change the destination, we would have to change the code that produces the log message.
That's a problem: that log message might be coming from a third-party library,
or from a part of the codebase that we don't own.
Having to fork those modules to accommodate the logging requirements of the final application
is a non-starter.
Facade
We need to decouple.
On one side, we will have an instrumentation API, used to emit log messages from the
application and its dependencies.
On the other side, we will have the processing code, the logic in charge of deciding
what to do with the log messages that have been produced.
If you are familiar with the Gang of Four's Design Patterns, you might have recognized this as an instance of the facade pattern.
The log
crate
The facade pattern only works if the ecosystem, as a whole, standardizes around the same facade. You can then use a single pipeline to collect and process instrumentation data coming from both first party code and third party dependencies.
In the early days of the Rust ecosystem, the log
crate arose as the de-facto standard
logging facade for Rust applications.
Let's have a look at it!
Exercise
The exercise for this section is located in 01_structured_logging/01_log_crate