Filters

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 and returns a boolean value. This boolean value determines whether the log statement should be forwarded to the Sink or filtered out.

Filtering Logs with the Built-In Filter

 1#include "quill/Backend.h"
 2#include "quill/Frontend.h"
 3#include "quill/LogMacros.h"
 4#include "quill/Logger.h"
 5#include "quill/sinks/ConsoleSink.h"
 6
 7int main()
 8{
 9  quill::Backend::start();
10
11  quill::Logger* logger = quill::Frontend::create_or_get_logger(
12    "root", quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1"));
13
14  LOG_INFO(logger, "This is a log info example {}", 123);
15
16  // Apply filter to the sink. This is thread-safe but to avoid setting the filter before the
17  // backend has processed the earlier log message we flush first
18  logger->flush_log();
19  quill::Frontend::get_sink("sink_id_1")->set_log_level_filter(quill::LogLevel::Error);
20  LOG_INFO(logger, "This message is filtered");
21
22  logger->flush_log();
23  quill::Frontend::get_sink("sink_id_1")->set_log_level_filter(quill::LogLevel::TraceL3);
24  LOG_INFO(logger, "This is a log info example {}", 456);
25}

Creating a Custom Log Filter

 1#include "quill/Backend.h"
 2#include "quill/Frontend.h"
 3#include "quill/LogMacros.h"
 4#include "quill/Logger.h"
 5#include "quill/filters/Filter.h"
 6#include "quill/sinks/ConsoleSink.h"
 7
 8#include <cstdint>
 9#include <string>
10#include <string_view>
11#include <utility>
12
13/**
14 * This example demonstrates the creation usage of a user defined filter.
15 * When a filter is applied, log messages are still enqueued from the frontend to the backend.
16 * Subsequently, the backend dynamically filters them based on a given condition.
17 */
18
19class UserFilter : public quill::Filter
20{
21public:
22  UserFilter() : quill::Filter("filter_1") {};
23
24  bool filter(quill::MacroMetadata const* /** log_metadata **/, uint64_t /** log_timestamp **/,
25              std::string_view /** thread_id **/, std::string_view /** thread_name **/,
26              std::string_view /** logger_name **/, quill::LogLevel log_level,
27              std::string_view log_message, std::string_view /** log_statement **/) noexcept override
28  {
29    // for example filter out duplicate log files
30    bool is_different = true;
31
32    if ((last_log_level == log_level) && (log_message == last_message))
33    {
34      is_different = false;
35    }
36
37    last_message = log_message;
38    last_log_level = log_level;
39
40    // return true to log the message, false otherwise
41    return is_different;
42  }
43
44private:
45  std::string last_message;
46  quill::LogLevel last_log_level{quill::LogLevel::None};
47};
48
49int main()
50{
51  // Start the backend thread
52  quill::BackendOptions backend_options;
53  quill::Backend::start(backend_options);
54
55  // Frontend
56  auto console_sink = quill::Frontend::create_or_get_sink<quill::ConsoleSink>("sink_id_1");
57
58  // Add the filter - adding filters is thread safe and can be called anytime
59  console_sink->add_filter(std::make_unique<UserFilter>());
60
61  quill::Logger* logger = quill::Frontend::create_or_get_logger("root", std::move(console_sink));
62
63  // Change the LogLevel to send everything
64  logger->set_log_level(quill::LogLevel::TraceL3);
65
66  LOG_INFO(logger, "This is a log info example {}", 123);
67  LOG_INFO(logger, "This is a log info example {}", 123);
68  LOG_INFO(logger, "This is a log info example {}", 123);
69  LOG_INFO(logger, "This is a log info example {}", 123);
70  LOG_INFO(logger, "This is a log info example {}", 456);
71  LOG_INFO(logger, "This is a log info example {}", 123);
72}