| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <thread>
 | 
					
						
							|  |  |  | #include <chrono>
 | 
					
						
							|  |  |  | #include <atomic>
 | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "base_sink.h"
 | 
					
						
							|  |  |  | #include "../logger.h"
 | 
					
						
							|  |  |  | #include "../details/blocking_queue.h"
 | 
					
						
							| 
									
										
										
										
											2014-03-28 19:03:24 +03:00
										 |  |  | #include "../details/log_msg.h"
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-30 21:25:33 +03:00
										 |  |  | #include<iostream>
 | 
					
						
							| 
									
										
										
										
											2014-03-28 19:03:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | namespace c11log | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | namespace sinks | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-30 21:25:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | class async_sink : public base_sink | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     using q_type = details::blocking_queue<details::log_msg>; | 
					
						
							| 
									
										
										
										
											2014-03-28 19:03:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     explicit async_sink(const q_type::size_type max_queue_size); | 
					
						
							| 
									
										
										
										
											2014-03-29 13:04:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |     //Stop logging and join the back thread
 | 
					
						
							|  |  |  |     // TODO: limit with timeout of the join and kill it afterwards?
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     ~async_sink(); | 
					
						
							|  |  |  |     void add_sink(logger::sink_ptr sink); | 
					
						
							|  |  |  |     void remove_sink(logger::sink_ptr sink_ptr); | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     q_type& q(); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     //Wait to remaining items (if any) in the queue to be written and shutdown
 | 
					
						
							| 
									
										
										
										
											2014-03-29 13:04:42 +03:00
										 |  |  |     void shutdown(const std::chrono::milliseconds& timeout); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | protected: | 
					
						
							| 
									
										
										
										
											2014-03-28 19:03:24 +03:00
										 |  |  |     void _sink_it(const details::log_msg& msg) override; | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     void _thread_loop(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							|  |  |  |     c11log::logger::sinks_vector_t _sinks; | 
					
						
							|  |  |  |     std::atomic<bool> _active; | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     q_type _q; | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     std::thread _back_thread; | 
					
						
							|  |  |  |     //Clear all remaining messages(if any), stop the _back_thread and join it
 | 
					
						
							|  |  |  |     void _shutdown(); | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |     std::mutex _shutdown_mutex; | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | // async_sink class implementation
 | 
					
						
							|  |  |  | ///////////////////////////////////////////////////////////////////////////////
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  | inline c11log::sinks::async_sink::async_sink(const q_type::size_type max_queue_size) | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     :_sinks(), | 
					
						
							|  |  |  |      _active(true), | 
					
						
							|  |  |  |      _q(max_queue_size), | 
					
						
							|  |  |  |      _back_thread(&async_sink::_thread_loop, this) | 
					
						
							|  |  |  | {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline c11log::sinks::async_sink::~async_sink() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _shutdown(); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-03-30 21:25:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-28 19:03:24 +03:00
										 |  |  | inline void c11log::sinks::async_sink::_sink_it(const details::log_msg& msg) | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  | {     | 
					
						
							|  |  |  |     if(!_active || msg.str.empty()) | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |         return; | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     _q.push(msg); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline void c11log::sinks::async_sink::_thread_loop() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     static std::chrono::seconds  pop_timeout { 1 }; | 
					
						
							|  |  |  |     while (_active) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |         q_type::item_type msg; | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |         if (_q.pop(msg, pop_timeout)) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             for (auto &sink : _sinks) | 
					
						
							|  |  |  |             { | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |                 sink->log(msg); | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |                 if(!_active) | 
					
						
							|  |  |  |                     break; | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline void c11log::sinks::async_sink::add_sink(logger::sink_ptr sink) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     _sinks.push_back(sink); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  | inline void c11log::sinks::async_sink::remove_sink(logger::sink_ptr sink) | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  |     _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end()); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-08 02:23:07 +03:00
										 |  |  | inline c11log::sinks::async_sink::q_type& c11log::sinks::async_sink::q() | 
					
						
							| 
									
										
										
										
											2014-03-30 23:47:42 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |     return _q; | 
					
						
							| 
									
										
										
										
											2014-03-30 23:47:42 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-29 13:04:42 +03:00
										 |  |  | inline void c11log::sinks::async_sink::shutdown(const std::chrono::milliseconds& timeout) | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |     if(timeout > std::chrono::milliseconds::zero()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto until = log_clock::now() + timeout; | 
					
						
							|  |  |  |         while (_q.size() > 0 && log_clock::now() < until) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             std::this_thread::sleep_for(std::chrono::milliseconds(2)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     _shutdown(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | inline void c11log::sinks::async_sink::_shutdown() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |     std::lock_guard<std::mutex> guard(_shutdown_mutex); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     if(_active) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         _active = false; | 
					
						
							|  |  |  |         if (_back_thread.joinable()) | 
					
						
							| 
									
										
										
										
											2014-03-31 02:31:26 +03:00
										 |  |  |             _back_thread.join(); | 
					
						
							| 
									
										
										
										
											2014-03-22 14:11:17 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |