Quick Start

Use this page for the smallest working setup, then move to the full API when you need more control over sinks, loggers, queues, or lifecycle.

Quickest Setup

For the quickest and simplest setup, use simple_logger() with the recommended LOG_* macros:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include "quill/LogMacros.h"
#include "quill/SimpleSetup.h"

int main()
{
  // log to the console
  auto* logger = quill::simple_logger();
  LOG_INFO(logger, "Hello from {}!", "Quill");

  // log to a file
  auto* logger2 = quill::simple_logger("test.log");
  LOG_WARNING(logger2, "This message goes to a file");

  // If you also want Quill's built-in signal handler, use:
  // auto* logger3 = quill::simple_logger_with_signal_handler();
}

Alternatively, a macro-free interface is available if you prefer function-call syntax:

#include "quill/LogFunctions.h"
#include "quill/SimpleSetup.h"

int main()
{
  auto* logger = quill::simple_logger();
  quill::info(logger, "Hello from {}!", "Quill");
}

The LOG_* macros are recommended for lowest latency — they avoid evaluating arguments when the log level is disabled and resolve metadata at compile time. The macro-free functions (quill::info(), quill::warning(), etc.) offer cleaner syntax with slightly higher overhead. See Macro-Free Mode for the full trade-off comparison.

Note

  • Use ``simple_logger()`` when you want the smallest setup with one or two default loggers.

  • Use ``Backend`` / ``Frontend`` when you need custom sinks, multiple loggers, custom formatter patterns, backend options, frontend options, or explicit lifecycle control.

  • See also: a standalone version of this convenience path is available in examples/simple_setup.cpp.

Architecture Overview

The library is header only and consists of two main components: the frontend and the backend.

  • Frontend: captures a copy of the log arguments and metadata from each LOG_* statement and places them in a thread-local SPSC (Single Producer Single Consumer) queue buffer. Each frontend thread has its own lock-free queue, ensuring no contention between logging threads.

  • Backend: runs in a separate thread, spawned by the library, asynchronously consuming messages from all frontend queues, formatting them, and writing them to the configured sinks.

Detailed Setup

For more detailed control, start the backend thread in your application, then set up one or more output Sinks and a Logger.

Once the initialization is complete, you only need to include two header files to issue log statements:

  • #include "quill/LogMacros.h"

  • #include "quill/Logger.h"

These headers have minimal dependencies, keeping compilation times low.

For larger projects, the recommended setup is to wrap Quill initialization and setup in your own small static library that you build once and link into the rest of the application, as shown in: Recommended Usage Example.

For a quick reference on usage see Recipes.

Logging to Console

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/ConsoleSink.h"

#include "quill/std/Array.h"

#include <string>
#include <utility>

int main()
{
  quill::Backend::start();

  // Frontend
  auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1");
  quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink));

  // Change the LogLevel to print everything
  logger->set_log_level(quill::LogLevel::TraceL3);

  // A log message with number 123
  int a = 123;
  std::string l = "log";
  LOG_INFO(logger, "A {} message with number {}", l, a);

  // libfmt formatting language is supported 3.14e+00
  double pi = 3.141592653589793;
  LOG_INFO(logger, "libfmt formatting language is supported {:.2e}", pi);

  // Logging STD types is supported [1, 2, 3]
  std::array<int, 3> arr = {1, 2, 3};
  LOG_INFO(logger, "Logging STD types is supported {}", arr);

  // Logging STD types is supported [arr: [1, 2, 3]]
  LOGV_INFO(logger, "Logging STD types is supported", arr);

  // A message with two variables [a: 123, b: 3.17]
  double b = 3.17;
  LOGV_INFO(logger, "A message with two variables", a, b);

  for (uint32_t i = 0; i < 10; ++i)
  {
    // Will only log the message once per second
    LOG_INFO_LIMIT(std::chrono::seconds{1}, logger, "A {} message with number {}", l, a);
    LOGV_INFO_LIMIT(std::chrono::seconds{1}, logger, "A message with two variables", a, b);
  }
}

Expected output:

20:07:26.653631750 [28794] example_console.cpp:26   LOG_INFO      root         A log message with number 123
20:07:26.653631950 [28794] example_console.cpp:30   LOG_INFO      root         libfmt formatting language is supported 3.14e+00
20:07:26.653632050 [28794] example_console.cpp:34   LOG_INFO      root         Logging STD types is supported [1, 2, 3]
20:07:26.653632150 [28794] example_console.cpp:37   LOG_INFO      root         Logging STD types is supported [arr: [1, 2, 3]]
20:07:26.653632250 [28794] example_console.cpp:41   LOG_INFO      root         A message with two variables [a: 123, b: 3.17]

Logging to File

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/FileSink.h"

#include <utility>

int main()
{
  quill::Backend::start();

  // Frontend
  auto file_sink = quill::Frontend::create_or_get_sink<quill::FileSink>(
    "trivial_logging.log",
    []()
    {
      quill::FileSinkConfig cfg;
      cfg.set_open_mode('w');
      cfg.set_filename_append_option(quill::FilenameAppendOption::StartDateTime);
      return cfg;
    }(),
    quill::FileEventNotifier{});

  quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(file_sink));

  LOG_INFO(logger, "log something {}", 123);
  LOG_WARNING(logger, "something else {}", 456);
}

Next Steps

  • Overview for the full architecture and design rationale.

  • Metrics for publishing compact metric samples through the same backend worker — including the built-in Prometheus exporter.

  • MDC for attaching per-thread request/session context to subsequent log lines.

  • JSON Logging for structured machine-friendly output.

  • Backend Options and Frontend Options for tuning queues, clocks, and backend behavior.

  • Guides for sinks, formatters, filters, backtrace logging, and more.

  • Recipes for common tasks and code examples, including STL and user-defined type logging.