Designing the Logger Class

The discussion Designing the Logging Component ends in concluding that ParallelZone needs a Logger class. This page details the design and architecture of the Logger class and the underlying infrastructure needed to make it work.

What is the Logger Class?

The Logger class is the user-facing API of ParallelZone’s logging component. The Logger class is used by users of ParallelZone to log events, i.e., errors, warnings, progress, etc.

Why do we need the Logger Class?

As summarized in Designing the Logging Component, we are not aware of any existing logging solutions that do everything we need. We have thus chosen to implement the missing features, to our liking, within the Logger class. The Logger class also provides a stable API for ParallelZone users in the event we should need to add additional logging capabilities or switch out the backend. The Logger class also separates the concern of “what to log” from “how to log it”; “how to log it” is the responsibility of the sink (which is currently an implementation detail of the Logger class).

Logger Considerations

The considerations for the Logger class are the considerations from Designing the Logging Component not addressed there. Specifically:

  1. Multiple logging levels.

    • Printing every message should be reserved for difficult debugging.

    • Severity level (info, warn, etc.) used to triage what to print.

  2. Concurrency aware.

    • Thread-safe ideally.

  3. Different “sinks”

    • Console, file, databases.

  4. Enable/disable logging

    • Can be expensive, too verbose, etc.

    • Assume logging disabled for performance runs

    • Ideally logger configurable at compile and runtime.

Existing Logger Solutions

Existing Logging Solutions covered the existing logging solutions in detail and will not be replicated here. Instead we point out that of the available choices, Spdlog has most of the features we want and is heavily supported. As seen in the next section we have opted to build our Logger infrastructure around Spdlog.

Logger Design

../../_images/logger_arch.png

Fig. 13 Architecture of the Logger class and its infrastructure.

For the first implementation of the logging component we adopted the simple architecture shown in Figure Fig. 13. Users of ParallelZone see one class, Logger. As a first pass, Logger simply provides APIs for printing arbitrary data, already in a std::string (or implicitly convertible to a std::string) at various severity levels. Eventually, this may be expanded to support more fine-grained control over the log formatting.

Internally Logger is implemented by a LoggerPIMPL object. The literal LoggerPIMPL object is an abstract base class which defines the API for actual implementations. Our Spdlog-based implementation derives the SpdlogPIMPL class from LoggerPIMPL to implement the parts of the PIMPL API common to all Spdlog-based implementations.

For now we have two sinks, and they are implemented by further specializing the SpdlogPIMPL. The sinks, StdoutSpdlog and FileSpdlog respectively output logs to standard out and a specified file.

This design addresses the considerations remaining from Designing the Logging Component by:

  1. Multiple logging levels.

    • Gained by using Spdlog.

  2. Concurrency aware.

    • Spdlog is thread-safe.

  3. Different “sinks”

    • Provided by Spdlog.

  4. Enable/disable logging

    • Spdlog supports log filtering by severity.

    • Logger can have a null pointer to represent null logging.

Future Considerations

The current design gets the job done, while being amenable to extension. In particular we note:

  • Can add Sink classes so users define their own sink behavior (Spdlog also allows custom sinks, so our Sink class would wrap theirs).

  • Can add more formatting options to Logger. Spdlog uses the C++ fmt library (which the C++20 extension is based heavily on). We can expose this down the road.

  • Can add support for more types beyond std::string. At the end of the day we ultimately need to print strings so supporting of other types is simply a convenience mechanism for channeling them into the string paths.

  • Can add wide-character support. Spdlog already supports it so it’s just a matter of exposing it.