1 // 2 // logger_service.hpp 3 // ~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef SERVICES_LOGGER_SERVICE_HPP 12 #define SERVICES_LOGGER_SERVICE_HPP 13 14 #include <boost/asio.hpp> 15 #include <boost/thread/thread.hpp> 16 #include <boost/bind/bind.hpp> 17 #include <boost/date_time/posix_time/posix_time.hpp> 18 #include <boost/noncopyable.hpp> 19 #include <boost/scoped_ptr.hpp> 20 #include <fstream> 21 #include <sstream> 22 #include <string> 23 24 namespace services { 25 26 /// Service implementation for the logger. 27 class logger_service 28 : public boost::asio::execution_context::service 29 { 30 public: 31 /// The type used to identify this service in the execution context. 32 typedef logger_service key_type; 33 34 /// The backend implementation of a logger. 35 struct logger_impl 36 { logger_implservices::logger_service::logger_impl37 explicit logger_impl(const std::string& ident) : identifier(ident) {} 38 std::string identifier; 39 }; 40 41 /// The type for an implementation of the logger. 42 typedef logger_impl* impl_type; 43 44 /// Constructor creates a thread to run a private io_context. logger_service(boost::asio::execution_context & context)45 logger_service(boost::asio::execution_context& context) 46 : boost::asio::execution_context::service(context), 47 work_io_context_(), 48 work_(boost::asio::require(work_io_context_.get_executor(), 49 boost::asio::execution::outstanding_work.tracked)), 50 work_thread_(new boost::thread( 51 boost::bind(&boost::asio::io_context::run, &work_io_context_))) 52 { 53 } 54 55 /// Destructor shuts down the private io_context. ~logger_service()56 ~logger_service() 57 { 58 /// Indicate that we have finished with the private io_context. Its 59 /// io_context::run() function will exit once all other work has completed. 60 work_ = boost::asio::any_io_executor(); 61 if (work_thread_) 62 work_thread_->join(); 63 } 64 65 /// Destroy all user-defined handler objects owned by the service. shutdown()66 void shutdown() 67 { 68 } 69 70 /// Return a null logger implementation. null() const71 impl_type null() const 72 { 73 return 0; 74 } 75 76 /// Create a new logger implementation. create(impl_type & impl,const std::string & identifier)77 void create(impl_type& impl, const std::string& identifier) 78 { 79 impl = new logger_impl(identifier); 80 } 81 82 /// Destroy a logger implementation. destroy(impl_type & impl)83 void destroy(impl_type& impl) 84 { 85 delete impl; 86 impl = null(); 87 } 88 89 /// Set the output file for the logger. The current implementation sets the 90 /// output file for all logger instances, and so the impl parameter is not 91 /// actually needed. It is retained here to illustrate how service functions 92 /// are typically defined. use_file(impl_type &,const std::string & file)93 void use_file(impl_type& /*impl*/, const std::string& file) 94 { 95 // Pass the work of opening the file to the background thread. 96 boost::asio::post(work_io_context_, boost::bind( 97 &logger_service::use_file_impl, this, file)); 98 } 99 100 /// Log a message. log(impl_type & impl,const std::string & message)101 void log(impl_type& impl, const std::string& message) 102 { 103 // Format the text to be logged. 104 std::ostringstream os; 105 os << impl->identifier << ": " << message; 106 107 // Pass the work of writing to the file to the background thread. 108 boost::asio::post(work_io_context_, boost::bind( 109 &logger_service::log_impl, this, os.str())); 110 } 111 112 private: 113 /// Helper function used to open the output file from within the private 114 /// io_context's thread. use_file_impl(const std::string & file)115 void use_file_impl(const std::string& file) 116 { 117 ofstream_.close(); 118 ofstream_.clear(); 119 ofstream_.open(file.c_str()); 120 } 121 122 /// Helper function used to log a message from within the private io_context's 123 /// thread. log_impl(const std::string & text)124 void log_impl(const std::string& text) 125 { 126 ofstream_ << text << std::endl; 127 } 128 129 /// Private io_context used for performing logging operations. 130 boost::asio::io_context work_io_context_; 131 132 /// A work-tracking executor giving work for the private io_context to 133 /// perform. If we do not give the io_context some work to do then the 134 /// io_context::run() function will exit immediately. 135 boost::asio::any_io_executor work_; 136 137 /// Thread used for running the work io_context's run loop. 138 boost::scoped_ptr<boost::thread> work_thread_; 139 140 /// The file to which log messages will be written. 141 std::ofstream ofstream_; 142 }; 143 144 } // namespace services 145 146 #endif // SERVICES_LOGGER_SERVICE_HPP 147