• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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