qxLib
logger.inl
Go to the documentation of this file.
1 /**
2 
3  @file logger.inl
4  @author Khrapov
5  @date 17.06.2019
6  @copyright © Nick Khrapov, 2021. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 namespace details
14 {
15 
16 template<sbo_poly_assignable_c<base_logger_stream> stream_t>
17 static constexpr auto logger_stream_filter = [](const logger::logger_sbo& stream)
18 {
19  return stream->is<stream_t>();
20 };
21 
22 } // namespace details
23 
24 inline logger::logger() noexcept
25 {
26  add_stream(fwrite_logger_stream());
27 }
28 
29 inline logger::~logger() noexcept
30 {
31  logger::flush();
32 }
33 
34 template<sbo_poly_assignable_c<base_logger_stream> stream_t>
35 inline void logger::add_stream(stream_t stream) noexcept
36 {
37  std::unique_lock _(m_StreamsMutex);
38  m_Streams.emplace_back(std::move(stream));
39 }
40 
41 template<sbo_poly_assignable_c<base_logger_stream> stream_t>
42 inline stream_t* logger::get_stream() noexcept
43 {
44  auto it = std::ranges::find_if(m_Streams, details::logger_stream_filter<stream_t>);
45  return it != m_Streams.end() ? static_cast<stream_t*>(&it->get()) : nullptr;
46 }
47 
48 template<sbo_poly_assignable_c<base_logger_stream> stream_t>
49 inline auto logger::get_streams() noexcept
50 {
51  return m_Streams | std::views::filter(details::logger_stream_filter<stream_t>)
52  | std::views::transform(
53  [](logger_sbo& stream)
54  {
55  return static_cast<stream_t*>(&stream.get());
56  });
57 }
58 
59 inline std::shared_mutex& logger::get_streams_mutex() noexcept
60 {
61  return m_StreamsMutex;
62 }
63 
64 template<sbo_poly_assignable_c<base_logger_stream> stream_t>
65 inline size_t logger::remove_streams() noexcept
66 {
67  std::unique_lock _(m_StreamsMutex);
68  return std::erase_if(m_Streams, details::logger_stream_filter<stream_t>);
69 }
70 
71 inline void logger::register_category(const category& category, category_data data) noexcept
72 {
73  register_category(category.get_name(), std::move(data));
74 }
75 
76 inline void logger::register_category(string_view svCategoryName, category_data data) noexcept
77 {
78  std::unique_lock _(m_RegisteredCategoriesMutex);
79  m_RegisteredCategories.emplace(svCategoryName, std::move(data));
80 }
81 
82 inline void logger::set_default_formatter(format_function_pointer pFormatter) noexcept
83 {
84  m_DefaultFormatFunction = pFormatter;
85 }
86 
87 inline void logger::log(
88  const category& category,
89  verbosity eVerbosity,
90  std::thread::id threadId,
91  std::chrono::system_clock::time_point messageTime,
92  string_view svFile,
93  string_view svFunction,
94  int nLine,
96 {
97  string sMessage = std::move(message.sValue);
98 
99  const flags<message_necessity_type> eMessageNecessity =
100  get_message_necessity_type(category, eVerbosity, threadId, messageTime, svFile, svFunction, nLine);
101  if (eMessageNecessity != message_necessity_type::not_required)
102  {
103  bool bFormatted = false;
104  {
105  std::shared_lock _(m_RegisteredCategoriesMutex);
106  if (auto itRegisteredCategory = m_RegisteredCategories.find(category.get_name());
107  itRegisteredCategory != m_RegisteredCategories.end())
108  {
109  const category_data& data = itRegisteredCategory->second;
110  if (data.formatFunction)
111  {
112  sMessage = data.formatFunction(
113  category,
114  eVerbosity,
115  threadId,
116  messageTime,
117  svFile,
118  svFunction,
119  nLine,
120  std::move(sMessage));
121 
122  bFormatted = true;
123  }
124  }
125  }
126 
127  if (!bFormatted)
128  {
129  sMessage = m_DefaultFormatFunction.load()(
130  category,
131  eVerbosity,
132  threadId,
133  messageTime,
134  svFile,
135  svFunction,
136  nLine,
137  std::move(sMessage));
138  }
139 
140  {
141  std::shared_lock _(m_StreamsMutex);
142  for (auto& stream : m_Streams)
143  {
144  if (eMessageNecessity != message_necessity_type::one_of_streams_requires
145  || stream->log_unconditionally_required(
146  category,
147  eVerbosity,
148  threadId,
149  messageTime,
150  svFile,
151  svFunction,
152  nLine))
153  {
154  stream->log(category, eVerbosity, threadId, messageTime, svFile, svFunction, nLine, sMessage);
155  }
156  }
157  }
158  }
159 
160  m_StringsPool.release(std::move(sMessage), message.nIndex);
161 }
162 
163 inline void logger::flush()
164 {
165  std::shared_lock _(m_StreamsMutex);
166  for (auto& stream : m_Streams)
167  stream->flush();
168 }
169 
170 inline void logger::reset() noexcept
171 {
172  flush();
173 
174  {
175  std::unique_lock _(m_StreamsMutex);
176  m_Streams.clear();
177  }
178 
179  {
180  std::unique_lock _(m_RegisteredCategoriesMutex);
181  m_RegisteredCategories.clear();
182  }
183 
184  m_DefaultFormatFunction = format_message_qx;
185 }
186 
188  const category& category,
189  verbosity eVerbosity,
190  std::thread::id threadId,
191  std::chrono::system_clock::time_point messageTime,
192  string_view svFile,
193  string_view svFunction,
194  int nLine) const noexcept
195 {
196  flags<message_necessity_type> eMessageNecessity;
197  {
198  std::shared_lock _(m_StreamsMutex);
199  const bool bSomeStreamRequires = std::ranges::any_of(
200  m_Streams,
201  [&category, eVerbosity, threadId, messageTime, svFile, svFunction, nLine](const auto& stream)
202  {
203  return stream->log_unconditionally_required(
204  category,
205  eVerbosity,
206  threadId,
207  messageTime,
208  svFile,
209  svFunction,
210  nLine);
211  });
212  if (bSomeStreamRequires)
213  eMessageNecessity |= message_necessity_type::one_of_streams_requires;
214  }
215 
216  {
217  std::shared_lock _(m_RegisteredCategoriesMutex);
218  if (auto itRegisteredCategory = m_RegisteredCategories.find(category.get_name());
219  itRegisteredCategory != m_RegisteredCategories.end())
220  {
221  const category_data& data = itRegisteredCategory->second;
222  if (eVerbosity >= data.eRuntimeVerbosity)
223  eMessageNecessity |= message_necessity_type::category_verbosity;
224  }
225  }
226 
227  if (eVerbosity >= verbosity::log)
228  eMessageNecessity |= message_necessity_type::default_verbosity;
229 
230  return eMessageNecessity;
231 }
232 
233 inline logger::logger_string_pool* logger::_get_string_pool() noexcept
234 {
235  return &m_StringsPool;
236 }
237 
238 } // namespace qx
A category is a class that identifies a particular piece of code. This code can be located in differe...
Definition: category.h:59
constexpr string_view get_name() const noexcept
Get category name.
Definition: category.inl:26
Wrapper for enumerations to be used as a list of flags.
Definition: flags.h:62
virtual void log(const category &category, verbosity eVerbosity, std::thread::id threadId, std::chrono::system_clock::time_point messageTime, string_view svFile, string_view svFunction, int nLine, logger_string_pool::item message)
Log to all streams.
Definition: logger.inl:87
size_t remove_streams() noexcept
Remove all the streams of the given type.
Definition: logger.inl:65
auto get_streams() noexcept
Get all the streams of the given type.
Definition: logger.inl:49
flags< message_necessity_type > get_message_necessity_type(const category &category, verbosity eVerbosity, std::thread::id threadId, std::chrono::system_clock::time_point messageTime, string_view svFile, string_view svFunction, int nLine) const noexcept
Check if this message will go somewhere.
Definition: logger.inl:187
void add_stream(stream_t stream) noexcept
Add an output stream to the logger.
Definition: logger.inl:35
void register_category(const category &category, category_data data) noexcept
Add custom rules for category.
Definition: logger.inl:71
std::shared_mutex & get_streams_mutex() noexcept
Get streams mutex.
Definition: logger.inl:59
stream_t * get_stream() noexcept
Get the first occurrence of a stream of the given type.
Definition: logger.inl:42
virtual void reset() noexcept
Reset logger and clear all streams.
Definition: logger.inl:170
void set_default_formatter(format_function_pointer pFormatter) noexcept
Set a function that will be used as the default formatter in case no formatter found in categories re...
Definition: logger.inl:82
virtual void flush()
Flush all streams.
Definition: logger.inl:163
Small Buffer Object for polymorphic classes.
Definition: sbo_poly.h:58
base_t & get() noexcept
Get object reference. Always valid.
Definition: sbo_poly.inl:127
Fixed-size atomic string pool.
Definition: string_pool.h:34
void release(string sValue, int nIndex)
Return a string back to the pool.
Definition: string_pool.inl:58
string format_message_qx(const category &category, verbosity eVerbosity, std::thread::id threadId, std::chrono::system_clock::time_point messageTime, string_view svFile, string_view svFunction, int nLine, string sMessage) noexcept