#ifndef SERVICES_LOGGER_SERVICE_HPP
#define SERVICES_LOGGER_SERVICE_HPP
#include <boost/asio.hpp>
#include <functional>
#include <fstream>
#include <sstream>
#include <string>
#include <thread>
namespace services {
class logger_service
: public boost::asio::execution_context::service
{
public:
typedef logger_service key_type;
struct logger_impl
{
explicit logger_impl(const std::string& ident) : identifier(ident) {}
std::string identifier;
};
typedef logger_impl* impl_type;
logger_service(boost::asio::execution_context& context)
: boost::asio::execution_context::service(context),
work_io_context_(),
work_(boost::asio::make_work_guard(work_io_context_)),
work_thread_([this]{ work_io_context_.run(); })
{
}
logger_service(const logger_service&) = delete;
logger_service& operator=(const logger_service&) = delete;;
~logger_service()
{
work_.reset();
if (work_thread_.joinable())
work_thread_.join();
}
void shutdown()
{
}
impl_type null() const
{
return 0;
}
void create(impl_type& impl, const std::string& identifier)
{
impl = new logger_impl(identifier);
}
void destroy(impl_type& impl)
{
delete impl;
impl = null();
}
void use_file(impl_type& , const std::string& file)
{
boost::asio::post(work_io_context_,
std::bind(&logger_service::use_file_impl, this, file));
}
void log(impl_type& impl, const std::string& message)
{
std::ostringstream os;
os << impl->identifier << ": " << message;
boost::asio::post(work_io_context_,
std::bind(&logger_service::log_impl, this, os.str()));
}
private:
void use_file_impl(const std::string& file)
{
ofstream_.close();
ofstream_.clear();
ofstream_.open(file.c_str());
}
void log_impl(const std::string& text)
{
ofstream_ << text << std::endl;
}
boost::asio::io_context work_io_context_;
boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> work_;
std::thread work_thread_;
std::ofstream ofstream_;
};
}
#endif