Filters

Use this page to selectively route log messages to sinks based on level, content, or custom criteria.

Filters are used to selectively control which log statements are sent to specific Sinks based on defined criteria.

Each Sink can be associated with one or multiple Filter objects. These filters allow customization of log statement handling, such as filtering by log level or other criteria.

By default, a logger sends all log messages to its Sinks. Filters provide a way to intercept and selectively process log records before they are outputted.

A filter is implemented as a callable object that evaluates each log statement on the backend thread and returns a boolean value. When the filter returns true, the log statement is forwarded to the Sink; when false, the log statement is discarded.

Filtering Logs with the Built-In Filter

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

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

  quill::Logger* logger = quill::Frontend::create_or_get_logger(
    "root", quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1"));

  LOG_INFO(logger, "This is a log info example {}", 123);

  // Apply filter to the sink. This is thread-safe but to avoid setting the filter before the
  // backend has processed the earlier log message we flush first
  logger->flush_log();
  quill::Frontend::get_sink("sink_id_1")->set_log_level_filter(quill::LogLevel::Error);
  LOG_INFO(logger, "This message is filtered");

  logger->flush_log();
  quill::Frontend::get_sink("sink_id_1")->set_log_level_filter(quill::LogLevel::TraceL3);
  LOG_INFO(logger, "This is a log info example {}", 456);
}

Creating a Custom Log Filter

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "quill/Backend.h"
#include "quill/Frontend.h"
#include "quill/LogMacros.h"
#include "quill/Logger.h"
#include "quill/filters/Filter.h"
#include "quill/sinks/ConsoleSink.h"

#include <cstdint>
#include <string>
#include <string_view>
#include <utility>

/**
 * This example shows how to implement and attach a user-defined filter.
 * When a filter is applied, log messages are still enqueued from the frontend
 * to the backend, and the backend decides whether to keep or drop them.
 */

class UserFilter : public quill::Filter
{
public:
  UserFilter() : quill::Filter("filter_1") {};

  bool filter(quill::MacroMetadata const* /** log_metadata **/, uint64_t /** log_timestamp **/,
              std::string_view /** thread_id **/, std::string_view /** thread_name **/,
              std::string_view /** logger_name **/, quill::LogLevel log_level,
              std::string_view log_message, std::string_view /** log_statement **/) noexcept override
  {
    // Example policy: drop consecutive duplicate messages with the same level.
    bool is_different = true;

    if ((last_log_level == log_level) && (log_message == last_message))
    {
      is_different = false;
    }

    last_message = log_message;
    last_log_level = log_level;

    // return true to log the message, false otherwise
    return is_different;
  }

private:
  std::string last_message;
  quill::LogLevel last_log_level{quill::LogLevel::None};
};

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

  // Frontend
  auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1");

  // Add the filter - adding filters is thread safe and can be called anytime
  console_sink->add_filter(std::make_unique<UserFilter>());

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

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

  LOG_INFO(logger, "This is a log info example {}", 123);
  LOG_INFO(logger, "This is a log info example {}", 123);
  LOG_INFO(logger, "This is a log info example {}", 123);
  LOG_INFO(logger, "This is a log info example {}", 123);
  LOG_INFO(logger, "This is a log info example {}", 456);
  LOG_INFO(logger, "This is a log info example {}", 123);
}