Simple-Log  alpha-v0.7
BasicSink.hpp
Go to the documentation of this file.
1 // Copyright Dominic Koepke 2021 - 2021.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE_1_0.txt or copy at
4 // https://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef SL_LOG_BASIC_SINK_HPP
7 #define SL_LOG_BASIC_SINK_HPP
8 
9 #pragma once
10 
11 #include "ISink.hpp"
12 #include "Record.hpp"
13 
14 #include <atomic>
15 #include <chrono>
16 #include <functional>
17 #include <iomanip>
18 #include <mutex>
19 #include <sstream>
20 
21 namespace sl::log
22 {
30  template <class T, class TRecord>
32  Record<TRecord> &&
33  std::is_invocable_r_v<std::string, T, const TRecord&>;
34 
38  template <class T, class TRecord>
39  concept RecordFilterFor =
40  Record<TRecord> &&
41  std::predicate<T, const TRecord&>;
42 
49  template <Record TRecord>
50  class BasicSink :
51  public ISink<TRecord>
52  {
53  using Super = ISink<TRecord>;
54 
55  public:
56  using typename Super::Record_t;
58  using Formatter_t = std::function<std::string(const Record_t&)>;
59  using Filter_t = std::function<bool(const Record_t&)>;
60 
61  protected:
62  static constexpr Formatter_t defaultFormatter() noexcept
63  {
64  return [](const Record_t& rec)
65  {
66  using namespace std::chrono;
67  using namespace std::chrono_literals;
68 
69  // ToDo: replace with c++20 chrono and format
70  const auto today = Projections_t::timePoint(rec).time_since_epoch() % 24h;
71  const auto hour = duration_cast<hours>(today);
72  const auto minute = duration_cast<minutes>(today) % 1h;
73  const auto second = duration_cast<seconds>(today) % 1min;
74  const auto millisecond = duration_cast<milliseconds>(today) % 1s;
75 
76  std::ostringstream out;
77  out << std::setfill('0') <<
78  std::setw(2) << hour.count() << ":" <<
79  std::setw(2) << minute.count() << ":" <<
80  std::setw(2) << second.count() << "." <<
81  std::setw(3) << millisecond.count() <<
82  " >>> ";
83 
84  out << Projections_t::severity(rec) << ":: ";
85  out << Projections_t::message(rec);
86  return std::move(out).str();
87  };
88  }
89 
90  static constexpr Filter_t defaultFilter() noexcept
91  {
92  return [](const Record_t& rec) { return true; };
93  }
94 
95  public:
99  explicit BasicSink() noexcept = default;
100 
104  ~BasicSink() noexcept = default;
105 
109  BasicSink(const BasicSink&) = delete;
113  BasicSink& operator =(const BasicSink&) = delete;
114 
118  BasicSink(BasicSink&&) = delete;
122  BasicSink& operator =(BasicSink&&) = delete;
123 
130  void log(const Record_t& record) final override
131  {
132  if (!m_Enabled)
133  return;
134 
135  if (std::scoped_lock lock{ m_FilterMx }; !std::invoke(m_Filter, record))
136  return;
137 
138  const auto message = [&]
139  {
140  std::scoped_lock lock{ m_FormatterMx };
141  return std::invoke(m_Formatter, record);
142  }();
143 
144  writeMessage(record, message);
145  }
146 
152  void setEnabled(bool enable = true) noexcept final override
153  {
154  m_Enabled = enable;
155  }
156 
161  [[nodiscard]]
162  bool isEnabled() const noexcept final override
163  {
164  return m_Enabled;
165  }
166 
179  template <RecordFormatterFor<Record_t> TFormatter>
180  void setFormatter(TFormatter&& formatter)
181  {
182  std::scoped_lock lock{ m_FormatterMx };
183  m_Formatter = std::forward<TFormatter>(formatter);
184  }
185 
190  {
191  std::scoped_lock lock{ m_FormatterMx };
192  m_Formatter = defaultFormatter();
193  }
194 
206  template <RecordFilterFor<Record_t> TFilter>
207  void setFilter(TFilter&& filter)
208  {
209  std::scoped_lock lock{ m_FilterMx };
210  m_Filter = std::forward<TFilter>(filter);
211  }
212 
217  {
218  std::scoped_lock lock{ m_FilterMx };
219  m_Filter = defaultFilter();
220  }
221 
222  protected:
230  virtual void writeMessage(const Record_t& record, std::string_view message) = 0;
231 
232  private:
233  std::mutex m_FormatterMx;
234  Formatter_t m_Formatter{ defaultFormatter() };
235 
236  std::mutex m_FilterMx;
237  Filter_t m_Filter{ defaultFilter() };
238 
239  std::atomic_bool m_Enabled{ false };
240  };
241 
243 }
244 
245 #endif
Abstract Sink class which offers basic filtering, formatting functionality.
Definition: BasicSink.hpp:52
void setFilter(TFilter &&filter)
Sets the active filter.
Definition: BasicSink.hpp:207
void removeFilter()
Replaces the active filter with the default one.
Definition: BasicSink.hpp:216
void setEnabled(bool enable=true) noexcept final override
Enables or disables the Sink object.
Definition: BasicSink.hpp:152
std::function< bool(const Record_t &)> Filter_t
Definition: BasicSink.hpp:59
static constexpr Formatter_t defaultFormatter() noexcept
Definition: BasicSink.hpp:62
bool isEnabled() const noexcept final override
Checks if the Sink object is enabled.
Definition: BasicSink.hpp:162
BasicSink() noexcept=default
Constructor.
void removeFormatter()
Replaces the active formatter with the default one.
Definition: BasicSink.hpp:189
void log(const Record_t &record) final override
Handles the given Record object.
Definition: BasicSink.hpp:130
std::function< std::string(const Record_t &)> Formatter_t
Definition: BasicSink.hpp:58
void setFormatter(TFormatter &&formatter)
Sets the active formatter.
Definition: BasicSink.hpp:180
virtual void writeMessage(const Record_t &record, std::string_view message)=0
This function will be called when the actual message should be printed.
static constexpr Filter_t defaultFilter() noexcept
Definition: BasicSink.hpp:90
Sink interface class.
Definition: ISink.hpp:29
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
concept RecordFilterFor
Concept for invokable filter objects.
Definition: BasicSink.hpp:39
concept RecordFormatterFor
Concept for invokable formatter objects.
Definition: BasicSink.hpp:31
Definition: BasicSink.hpp:22
Provides a layer of abstraction to Record member setter.
Definition: Record.hpp:118
constexpr static auto timePoint
Definition: Record.hpp:122
constexpr static auto message
Definition: Record.hpp:119
constexpr static auto severity
Definition: Record.hpp:120