Choosing a logging library for Merino
- Status: accepted
- Date: 2021-05-11
Tracking issue: mozilla-services/merino#15
Context and Problem Statement
Merino needs a system to produce logging. Rust has several options to do this, with no clear winner. What library should Merino use?
The log
Crate
There is a de facto standard logging library for Rust,
log
. It is an important part of the decision,
but it is not a solution to the problem: it is a logging facade that provides
a way for libraries to produce their own logs, but does not provide any logging
capabilities itself. Without a logger crate to use it with, the logs compile
away to nothing.
Decision Drivers
- Sentry integration should be available
- MozLog format should be supported
- There should be both human and machine friendly logging output options.
- Library compatibility
Considered Options
- Something from the
log
ecosystem
Decision Outcome
Option 2 - Tracing. Although Slog has more momentum at this time, Tracing sets us up for a better set of tools long term.
Pros and Cons of the Options
Option 1 - Slog
slog
is an ecosystem of reusable components for structured, extensible, composable and contextual logging for Rust.
Slog's first release was 0.1.0 in June of 2016, and it's 1.0 release was in September of 2016.
To use it, developers create logger objects that provide methods to produce log lines and create sub-loggers. These loggers must be passed to lower level code explicitly to be used.
Slog is compatible with the de facto log
crate. Log lines emitted using that
system (such as by libraries) can be routed to a logger object, with no loss of
detail. Few libraries use slog directly, and none of the libraries that are
currently used in Merino do at all. Since libraries aren't using slog
, it will
be harder to make them participate in the logging hierarchy.
Structured logging is supported. Logs can carry associated data, which can aid in the machine readability of logs.
The tree of loggers is built explicitly through the loggers objects, and subloggers must be aware of superloggers, since the only way to get a sublogger is to call a method on a logger. This separates the logging structure from the call stack, but makes it awkward to recover that information should it be helpful. This means that logging generally has to be passed as arguments to many functions, making the tree of loggers less flexible.
The Sentry library for Rust has support for slog. There is a a MozLog crate for slog that Mozilla wrote.
- Good, because structured logging helps provide more useful logs.
- Good, because it has Sentry integration.
- Good, because it already has MozLog integration.
- Bad, because it has little library support.
- Bad, because explicitly building the logging tree is rigid.
Option 2 - Tracing
tracing
is a framework for instrumenting Rust programs to collect structured, event-based diagnostic information.
Tracing's first release was 0.0.0 in November of 2017. It has not had a 1.0 release. It's latest release is 0.1.26, published April 2021.
To use it, developers set up a global or scope-based subscriber of logs, which
collects spans and events that are generated in the code. Spans can be
enter
ed and exit
ed. During the time between these, all spans and events are
associated with the entered span as their parent. This association happens
explicitly, and can cross call boundaries. However, spans can be entered and
exited in more fine grained ways if needed.
Tracing is compatible with the de facto log
crate. Log lines emitted using
that system are seen as events in Tracing, with no loss of detail.
Structured logging is supported. Both spans and events can carry associated data. This data can be accessed hierarchically, building up a context of execution.
The tree of spans is built by entering spans. Loggers do not have to be aware of their parents, their logs are placed in the context of whatever set of spans has been entered at that moment. because [ one like we did with slog.
Tracing is developed as a part of the Tokio ecosystem, the same that our web
framework (Actix), http client (Reqwest), and async runtime (Tokio) are
developed under. It has some library support. Additionally, since the tree of
spans is built more implicitly, libraries that use the log
facade can
participate in our structured logging.
- Good, because structured logging helps provide more useful logs.
- Good, because it has good integration into the libraries we use.
- Good, because implicitly building the logging hierarchy and context is flexible.
- Bad, because it lacks Sentry support.
- Bad, because it lacks MozLog support.
Option 3 - Something in the log
ecosystem
This option was not considered deeply because log
does not support structured
logging. Not being able to attach concrete data to logs makes much of the
logging tasks much harder.
- Bad, because it lacks structured logging.