quill
Sink.h
1 
7 #pragma once
8 
9 #include "quill/core/Attributes.h"
10 #include "quill/core/LogLevel.h"
11 #include "quill/core/PatternFormatterOptions.h"
12 #include "quill/core/QuillError.h"
13 #include "quill/core/Spinlock.h"
14 #include "quill/filters/Filter.h"
15 
16 #include <algorithm>
17 #include <atomic>
18 #include <cstdint>
19 #include <memory>
20 #include <optional>
21 #include <string>
22 #include <string_view>
23 #include <utility>
24 #include <vector>
25 
26 QUILL_BEGIN_NAMESPACE
27 
29 class MacroMetadata;
30 class PatternFormatter;
31 
32 namespace detail
33 {
34 class BackendWorker;
35 }
36 
40 class Sink
41 {
42 public:
47  explicit Sink(std::optional<PatternFormatterOptions> override_pattern_formatter_options = std::nullopt)
48  : _override_pattern_formatter_options(std::move(override_pattern_formatter_options))
49  {
50  }
51 
55  virtual ~Sink() = default;
56 
57  Sink(Sink const&) = delete;
58  Sink& operator=(Sink const&) = delete;
59 
65  void set_log_level_filter(LogLevel log_level)
66  {
67  _log_level.store(log_level, std::memory_order_relaxed);
68  }
69 
75  QUILL_NODISCARD LogLevel get_log_level_filter() const noexcept
76  {
77  return _log_level.load(std::memory_order_relaxed);
78  }
79 
85  void add_filter(std::unique_ptr<Filter> filter)
86  {
87  // Lock and add this filter to our global collection
88  detail::LockGuard const lock{_global_filters_lock};
89 
90  // Check if the same filter already exists
91  auto const search_filter_it = std::find_if(
92  _global_filters.cbegin(), _global_filters.cend(), [&filter](std::unique_ptr<Filter> const& elem_filter)
93  { return elem_filter->get_filter_name() == filter->get_filter_name(); });
94 
95  if (QUILL_UNLIKELY(search_filter_it != _global_filters.cend()))
96  {
97  QUILL_THROW(QuillError{"Filter with the same name already exists"});
98  }
99 
100  _global_filters.push_back(std::move(filter));
101 
102  // Indicate a new filter was added - here relaxed is okay as the spinlock will do acq-rel on destruction
103  _new_filter.store(true, std::memory_order_relaxed);
104  }
105 
106 protected:
123  QUILL_ATTRIBUTE_HOT virtual void write_log(
124  MacroMetadata const* log_metadata, uint64_t log_timestamp, std::string_view thread_id,
125  std::string_view thread_name, std::string const& process_id, std::string_view logger_name,
126  LogLevel log_level, std::string_view log_level_description, std::string_view log_level_short_code,
127  std::vector<std::pair<std::string, std::string>> const* named_args,
128  std::string_view log_message, std::string_view log_statement) = 0;
129 
133  QUILL_ATTRIBUTE_HOT virtual void flush_sink() = 0;
134 
141  QUILL_ATTRIBUTE_HOT virtual void run_periodic_tasks() noexcept {}
142 
156  QUILL_NODISCARD bool apply_all_filters(MacroMetadata const* log_metadata, uint64_t log_timestamp,
157  std::string_view thread_id, std::string_view thread_name,
158  std::string_view logger_name, LogLevel log_level,
159  std::string_view log_message, std::string_view log_statement)
160  {
161  if (log_level < _log_level.load(std::memory_order_relaxed))
162  {
163  return false;
164  }
165 
166  // Update our local collection of the filters
167  if (QUILL_UNLIKELY(_new_filter.load(std::memory_order_relaxed)))
168  {
169  // if there is a new filter we have to update
170  _local_filters.clear();
171 
172  detail::LockGuard const lock{_global_filters_lock};
173 
174  for (auto const& filter : _global_filters)
175  {
176  _local_filters.push_back(filter.get());
177  }
178 
179  // all filters loaded so change to false
180  _new_filter.store(false, std::memory_order_relaxed);
181  }
182 
183  if (_local_filters.empty())
184  {
185  return true;
186  }
187  else
188  {
189  return std::all_of(_local_filters.begin(), _local_filters.end(),
190  [log_metadata, log_timestamp, thread_id, thread_name, logger_name,
191  log_level, log_message, log_statement](Filter* filter_elem)
192  {
193  return filter_elem->filter(log_metadata, log_timestamp, thread_id, thread_name,
194  logger_name, log_level, log_message, log_statement);
195  });
196  }
197  }
198 
199 private:
200  friend class detail::BackendWorker;
201 
203  std::optional<PatternFormatterOptions> _override_pattern_formatter_options; /* Set by the frontend and accessed by the backend to initialise PatternFormatter */
204  std::shared_ptr<PatternFormatter> _override_pattern_formatter; /* The backend thread will set this once */
205 
207  std::vector<Filter*> _local_filters;
208 
210  std::vector<std::unique_ptr<Filter>> _global_filters;
211  detail::Spinlock _global_filters_lock;
213  std::atomic<bool> _new_filter{false};
214 
215  std::atomic<LogLevel> _log_level{LogLevel::TraceL3};
216 };
217 
218 QUILL_END_NAMESPACE
QUILL_NODISCARD bool apply_all_filters(MacroMetadata const *log_metadata, uint64_t log_timestamp, std::string_view thread_id, std::string_view thread_name, std::string_view logger_name, LogLevel log_level, std::string_view log_message, std::string_view log_statement)
Applies all registered filters to the log record.
Definition: Sink.h:156
Base class for sinks.
Definition: Sink.h:40
Definition: format.h:126
Captures and stores information about a logging event in compile time.
Definition: MacroMetadata.h:22
virtual QUILL_ATTRIBUTE_HOT void run_periodic_tasks() noexcept
Executes periodic tasks by the backend thread, providing an opportunity for the user to perform custo...
Definition: Sink.h:141
Base filter class.
Definition: Filter.h:26
Definition: PatternFormatter.h:33
void add_filter(std::unique_ptr< Filter > filter)
Adds a new filter to the sink.
Definition: Sink.h:85
void set_log_level_filter(LogLevel log_level)
Sets a log level filter on the sink.
Definition: Sink.h:65
Setups a signal handler to handle fatal signals.
Definition: BackendManager.h:24
QUILL_NODISCARD LogLevel get_log_level_filter() const noexcept
Returns the current log level filter set on the sink.
Definition: Sink.h:75
Definition: Spinlock.h:18
custom exception
Definition: QuillError.h:45
Sink(std::optional< PatternFormatterOptions > override_pattern_formatter_options=std::nullopt)
Constructor Uses the default pattern formatter.
Definition: Sink.h:47
Definition: Spinlock.h:58
Definition: BackendWorker.h:72