Skip to content

4. Formatters

Odysseas Georgoudis edited this page Oct 28, 2022 · 10 revisions

Formatters specify the layout of log records in the final output.

Each Handler object owns its own instance of a Formatter object. This means that each Handler object can be customised to output in a different format.

Customising the format output only be done prior to the creation of the logger by calling set_pattern() on the Handler instance.

The following format is used by default :

ascii_time [thread_id] filename:line level_name logger_name - message

If no custom format is set each newly created Handler will use the same formatting as the default logger

For using the same custom format on all loggers it is advised to initially set the desired format on the default logger in the beginning. Then any new logger created will by default use the format of the default logger unless otherwise specified.

The format output can be customised by providing a string of certain attributes.

Name Format Description
ascii_time %(ascii_time) Human-readable time when the LogRecord was created. By default this is of the form ‘2003-07-08 16:49:45,896’ (the numbers after the comma are millisecond portion of the time).
filename %(filename) Filename portion of pathname.
function_name %(function_name) Name of function containing the logging call.
level_name %(level_name) Text logging level for the message ('TRACEL3', 'TRACEL2', 'TRACEL1', 'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 'BACKTRACE').
level_id %(level_id) Abbreviated level name ('T3', 'T2', 'T1', 'D', 'I', 'W', 'E', 'C', 'BT').
lineno %(lineno) Source line number where the logging call was issued (if available).
message %(message) The logged message, computed as msg % args. This is set when Formatter.format() is invoked.
logger_name %(logger_name) Name of the logger used to log the call.
pathname %(pathname) Full pathname of the source file where the logging call was issued (if available).
thread %(thread) Thread ID (if available).
thread name %(thread_name) Thread name if set. The name of the thread must be set prior to issuing any log statement on that thread.
process %(process) Process ID

Customising the timestamp

The timestamp is customisable on :

  • Format. Same format specifiers as strftime(...) format without the additional .Qms .Qus .Qns arguments.

Note that MinGW compiler does not support all strftime(...) format specifiers and you might get a bad alloc if the format specifier is not supported

  • Local timezone or GMT timezone. Local timezone is used by default.
  • Fractional second precision. Using the additional fractional second specifiers in the timestamp format string.
Specifier Description
%Qms Milliseconds
%Qus Microseconds
%Qns Nanoseconds

Quill by default is using the following timestamp format "%H:%M:%S.%Qns"

Setting a default formatter for logging to stdout

  // Get the stdout file handler
  quill::Handler* file_handler = quill::stdout_handler();

  // Set a custom formatter for this handler
  file_handler->set_pattern("%(ascii_time) [%(process)] [%(thread)] %(logger_name) - %(message)", // format
                            "%D %H:%M:%S.%Qms %z",     // timestamp format
                            quill::Timezone::GmtTime); // timestamp's timezone

  // Config using the custom ts class and the stdout handler
  quill::Config cfg;
  cfg.default_handlers.emplace_back(file_handler);
  quill::configure(cfg);

  // Start the backend logging thread
  quill::start();

  // Log using the default logger
  LOG_INFO(quill::get_logger(), "The default logger is using a custom format");

  // Obtain a new logger. Since no handlers were specified during the creation of the new logger. The new logger will use the default logger's handlers. In that case it will use the stdout_handler with the modified format.
  quill::Logger* logger_foo = quill::create_logger("logger_foo");

  LOG_INFO(logger_foo, "The new logger is using the custom format");

Setting a default formatter on a FileHandler

  // Start the logging backend thread
  quill::start();

  // Calling the function with the same filename will return the existing handler
  quill::Handler* file_handler = quill::file_handler(filename, "w");

  // Set a custom pattern to this file handler
  file_handler->set_pattern("%(ascii_time) [%(process)] [%(thread)] %(logger_name) - %(message)", // format
                            "%D %H:%M:%S.%Qms %z",     // timestamp format
                            quill::Timezone::GmtTime); // timestamp's timezone

  // Create a logger using this handler
  quill::Logger* logger_foo = quill::create_logger("logger_foo", file_handler);

  // Log using the logger
  LOG_INFO(logger_foo, "Hello from {}", "library foo");