43#include <condition_variable>
54 template <std::
size_t Instance = 0>
61 typedef std::string buffer_t;
63 typedef std::map<category_id, std::pair<bool, std::string>> category_map_t;
64 typedef std::map<std::thread::id, std::pair<std::shared_ptr<buffer_t>, std::shared_ptr<buffer_t>>> buffer_list_t;
65 typedef std::vector<i_logger*> copy_list_t;
77 std::lock_guard<std::recursive_mutex> lg{
mutex() };
78 copies().push_back(&aLogger);
82 std::lock_guard<std::recursive_mutex> lg{
mutex() };
83 copies().erase(std::remove(copies().begin(), copies().end(), &aLogger), copies().end());
87 std::lock_guard<std::recursive_mutex> lg{
mutex() };
88 return iLoggingThread != std::nullopt;
92 std::lock_guard<std::recursive_mutex> lg{
mutex() };
94 throw logging_thread_already_created();
95 iLoggingThread.emplace([&]()
100 iCommitSignal.wait(lk, [&]() {
return any_available() ||
is_destroying(); });
110 std::lock_guard<std::recursive_mutex> lg{
mutex() };
111 return iFilterSeverity;
115 std::lock_guard<std::recursive_mutex> lg{
mutex() };
116 iFilterSeverity = aSeverity;
124 std::lock_guard<std::recursive_mutex> lg{
mutex() };
125 iCategories[aId].first =
true;
126 iCategories[aId].second = aName.to_std_string_view();
127 for (
auto& copy : copies())
128 copy->register_category(aId, aName);
132 std::lock_guard<std::recursive_mutex> lg{
mutex() };
133 auto existing = iCategories.find(aId);
134 return existing != iCategories.end() && existing->second.first;
138 std::lock_guard<std::recursive_mutex> lg{
mutex() };
139 auto existing = iCategories.find(aId);
140 if (existing != iCategories.end())
141 existing->second.first =
true;
142 for (
auto& copy : copies())
143 copy->enable_category(aId);
147 std::lock_guard<std::recursive_mutex> lg{
mutex() };
148 auto existing = iCategories.find(aId);
149 if (existing != iCategories.end())
150 existing->second.first =
false;
151 for (
auto& copy : copies())
152 copy->disable_category(aId);
157 std::lock_guard<std::recursive_mutex> lg{
mutex() };
158 return iFormatter !=
nullptr;
162 std::lock_guard<std::recursive_mutex> lg{
mutex() };
163 if (iFormatter !=
nullptr)
169 std::lock_guard<std::recursive_mutex> lg{
mutex() };
170 iFormatter = std::shared_ptr<i_formatter>{ std::shared_ptr<i_formatter>{}, &aFormatter };
174 std::lock_guard<std::recursive_mutex> lg{
mutex() };
175 iFormatter =
nullptr;
187 using i_logger::operator<<;
190 std::lock_guard<std::recursive_mutex> lg{
mutex() };
192 for (
auto& copy : copies())
193 (*copy) << aSeverity;
198 std::lock_guard<std::recursive_mutex> lg{
mutex() };
200 for (
auto& copy : copies())
201 (*copy) << aCategory;
211 return iCommitSignalMutex;
215 return iCommitSignal;
220 iLoggingThread->join();
224 return message_severity_ref();
228 message_severity_ref() = aMessageSeverity;
232 return message_category_ref();
236 message_category_ref() = aid;
240 std::lock_guard<std::recursive_mutex> lg{
mutex() };
242 return existing == iCategories.end() || existing->second.first;
247 if (!iLoggingThread || std::this_thread::get_id() == iLoggingThread->get_id())
250 std::lock_guard<std::recursive_mutex> lg{
mutex() };
251 for (
auto& entry : buffers())
253 auto& buffers = entry.second;
254 std::swap(buffers.first, buffers.second);
257 thread_local buffer_t tempBuffer;
258 for (
auto& entry : buffers())
260 auto& buffer = *entry.second.second;
263 tempBuffer += buffer;
277 while (any_available())
279 using namespace std::chrono_literals;
280 std::this_thread::sleep_for(10ms);
294 buffer() += aMessage.to_std_string_view();
295 NewLogMessage.trigger(aMessage);
299 thread_local string tempFormattedMessage;
302 NewLogMessage.trigger(tempFormattedMessage);
303 tempFormattedMessage.
clear();
308 for (
auto& copy : copies())
309 copy->flush(aMessage);
315 virtual void commit(buffer_t
const& aBuffer) = 0;
336 severity const& message_severity_ref()
const
339 return tMessageSeverity;
343 return const_cast<severity&
>(
const_cast<self_type const&
>(*this).message_severity_ref());
348 return tMessageCategory;
352 return const_cast<category_id&
>(
const_cast<self_type const&
>(*this).message_category_ref());
354 bool any_available()
const
356 std::lock_guard<std::recursive_mutex> lg{
mutex() };
357 for (
auto& entry : buffers())
359 auto& buffer = *entry.second.first;
365 buffer_t
const& buffer()
const
367 std::lock_guard<std::recursive_mutex> lg{
mutex() };
368 thread_local struct cleanup
374 if (!parentDestroyed)
377 std::lock_guard<std::recursive_mutex> lg{ parent.mutex() };
378 parent.buffers().erase(std::this_thread::get_id());
381 } cleanup{ *
this, *
this };
382 auto existing = iBuffers.find(std::this_thread::get_id());
383 if (existing != iBuffers.end())
384 return *existing->second.first;
385 existing = iBuffers.insert(buffer_list_t::value_type{ std::this_thread::get_id(), buffer_list_t::mapped_type{ std::make_shared<buffer_t>(), std::make_shared<buffer_t>() } }).first;
386 return *existing->second.first;
390 return const_cast<buffer_t&
>(
const_cast<logger const&
>(*this).buffer());
392 buffer_list_t& buffers()
const
394 std::lock_guard<std::recursive_mutex> lg{
mutex() };
397 copy_list_t
const& copies()
const
401 copy_list_t& copies()
406 mutable std::recursive_mutex iMutex;
407 mutable std::mutex iCommitSignalMutex;
408 mutable std::condition_variable iCommitSignal;
409 std::optional<std::thread> iLoggingThread;
411 category_map_t iCategories;
412 std::shared_ptr<i_formatter> iFormatter;
414 mutable buffer_list_t iBuffers;
417 static uuid const&
iid() {
static uuid const sIid{ Instance + 0x442ed95b, 0x215c, 0x4b6e, 0xb945, { 0xf9, 0x61, 0xc4, 0xca, 0xd8, 0x7b } };
return sIid; }
void set_destroying() override
bool is_destroying() const final
virtual bool category_enabled(category_id aId) const =0
virtual void enable_category(category_id aId)=0
virtual void register_category(category_id aId, i_string const &aName)=0
virtual void disable_category(category_id aId)=0
bool has_logging_thread() const final
void set_formatter(i_formatter &aFormatter) final
i_logger & operator<<(category_id aCategory) final
void flush(i_string const &aMessage) final
void create_logging_thread() final
void set_message_category(category_id aid)
void reset_line_id(line_id_t aLineId=DefaultInitialLineId) final
void clear_formatter() final
bool has_formatter() const final
severity message_severity() const
void cancel_copy_to(i_logger &aLogger) final
void enable_category(category_id aId) final
void set_message_severity(severity aMessageSeverity)
void disable_category(category_id aId) final
virtual void commit(buffer_t const &aBuffer)=0
std::mutex & commit_signal_mutex() const
void set_filter_severity(severity aSeverity) final
severity filter_severity() const final
std::condition_variable & commit_signal() const
void copy_to(i_logger &aLogger) final
bool category_enabled(category_id aId) const final
i_logger & operator<<(severity aSeverity) final
bool message_category_enabled() const
std::recursive_mutex & mutex() const
line_id_t line_id() const final
void register_category(category_id aId, i_string const &aName) final
static uuid const & iid()
category_id message_category() const
void join_logging_thread()
i_formatter & formatter() const final
std::string_view to_std_string_view() const noexcept
neolib::logger::logger< 9999 > logger
constexpr line_id_t DefaultInitialLineId
lifetime_flag< lifetime_state::Destroyed > destroyed_flag
void swap(plf::hive< element_type, allocator_type > &a, plf::hive< element_type, allocator_type > &b) noexcept(std::allocator_traits< allocator_type >::propagate_on_container_swap::value||std::allocator_traits< allocator_type >::is_always_equal::value)
#define define_declared_event(name, declName,...)