1
+ #include " doctest/doctest.h"
2
+
3
+ #include " misc/TestUtilities.h"
4
+ #include " quill/Backend.h"
5
+ #include " quill/Frontend.h"
6
+ #include " quill/LogMacros.h"
7
+ #include " quill/sinks/FileSink.h"
8
+
9
+ #include < cstdio>
10
+ #include < string>
11
+ #include < vector>
12
+
13
+ using namespace quill ;
14
+
15
+ class FileFilterA : public Filter
16
+ {
17
+ public:
18
+ FileFilterA () : Filter(" FileFilterA" ) {}
19
+
20
+ QUILL_NODISCARD bool filter (quill::MacroMetadata const * log_metadata, uint64_t /* * log_timestamp **/ ,
21
+ std::string_view /* * thread_id **/ , std::string_view /* * thread_name **/ ,
22
+ std::string_view /* * logger_name **/ , quill::LogLevel /* * log_level **/ ,
23
+ std::string_view /* * log_message **/ , std::string_view log_statement) noexcept override
24
+ {
25
+ if (log_metadata->log_level () < LogLevel::Warning)
26
+ {
27
+ // we expect to match the override format pattern here
28
+ REQUIRE_EQ (log_statement, std::string{" Lorem ipsum dolor sit amet, consectetur adipiscing elit [file]\n " });
29
+ return true ;
30
+ }
31
+ return false ;
32
+ }
33
+ };
34
+
35
+ class FileFilterB : public Filter
36
+ {
37
+ public:
38
+ FileFilterB () : Filter(" FileFilterB" ) {}
39
+
40
+ bool filter (quill::MacroMetadata const * log_metadata, uint64_t /* * log_timestamp **/ ,
41
+ std::string_view /* * thread_id **/ , std::string_view /* * thread_name **/ ,
42
+ std::string_view /* * logger_name **/ , quill::LogLevel /* * log_level **/ ,
43
+ std::string_view /* * log_message **/ , std::string_view log_statement) noexcept override
44
+ {
45
+ if (log_metadata->log_level () >= LogLevel::Warning)
46
+ {
47
+ // we expect to match the override format pattern here
48
+ REQUIRE_EQ (log_statement, std::string{" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [logger]\n " });
49
+ return true ;
50
+ }
51
+ return false ;
52
+ }
53
+ };
54
+
55
+ /* **/
56
+ TEST_CASE (" sink_filter_override_format" )
57
+ {
58
+ // Tests that when we override the format of a sink, the filter gets the overridden format in log_statement
59
+ static constexpr char const * filename_a = " sink_filter_a.log" ;
60
+ static constexpr char const * filename_b = " sink_filter_b.log" ;
61
+ static std::string const logger_name = " logger" ;
62
+
63
+ // Start the logging backend thread
64
+ Backend::start ();
65
+
66
+ // Set writing logging to a file
67
+ auto file_sink_a = Frontend::create_or_get_sink<FileSink>(
68
+ filename_a,
69
+ []()
70
+ {
71
+ // Override format
72
+ PatternFormatterOptions formatter_options_file_sink_a;
73
+ formatter_options_file_sink_a.format_pattern = " %(message) [file]" ;
74
+
75
+ FileSinkConfig cfg;
76
+ cfg.set_open_mode (' w' );
77
+ cfg.set_override_pattern_formatter_options (formatter_options_file_sink_a);
78
+ return cfg;
79
+ }(),
80
+ FileEventNotifier{});
81
+
82
+ // log to filename_a anything below warning
83
+ std::unique_ptr<Filter> filter_a = std::make_unique<FileFilterA>();
84
+
85
+ // Also test get_filter_name()
86
+ REQUIRE_EQ (filter_a->get_filter_name (), std::string_view{" FileFilterA" });
87
+
88
+ // Add the filter
89
+ file_sink_a->add_filter (std::move (filter_a));
90
+
91
+ // Try to add the same again (same name)
92
+ std::unique_ptr<Filter> filter_a_2 = std::make_unique<FileFilterA>();
93
+ REQUIRE_EQ (filter_a_2->get_filter_name (), std::string_view{" FileFilterA" });
94
+ REQUIRE_THROWS_AS (file_sink_a->add_filter (std::move (filter_a_2)), QuillError);
95
+
96
+ auto file_sink_b = Frontend::create_or_get_sink<FileSink>(
97
+ filename_b,
98
+ []()
99
+ {
100
+ // No format override for file_sink_b
101
+ FileSinkConfig cfg;
102
+ cfg.set_open_mode (' w' );
103
+ return cfg;
104
+ }(),
105
+ FileEventNotifier{});
106
+
107
+ // log to filename_b warning, error, critical
108
+ file_sink_b->add_filter (std::make_unique<FileFilterB>());
109
+
110
+ Logger* logger =
111
+ Frontend::create_or_get_logger (logger_name, {std::move (file_sink_a), std::move (file_sink_b)},
112
+ PatternFormatterOptions{" %(message) [logger]" });
113
+
114
+ LOG_INFO (logger, " Lorem ipsum dolor sit amet, consectetur adipiscing elit" );
115
+ LOG_ERROR (logger, " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante" );
116
+
117
+ // Let all log get flushed to the file
118
+ logger->flush_log ();
119
+ Frontend::remove_logger (logger);
120
+
121
+ // Wait until the backend thread stops for test stability
122
+ Backend::stop ();
123
+
124
+ // Read file and check
125
+ std::vector<std::string> const file_contents_a = quill::testing::file_contents (filename_a);
126
+ REQUIRE_EQ (file_contents_a.size (), 1 );
127
+ REQUIRE (quill::testing::file_contains (
128
+ file_contents_a, std::string{" Lorem ipsum dolor sit amet, consectetur adipiscing elit [file]" }));
129
+
130
+ std::vector<std::string> const file_contents_b = quill::testing::file_contents (filename_b);
131
+ REQUIRE_EQ (file_contents_b.size (), 1 );
132
+ REQUIRE (quill::testing::file_contains (
133
+ file_contents_b, std::string{" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [logger]" }));
134
+
135
+ testing::remove_file (filename_a);
136
+ testing::remove_file (filename_b);
137
+ }
0 commit comments