Simple-Log  alpha-v0.7
ConsoleSink.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_CONSOLE_SINK_HPP
7 #define SL_LOG_CONSOLE_SINK_HPP
8 
9 #pragma once
10 
11 #include "OStreamSink.hpp"
12 #include "Record.hpp"
13 
14 // rang.hpp includes windows.hpp internally, thus macros min and max will be defined. This macro prevents this.
15 #define NOMINMAX
16 #include "third_party/rang/rang.hpp"
17 
18 #include <cassert>
19 #include <functional>
20 #include <iostream>
21 #include <mutex>
22 #include <unordered_map>
23 
24 namespace sl::log
25 {
43  {
44  enum class Color
45  {
46  black = 0,
47  red,
48  green,
49  yellow,
50  blue,
51  magenta,
52  cyan,
53  gray,
54  standard,
55 
57  brightRed,
60  brightBlue,
62  brightCyan,
63  brightGray,
64  };
65 
66  enum class Style
67  {
68  standard = 0,
69  bold,
70  dim,
71  italic,
72  underline,
73  reversed = 7,
74  crossed = 9
75  };
76 
81 
86 
91  };
92 
96  template <class T, class TRecord>
98  Record<TRecord> &&
99  std::is_invocable_r_v<ConsoleTextStyle, T, const TRecord&>;
100 
106 
109 }
110 
111 namespace sl::log::detail
112 {
113  std::ostream& applyTextColor(std::ostream& out, ConsoleTextStyle::Color color) noexcept;
114  std::ostream& applyBackgroundColor(std::ostream& out, ConsoleTextStyle::Color color) noexcept;
115  std::ostream& applyStyle(std::ostream& out, ConsoleTextStyle::Style style) noexcept;
116 }
117 
118 namespace sl::log
119 {
135  inline std::ostream& operator <<(std::ostream& out, const ConsoleTextStyle& style)
136  {
137  detail::applyStyle(out, style.style);
138  detail::applyTextColor(out, style.textColor);
139  detail::applyBackgroundColor(out, style.bgColor);
140  return out;
141  }
142 
153  template <class TProjection, class TTable>
155  {
156  public:
157  using Projection_t = std::remove_cvref_t<TProjection>;
158  using Table_t = std::remove_cvref_t<TTable>;
159  using Key_t = typename Table_t::key_type;
160 
166  ConsoleTextStyleTable(TProjection projection, TTable table) :
167  m_Projection{ std::move(projection) },
168  m_StyleTable{ std::move(table) }
169  {
170  }
171 
179  template <Record TRecord>
180  ConsoleTextStyle operator ()(const TRecord& record) const
181  {
182  if (auto itr = m_StyleTable.find(std::invoke(m_Projection, record)); itr != std::end(m_StyleTable))
183  {
184  return itr->second;
185  }
187  }
188 
195  void insert(Key_t key, ConsoleTextStyle style)
196  {
197  m_StyleTable.insert_or_assign(std::move(key), std::move(style));
198  }
199 
200  private:
201  Projection_t m_Projection;
202  Table_t m_StyleTable;
203  };
204 
218  template <Record TRecord,
219  std::invocable<const TRecord&> TProjection,
220  class TTable = std::unordered_map<
221  std::remove_cvref_t<std::invoke_result_t<TProjection, const TRecord&>>,
222  ConsoleTextStyle
223  >>
224  auto makeConsoleTextStyleTableFor(TProjection projection, TTable table)
225  {
226  return ConsoleTextStyleTable{ std::move(projection), std::move(table) };
227  }
228 
236  template <Record TRecord>
237  class ConsoleSink final :
238  public OStreamSink<TRecord>
239  {
240  using Super = OStreamSink<TRecord>;
241 
242  public:
243  using typename Super::Record_t;
244  using typename Super::Formatter_t;
245  using typename Super::Filter_t;
246  using typename Super::FlushPolicy_t;
247  using TextStylePolicy_t = std::function<ConsoleTextStyle(const Record_t&)>;
248 
249  protected:
254  [[nodiscard]]
256  {
257  return [](const Record_t&) { return defaultConsoleTextStyle; };
258  }
259 
260  public:
264  explicit ConsoleSink() :
265  Super{ std::cout }
266  {
267  }
268 
273  ~ConsoleSink() noexcept = default;
274 
278  ConsoleSink(const ConsoleSink&) = delete;
282  ConsoleSink& operator =(const ConsoleSink&) = delete;
283 
291  ConsoleSink& operator =(ConsoleSink&&) = delete;
292 
298  template <ConsoleTextStylePolicyFor<Record_t> TStylePolicy>
299  void setTextStylePolicy(TStylePolicy&& policy)
300  {
301  std::scoped_lock lock{ m_TextStylePolicyMx };
302  m_TextStylePolicy = std::forward<TStylePolicy>(policy);
303  }
304 
309  {
310  std::scoped_lock lock{ m_TextStylePolicyMx };
311  m_TextStylePolicy = defaultTextStylePolicy();
312  }
313 
314  private:
315  std::mutex m_TextStylePolicyMx;
316  TextStylePolicy_t m_TextStylePolicy{ defaultTextStylePolicy() };
317 
318  void beforeMessageWrite(const Record_t& record, std::string_view message) override
319  {
320  std::scoped_lock lock{ m_TextStylePolicyMx };
321  assert(m_TextStylePolicy && "TextStylePolicy must not be empty.");
322  std::cout << std::invoke(m_TextStylePolicy, record);
323  }
324 
325  void afterMessageWrite(const Record_t& record, std::string_view message) override
326  {
327  std::cout << defaultConsoleTextStyle;
328  }
329  };
330 
333 }
334 
335 namespace sl::log::detail
336 {
337  inline std::ostream& applyTextColor(std::ostream& out, ConsoleTextStyle::Color color) noexcept
338  {
339  using Color = ConsoleTextStyle::Color;
340  if (color < Color::brightBlack)
341  {
342  const auto begin = static_cast<unsigned>(rang::fg::black);
343  out << static_cast<rang::fg>(static_cast<unsigned>(color) + begin);
344  }
345  else
346  {
347  const auto begin = static_cast<unsigned>(rang::fgB::black);
348  const auto localColor = static_cast<Color>(begin +
349  static_cast<unsigned>(color) -
350  static_cast<unsigned>(Color::brightBlack));
351  out << static_cast<rang::fgB>(localColor);
352  }
353  return out;
354  }
355 
356  inline std::ostream& applyBackgroundColor(std::ostream& out, ConsoleTextStyle::Color color) noexcept
357  {
358  using Color = ConsoleTextStyle::Color;
359  if (color < Color::brightBlack)
360  {
361  const auto begin = static_cast<unsigned>(rang::bg::black);
362  out << static_cast<rang::bg>(static_cast<unsigned>(color) + begin);
363  }
364  else
365  {
366  const auto begin = static_cast<unsigned>(rang::bgB::black);
367  const auto localColor = static_cast<Color>(begin +
368  static_cast<unsigned>(color) -
369  static_cast<unsigned>(Color::brightBlack));
370  out << static_cast<rang::bgB>(localColor);
371  }
372  return out;
373  }
374 
375  inline std::ostream& applyStyle(std::ostream& out, ConsoleTextStyle::Style style) noexcept
376  {
377  const auto value = static_cast<rang::style>(style);
378  out << value;
379  return out;
380  }
381 }
382 
383 #endif
std::function< bool(const Record_t &)> Filter_t
Definition: BasicSink.hpp:59
std::function< std::string(const Record_t &)> Formatter_t
Definition: BasicSink.hpp:58
Sink class for directly logging onto std::cout.
Definition: ConsoleSink.hpp:239
void setTextStylePolicy(TStylePolicy &&policy)
Sets the active ConsoleTextStylePolicy.
Definition: ConsoleSink.hpp:299
~ConsoleSink() noexcept=default
Default destructor.
void removeTextStylePolicy()
Replaces the current ConsoleTextStylePolicy with the default one.
Definition: ConsoleSink.hpp:308
ConsoleSink()
Constructor.
Definition: ConsoleSink.hpp:264
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
static constexpr TextStylePolicy_t defaultTextStylePolicy()
Constructs the default TextStylePolicy.
Definition: ConsoleSink.hpp:255
std::function< ConsoleTextStyle(const Record_t &)> TextStylePolicy_t
Definition: ConsoleSink.hpp:247
Convenience class for setting up style policies for a given Record member.
Definition: ConsoleSink.hpp:155
typename Table_t::key_type Key_t
Definition: ConsoleSink.hpp:159
ConsoleTextStyle operator()(const TRecord &record) const
Invocation operator.
Definition: ConsoleSink.hpp:180
void insert(Key_t key, ConsoleTextStyle style)
Inserts a style policy.
Definition: ConsoleSink.hpp:195
ConsoleTextStyleTable(TProjection projection, TTable table)
Constructor.
Definition: ConsoleSink.hpp:166
std::remove_cvref_t< TTable > Table_t
Definition: ConsoleSink.hpp:158
std::remove_cvref_t< TProjection > Projection_t
Definition: ConsoleSink.hpp:157
Sink interface class.
Definition: ISink.hpp:29
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
An std::ostream orientated Sink class which extends BasicSink.
Definition: OStreamSink.hpp:35
std::unique_ptr< detail::AbstractFlushPolicyWrapper< Record_t > > FlushPolicy_t
Definition: OStreamSink.hpp:42
std::remove_cvref_t< TRecord > Record_t
Used Record type.
Definition: ISink.hpp:34
constexpr ConsoleTextStyle defaultConsoleTextStyle
A constant object used for resetting the style back to default.
Definition: ConsoleSink.hpp:105
concept ConsoleTextStylePolicyFor
Concept which checks for validity of given text style policy.
Definition: ConsoleSink.hpp:97
auto makeConsoleTextStyleTableFor(TProjection projection, TTable table)
The factory function for creating ConsoleTextStyleTable instances.
Definition: ConsoleSink.hpp:224
std::ostream & operator<<(std::ostream &out, const ConsoleTextStyle &style)
Operator << overload for ConsoleTextStyle type.
Definition: ConsoleSink.hpp:135
concept Record
Concept which all the necessary concepts for Record types.
Definition: Record.hpp:204
Definition: BasicSink.hpp:22
Collection of possible style and color options for text printed onto the console.
Definition: ConsoleSink.hpp:43
Color textColor
determines the text color
Definition: ConsoleSink.hpp:85
Style
Definition: ConsoleSink.hpp:67
Style style
determines the style
Definition: ConsoleSink.hpp:80
Color bgColor
determines the background color
Definition: ConsoleSink.hpp:90
Color
Definition: ConsoleSink.hpp:45