Logger System 1.0.0
High-performance C++20 thread-safe logging system with asynchronous capabilities
Loading...
Searching...
No Matches
log_filter.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
10#pragma once
11
14#include <kcenon/common/interfaces/logger_interface.h>
15#include <algorithm>
16#include <regex>
17#include <functional>
18
20
21// Type alias for log_level
22using log_level = common::interfaces::log_level;
23
30private:
31 log_level min_level_;
32
33public:
34 explicit level_filter(log_level min_level) : min_level_(min_level) {}
35
36 bool should_log(const log_entry& entry) const override {
37 return static_cast<int>(entry.level) >= static_cast<int>(min_level_);
38 }
39
40 std::string get_name() const override {
41 return "level_filter";
42 }
43};
44
51private:
52 log_level level_;
53
54public:
55 explicit exact_level_filter(log_level level) : level_(level) {}
56
57 bool should_log(const log_entry& entry) const override {
58 return entry.level == level_;
59 }
60
61 std::string get_name() const override {
62 return "exact_level_filter";
63 }
64};
65
70private:
71 std::regex pattern_;
73
74public:
75 regex_filter(const std::string& pattern, bool include_matches = true)
76 : pattern_(pattern), include_matches_(include_matches) {}
77
78 bool should_log(const log_entry& entry) const override {
79 bool matches = std::regex_search(entry.message.to_string(), pattern_);
80 return include_matches_ ? matches : !matches;
81 }
82
83 std::string get_name() const override {
84 return "regex_filter";
85 }
86};
87
92public:
93 enum class logic_type { AND, OR };
94
95private:
96 std::vector<std::unique_ptr<log_filter_interface>> filters_;
98
99public:
100 explicit composite_filter(logic_type logic) : logic_(logic) {}
101
102 void add_filter(std::unique_ptr<log_filter_interface> filter) {
103 filters_.push_back(std::move(filter));
104 }
105
106 bool should_log(const log_entry& entry) const override {
107 if (filters_.empty()) return true;
108
109 if (logic_ == logic_type::AND) {
110 for (const auto& filter : filters_) {
111 if (!filter->should_log(entry)) {
112 return false;
113 }
114 }
115 return true;
116 } else { // OR logic
117 for (const auto& filter : filters_) {
118 if (filter->should_log(entry)) {
119 return true;
120 }
121 }
122 return false;
123 }
124 }
125
126 std::string get_name() const override {
127 return logic_ == logic_type::AND ? "composite_and_filter" : "composite_or_filter";
128 }
129};
130
135private:
136 std::function<bool(const log_entry&)> predicate_;
137
138public:
139 explicit function_filter(decltype(predicate_) predicate) : predicate_(std::move(predicate)) {}
140
141 bool should_log(const log_entry& entry) const override {
142 return predicate_(entry);
143 }
144
145 std::string get_name() const override {
146 return "function_filter";
147 }
148};
149
157private:
158 std::string field_name_;
160
161public:
167 explicit field_exists_filter(const std::string& field_name, bool require_exists = true)
168 : field_name_(field_name), require_exists_(require_exists) {}
169
170 bool should_log(const log_entry& entry) const override {
171 bool has_field = entry.fields.has_value() &&
172 entry.fields->find(field_name_) != entry.fields->end();
173 return require_exists_ ? has_field : !has_field;
174 }
175
176 std::string get_name() const override {
177 return "field_exists_filter";
178 }
179};
180
188private:
189 std::string field_name_;
192
193public:
200 field_value_filter(const std::string& field_name, log_value expected_value, bool negate = false)
201 : field_name_(field_name), expected_value_(std::move(expected_value)), negate_(negate) {}
202
203 bool should_log(const log_entry& entry) const override {
204 if (!entry.fields.has_value()) {
205 return negate_; // No fields: pass if negating
206 }
207
208 auto it = entry.fields->find(field_name_);
209 if (it == entry.fields->end()) {
210 return negate_; // Field not found: pass if negating
211 }
212
213 bool matches = it->second == expected_value_;
214 return negate_ ? !matches : matches;
215 }
216
217 std::string get_name() const override {
218 return "field_value_filter";
219 }
220};
221
229private:
230 std::string field_name_;
235
236public:
245 field_range_filter(const std::string& field_name,
246 double min_value,
247 double max_value,
248 bool inclusive_min = true,
249 bool inclusive_max = true)
250 : field_name_(field_name)
251 , min_value_(min_value)
252 , max_value_(max_value)
253 , inclusive_min_(inclusive_min)
254 , inclusive_max_(inclusive_max) {}
255
256 bool should_log(const log_entry& entry) const override {
257 if (!entry.fields.has_value()) {
258 return false;
259 }
260
261 auto it = entry.fields->find(field_name_);
262 if (it == entry.fields->end()) {
263 return false;
264 }
265
266 // Extract numeric value
267 double value = 0.0;
268 if (std::holds_alternative<int64_t>(it->second)) {
269 value = static_cast<double>(std::get<int64_t>(it->second));
270 } else if (std::holds_alternative<double>(it->second)) {
271 value = std::get<double>(it->second);
272 } else {
273 return false; // Not a numeric field
274 }
275
276 // Check range
277 bool above_min = inclusive_min_ ? (value >= min_value_) : (value > min_value_);
278 bool below_max = inclusive_max_ ? (value <= max_value_) : (value < max_value_);
279 return above_min && below_max;
280 }
281
282 std::string get_name() const override {
283 return "field_range_filter";
284 }
285};
286
294private:
295 std::string field_name_;
296 std::regex pattern_;
298
299public:
306 field_regex_filter(const std::string& field_name,
307 const std::string& pattern,
308 bool include_matches = true)
309 : field_name_(field_name)
310 , pattern_(pattern)
311 , include_matches_(include_matches) {}
312
313 bool should_log(const log_entry& entry) const override {
314 if (!entry.fields.has_value()) {
315 return !include_matches_;
316 }
317
318 auto it = entry.fields->find(field_name_);
319 if (it == entry.fields->end()) {
320 return !include_matches_;
321 }
322
323 // Only works on string fields
324 if (!std::holds_alternative<std::string>(it->second)) {
325 return !include_matches_;
326 }
327
328 const auto& str_value = std::get<std::string>(it->second);
329 bool matches = std::regex_search(str_value, pattern_);
330 return include_matches_ ? matches : !matches;
331 }
332
333 std::string get_name() const override {
334 return "field_regex_filter";
335 }
336};
337
345private:
346 std::vector<std::string> categories_;
348
349public:
355 category_filter(std::vector<std::string> categories, bool include = true)
356 : categories_(std::move(categories)), include_(include) {}
357
358 bool should_log(const log_entry& entry) const override {
359 if (!entry.category.has_value()) {
360 return !include_; // No category: pass if excluding
361 }
362
363 std::string cat = entry.category->to_string();
364 bool found = std::find(categories_.begin(), categories_.end(), cat) != categories_.end();
365 return include_ ? found : !found;
366 }
367
368 std::string get_name() const override {
369 return "category_filter";
370 }
371};
372
373} // namespace kcenon::logger::filters
Filter based on category field.
Definition log_filter.h:344
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:368
std::vector< std::string > categories_
Definition log_filter.h:346
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:358
category_filter(std::vector< std::string > categories, bool include=true)
Constructor.
Definition log_filter.h:355
Composite filter with AND/OR logic.
Definition log_filter.h:91
void add_filter(std::unique_ptr< log_filter_interface > filter)
Definition log_filter.h:102
std::vector< std::unique_ptr< log_filter_interface > > filters_
Definition log_filter.h:96
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:126
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:106
Exact level filter (matches only the specified level)
Definition log_filter.h:50
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:57
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:61
Filter based on structured field presence.
Definition log_filter.h:156
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:176
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:170
field_exists_filter(const std::string &field_name, bool require_exists=true)
Constructor.
Definition log_filter.h:167
Filter based on structured field value range (for numeric types)
Definition log_filter.h:228
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:282
field_range_filter(const std::string &field_name, double min_value, double max_value, bool inclusive_min=true, bool inclusive_max=true)
Constructor.
Definition log_filter.h:245
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:256
Filter based on string field pattern matching.
Definition log_filter.h:293
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:313
field_regex_filter(const std::string &field_name, const std::string &pattern, bool include_matches=true)
Constructor.
Definition log_filter.h:306
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:333
Filter based on structured field value.
Definition log_filter.h:187
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:203
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:217
field_value_filter(const std::string &field_name, log_value expected_value, bool negate=false)
Constructor.
Definition log_filter.h:200
function_filter(decltype(predicate_) predicate)
Definition log_filter.h:139
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:145
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:141
std::function< bool(const log_entry &)> predicate_
Definition log_filter.h:136
Level-based log filter (minimum level threshold)
Definition log_filter.h:29
level_filter(log_level min_level)
Definition log_filter.h:34
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:40
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:36
regex_filter(const std::string &pattern, bool include_matches=true)
Definition log_filter.h:75
bool should_log(const log_entry &entry) const override
Check if a log entry should be processed.
Definition log_filter.h:78
std::string get_name() const override
Get the name of this filter.
Definition log_filter.h:83
std::string to_string() const
Convert to std::string.
Data structures for representing log entries and source locations kcenon.
Interface for log filters used by filtered_logger.
std::variant< std::string, int64_t, double, bool > log_value
Value type for structured logging fields.
Definition log_entry.h:69
Represents a single log entry with all associated metadata.
Definition log_entry.h:155
std::optional< log_fields > fields
Optional structured fields for key-value logging.
Definition log_entry.h:213
log_level level
Severity level of the log message.
Definition log_entry.h:162
std::optional< small_string_128 > category
Optional category for log filtering and routing.
Definition log_entry.h:197
small_string_256 message
The actual log message.
Definition log_entry.h:169