summaryrefslogtreecommitdiff
path: root/doc/html/boost_asio/example/cpp03/services/logger_service.hpp
blob: 071d6bfc5e453d6cdcaa19eae4130159ab4205d3 (plain)
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-2017 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.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::io_context::service
{
public:
  /// The unique service identifier.
  static boost::asio::io_context::id id;

  /// 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::io_context& io_context)
    : boost::asio::io_context::service(io_context),
      work_io_context_(),
      work_(boost::asio::make_work_guard(work_io_context_)),
      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_.reset();
    if (work_thread_)
      work_thread_->join();
  }

  /// Destroy all user-defined handler objects owned by the service.
  void shutdown_service()
  {
  }

  /// 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_;

  /// 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::executor_work_guard<
      boost::asio::io_context::executor_type> 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