async_sink: catch back thread exceptions and rethrow on the calling thread on the next logging request
This commit is contained in:
		@@ -22,6 +22,14 @@
 | 
				
			|||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 | 
					/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 | 
				
			||||||
/*************************************************************************/
 | 
					/*************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// async sink:
 | 
				
			||||||
 | 
					// Process logs asynchronously using a back thread.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If the internal queue of log messages reaches its max size,
 | 
				
			||||||
 | 
					// then the client call will block until there is more room.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// If the back thread throws during logging, a spdlog::spdlog_ex exception
 | 
				
			||||||
 | 
					// will be thrown in client's thread when tries to log the next message
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <thread>
 | 
					#include <thread>
 | 
				
			||||||
@@ -68,9 +76,17 @@ private:
 | 
				
			|||||||
    std::atomic<bool> _active;
 | 
					    std::atomic<bool> _active;
 | 
				
			||||||
    q_type _q;
 | 
					    q_type _q;
 | 
				
			||||||
    std::thread _back_thread;
 | 
					    std::thread _back_thread;
 | 
				
			||||||
    //Clear all remaining messages(if any), stop the _back_thread and join it
 | 
					 | 
				
			||||||
    void _join() ;
 | 
					 | 
				
			||||||
    std::mutex _mutex;
 | 
					    std::mutex _mutex;
 | 
				
			||||||
 | 
					    //Last exception thrown from the back thread
 | 
				
			||||||
 | 
					    std::shared_ptr<spdlog_ex> _last_backthread_ex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //will throw last back thread exception or if backthread no active
 | 
				
			||||||
 | 
					    void _push_sentry();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Clear all remaining messages(if any), stop the _back_thread and join it
 | 
				
			||||||
 | 
					    void _join();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -80,7 +96,7 @@ private:
 | 
				
			|||||||
///////////////////////////////////////////////////////////////////////////////
 | 
					///////////////////////////////////////////////////////////////////////////////
 | 
				
			||||||
inline spdlog::sinks::async_sink::async_sink(const q_type::size_type max_queue_size)
 | 
					inline spdlog::sinks::async_sink::async_sink(const q_type::size_type max_queue_size)
 | 
				
			||||||
    :_sinks(),
 | 
					    :_sinks(),
 | 
				
			||||||
     _active(true),
 | 
					     _active(false),
 | 
				
			||||||
     _q(max_queue_size),
 | 
					     _q(max_queue_size),
 | 
				
			||||||
     _back_thread(&async_sink::_thread_loop, this)
 | 
					     _back_thread(&async_sink::_thread_loop, this)
 | 
				
			||||||
{}
 | 
					{}
 | 
				
			||||||
@@ -92,14 +108,15 @@ inline spdlog::sinks::async_sink::~async_sink()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
inline void spdlog::sinks::async_sink::_sink_it(const details::log_msg& msg)
 | 
					inline void spdlog::sinks::async_sink::_sink_it(const details::log_msg& msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (!_active)
 | 
					    _push_sentry();
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    _q.push(msg);
 | 
					    _q.push(msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void spdlog::sinks::async_sink::_thread_loop()
 | 
					inline void spdlog::sinks::async_sink::_thread_loop()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    static std::chrono::seconds  pop_timeout { 1 };
 | 
					    std::chrono::seconds  pop_timeout { 1 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (_active)
 | 
					    while (_active)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        q_type::item_type msg;
 | 
					        q_type::item_type msg;
 | 
				
			||||||
@@ -109,7 +126,20 @@ inline void spdlog::sinks::async_sink::_thread_loop()
 | 
				
			|||||||
                return;
 | 
					                return;
 | 
				
			||||||
            for (auto &s : _sinks)
 | 
					            for (auto &s : _sinks)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                s->log(msg);
 | 
					                try
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    s->log(msg);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                catch (const std::exception& ex)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _last_backthread_ex = std::make_shared<spdlog_ex>(ex.what());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                catch (...)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    _last_backthread_ex = std::make_shared<spdlog_ex>("Unknown exception");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -149,10 +179,18 @@ inline void spdlog::sinks::async_sink::shutdown(const std::chrono::milliseconds&
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline void spdlog::sinks::async_sink::_push_sentry()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    std::shared_ptr<spdlog_ex> ex_copy = std::move(_last_backthread_ex);
 | 
				
			||||||
 | 
					    if (ex_copy)
 | 
				
			||||||
 | 
					        throw *ex_copy;
 | 
				
			||||||
 | 
					    if (!_active)
 | 
				
			||||||
 | 
					        throw(spdlog_ex("async_sink not active"));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void spdlog::sinks::async_sink::_join()
 | 
					inline void spdlog::sinks::async_sink::_join()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    std::lock_guard<std::mutex> guard(_mutex);
 | 
					 | 
				
			||||||
    _active = false;
 | 
					    _active = false;
 | 
				
			||||||
    if (_back_thread.joinable())
 | 
					    if (_back_thread.joinable())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -160,11 +198,9 @@ inline void spdlog::sinks::async_sink::_join()
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _back_thread.join();
 | 
					            _back_thread.join();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        catch (const std::system_error&) //Dont crush if thread not joinable
 | 
					        catch (const std::system_error&) //Dont crash if thread not joinable
 | 
				
			||||||
        {
 | 
					        {}
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user