Sink Types

Reference for all built-in sink implementations. See Sinks for how to create, share, and extend sinks.

ConsoleSink

The ConsoleSink class sends logging output to streams stdout or stderr. Printing color codes to terminal or Windows console is also supported.

FileSink

The FileSink is a straightforward sink that outputs to a file. The filepath of the FileSink serves as a unique identifier, allowing you to retrieve the same sink later using FrontendImpl::get_sink().

Each file can only have a single instance of FileSink.

Note

When using FileEventNotifier with FileSink, the callback handle type is platform-dependent and is exposed as quill::FileEventNotifierHandle. On Windows it is a native HANDLE. On other platforms it is a FILE*.

before_write runs as part of normal log writing. before_open, after_open, before_close, and after_close run on whichever thread performs the file open/close operation. Different callbacks, and different invocations of the same callback, may therefore run on different threads over the sink lifetime. Callbacks must be thread-safe and must not assume a single calling thread.

 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);
}

RotatingFileSink

The RotatingFileSink is built on top of the FileSink and provides log file rotation based on specified time intervals, file sizes, or daily schedules.

Note

When the sink starts in append mode, rotated files left behind by previous runs are detected for every RotationNamingScheme and count towards max_backup_files whether or not the base filename has an extension; the oldest ones are removed on startup if they exceed the limit, so log files do not accumulate across restarts. Set set_overwrite_rolled_files(false) to prevent append-mode recovery from deleting existing rotated files, or use FilenameAppendOption::StartDateTime to give each run its own independent set of files.

 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
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/RotatingFileSink.h"

#include <utility>

/**
 * This example shows a `RotatingFileSink` configured with both daily rotation
 * and size-based rotation.
 *
 * See `RotatingFileSinkConfig` for additional rotation options.
 */

int main()
{
  // Start the backend thread
  quill::BackendOptions backend_options;
  quill::Backend::start(backend_options);

  // Frontend
  auto rotating_file_sink = quill::Frontend::create_or_get_sink<quill::RotatingFileSink>(
    "rotating_file.log",
    []()
    {
      // See RotatingFileSinkConfig for more options
      quill::RotatingFileSinkConfig cfg;
      cfg.set_open_mode('w');
      cfg.set_filename_append_option(quill::FilenameAppendOption::StartDateTime);
      cfg.set_rotation_time_daily("18:30");
      cfg.set_rotation_max_file_size(1024); // small value to demonstrate the example
      return cfg;
    }());

  quill::Logger* logger = quill::Frontend::create_or_get_logger(
    "root", std::move(rotating_file_sink),
    quill::PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) "
                                   "LOG_%(log_level:<9) %(logger:<12) %(message)",
                                   "%H:%M:%S.%Qns", quill::Timezone::GmtTime});

  for (int i = 0; i < 20; ++i)
  {
    LOG_INFO(logger, "Hello from rotating logger, index is {}", i);
  }
}

JsonFileSink/JsonConsoleSink

 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
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/JsonSink.h"
#include <string>

int main()
{
  // Start the backend thread
  quill::BackendOptions backend_options;
  quill::Backend::start(backend_options);

  // Create a json sink
  auto json_sink = quill::Frontend::create_or_get_sink<quill::JsonFileSink>("example_json.log",
                                                                            []()
                                                                            {
                                                                              quill::FileSinkConfig config;
                                                                              return config;
                                                                            }());

  // PatternFormatter is only used for non-structured logs formatting
  // When logging only json, it is ideal to set the logging pattern to empty to avoid unnecessary message formatting.
  quill::Logger* logger = quill::Frontend::create_or_get_logger(
    "json_logger", std::move(json_sink),
    quill::PatternFormatterOptions{"", "%H:%M:%S.%Qns", quill::Timezone::GmtTime});

  int var_a = 123;
  std::string var_b = "test";

  // Log via the convenient LOGJ_ macros
  LOGJ_INFO(logger, "A json message", var_a, var_b);

  // Or manually specify the desired names of each variable
  LOG_INFO(logger, "A json message with {var_1} and {var_2}", var_a, var_b);
}

RotatingJsonFileSink

The RotatingJsonFileSink is built on top of the JsonFileSink and provides log file rotation based on specified time intervals, file sizes, or daily schedules.

 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
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/RotatingJsonFileSink.h"

#include <utility>

/**
 * This example demonstrates how to create a `RotatingJsonFileSink` with daily
 * rotation and automatic rotation based on maximum file size.
 *
 * See `RotatingFileSinkConfig` for additional rotation options.
 */

int main()
{
  // Start the backend thread
  quill::BackendOptions backend_options;
  quill::Backend::start(backend_options);

  // Frontend
  auto rotating_json_sink = quill::Frontend::create_or_get_sink<quill::RotatingJsonFileSink>(
    "rotating_json.log",
    []()
    {
      // See RotatingFileSinkConfig for more options
      quill::RotatingFileSinkConfig cfg;
      cfg.set_open_mode('w');
      cfg.set_filename_append_option(quill::FilenameAppendOption::StartDateTime);
      cfg.set_rotation_time_daily("18:30");
      cfg.set_rotation_max_file_size(1024); // small value to demonstrate the example
      return cfg;
    }());

  quill::Logger* logger = quill::Frontend::create_or_get_logger(
    "root", std::move(rotating_json_sink),
    quill::PatternFormatterOptions{"%(time) [%(thread_id)] %(short_source_location:<28) "
                                   "LOG_%(log_level:<9) %(logger:<12) %(message)",
                                   "%H:%M:%S.%Qns", quill::Timezone::GmtTime});

  for (int i = 0; i < 20; ++i)
  {
    LOG_INFO(logger, "Hello from rotating logger {index}", i);
  }
}

SyslogSink

The SyslogSink leverages the syslog API to send messages.

Note

Syslog uses process-global state. Multiple SyslogSink instances are therefore not independent if they use different identifiers, options, or facilities. Use a single SyslogSink configuration per process.

StreamSink

The StreamSink is a base sink class used to write log messages to C-style FILE* streams, such as stdout, stderr, or files opened with fopen. It is typically used as a foundation for higher-level sinks like ConsoleSink.

AndroidSink

The AndroidSink sends log messages to the Android logging system using the Android NDK logging API.

NullSink

The NullSink discards all log messages, useful for performance testing or disabling specific logger output without removing logging calls.

Note

Macro Collision Notice

When including syslog.h via SyslogSink, the header defines macros such as LOG_INFO (and others) that may collide with Quill’s unprefixed LOG_ macros. To resolve this issue, consider one of the following solutions:

  • Include SyslogSink in a .cpp file only: Instantiate the SyslogSink in a source file rather than in a header file. This ensures that syslog.h is included only in that specific translation unit, allowing the rest of your code to use the unprefixed Quill LOG_ macros without conflict.

  • Define the preprocessor flag ``QUILL_DISABLE_NON_PREFIXED_MACROS``: This flag disables the unprefixed Quill LOG_ macros and forces the use of the longer QUILL_LOG_ macros instead. This approach allows Quill to work alongside syslog.h in the same translation unit.

Alternatively, you can combine both solutions if you include SyslogSink in a .cpp file where you also want to use the unprefixed LOG_ macros. However, the first solution is generally preferred since it allows for less typing with the concise LOG_ macros.

#define QUILL_DISABLE_NON_PREFIXED_MACROS

#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/SyslogSink.h"

#include <string>
#include <utility>

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

  // Frontend
  auto sink = quill::Frontend::create_or_get_sink<quill::SyslogSink>(
    "app", []()
    {
      quill::SyslogSinkConfig config;
      config.set_identifier("app");
      return config;
    }());

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

  QUILL_LOG_INFO(logger, "A {} message with number {}", "log", 1);
  QUILL_LOG_WARNING(logger, "test message {}", 123);
}

SystemdSink

The SystemdSink integrates with the systemd journal, allowing messages to be sent directly to systemd. To use this sink, ensure the systemd-devel package is installed. Additionally, link your program against lsystemd.

find_package(PkgConfig REQUIRED)
pkg_check_modules(SYSTEMD REQUIRED libsystemd)
target_link_libraries(${TARGET} ${SYSTEMD_LIBRARIES})

Note

Macro Collision Notice

When including syslog.h via SystemdSink, the header defines macros such as LOG_INFO (and others) that may collide with Quill’s unprefixed LOG_ macros. To resolve this issue, consider one of the following solutions:

  • Include SystemdSink in a .cpp file only: Instantiate the SystemdSink in a source file rather than in a header file. This ensures that syslog.h is included only in that specific translation unit, allowing the rest of your code to use the unprefixed Quill LOG_ macros without conflict.

  • Define the preprocessor flag ``QUILL_DISABLE_NON_PREFIXED_MACROS``: This flag disables the unprefixed Quill LOG_ macros and forces the use of the longer QUILL_LOG_ macros instead. This approach allows Quill to work alongside syslog.h in the same translation unit.

Alternatively, you can combine both solutions if you include SystemdSink in a .cpp file where you also want to use the unprefixed LOG_ macros. However, the first solution is generally preferred since it allows for less typing with the concise LOG_ macros.

#define QUILL_DISABLE_NON_PREFIXED_MACROS

#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/sinks/SystemdSink.h"

#include <string>
#include <utility>

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

  // Frontend
  auto sink = quill::Frontend::create_or_get_sink<quill::SystemdSink>(
    "app", []()
    {
      quill::SystemdSinkConfig config;
      config.set_identifier("app");
      return config;
    }());

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

  QUILL_LOG_INFO(logger, "A {} message with number {}", "log", 1);
  QUILL_LOG_WARNING(logger, "test message {}", 123);
}