3 things that make logging fast and secure

Thursday December 16, 2021

Log4J is making the news because of recent major security vulnerabilities. Writing secure software is extremely hard, and logging frameworks are often overlooked as a simple, unimportant component.

Any software component that parses and outputs user input needs to be considered seriously from a security standpoint.

Being written in C++, Quasar does not use log4j. It does not use or any off-the-shelve components, either.
Quasar has its bespoke log engine. Sounds crazy?

Here we explore three characteristics that make it secure and fast.

It’s asynchronous

Asynchronous logging is a must for high-performance applications. When Quasar logs something, the actual logging occurs in a dedicated thread that will not block the execution flow.

For example, if we take this piece of code:

for (const auto & [uid, v] : values_map)
    // force the type to std::string to avoid having the data
    // in a view
    const std::string key_name = uid.empty() ? default_key_name : fmt::format("{}.uid_{}", k, uid.value());
    const auto ec              = store_locally(key_name, v);

    if (ec)
            "could not store local key {}: {}", key_name, 

When the log is emitted, the string is formatted into a log packet. The log packet is then pushed down a lock-free asynchronous queue. A background thread will read from the asynchronous line and write the content on the configurable sink (console, event log, file…).

Logging will thus never result in waiting for I/O, and the performance impact is minimal.

Tight memory management

Log packets used for logging are pre-allocated on startup, reducing the performance penalty of logging. But it’s not just a performance gain; it’s also a security advantage.

The loglines are formatted so that if they exceed the packet size, they will be trimmed down. This size limit prevents log trashing and seriously limits the potential for memory overruns.

In addition to that, log packets exist in a separate memory area with fences. If a memory overrun occurs despite trimming, it will be seriously mitigated.

Compile-time format checks

Let’s look at our piece of code again:

    "could not store local key {}: {}", key_name, ec.message());

As you can see, we don’t use printf specifiers. If you’re into having your software listed on 0-days exploit sites regularly, please use printf and sprintf as much as you can.

But you know, if you’re a true masochist, keep in mind that Quasar is always hiring great software engineers. We promise that your suffering will be legendary.

Quasar uses libfmt to format log lines, with compile-time formatting checks in place. Not only does libfmt dramatically reduce the chances of a format error, but it will tell you, at compilation, if you’ve made a mistake.

Last but not least, libfmt is extremely fast. That’s good because we don’t want to waste precious CPU cycles on logging.

Quasar and security

While Quasar is mainly known for being high performance, we seriously take security. We have taken a lot of care into details such as logging to increase the robustness and safety of Quasar.

Writing secure software is extremely hard. Security is a never-ending process. 

Curious about what Quasar is? Learn more here!

Want to take Quasar for a spin? Try our free community edition!

Recent Posts

Quasar “Senaca” Beta 3.13.6 released

This is the beta 3.13 branch, not to be confused with the stable 3.10 branch.

Important update to the Quasar Python API

We just pushed an important bug fix to the Python API for 3.13.5. The bug

Reaching your performance goals with Quasar

If you've tried the community edition of Quasar, you might be wondering if the performance you are

Quasar “Seneca” Beta 3.13.5 Released

This is the beta 3.13 branch, not to be confused with the stable 3.10 branch.

Quasar “Seneca” Beta 3.13.4 Released

This is the beta 3.13 branch, not to be confused with the stable 3.10 branch.

Try the community edition now!