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