1 /*
2  *                 Copyright Lingxi Li 2015.
3  *              Copyright Andrey Semashev 2016.
4  * Distributed under the Boost Software License, Version 1.0.
5  *    (See accompanying file LICENSE_1_0.txt or copy at
6  *          http://www.boost.org/LICENSE_1_0.txt)
7  */
8 /*!
9  * \file   text_ipc_message_queue_backend.hpp
10  * \author Lingxi Li
11  * \author Andrey Semashev
12  * \date   14.10.2015
13  *
14  * The header contains implementation of a text interprocess message queue sink
15  * backend along with implementation of a supporting interprocess message queue.
16  */
17 
18 #ifndef BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_
19 #define BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_
20 
21 #include <limits>
22 #include <string>
23 #include <boost/cstdint.hpp>
24 #include <boost/move/core.hpp>
25 #include <boost/preprocessor/control/if.hpp>
26 #include <boost/preprocessor/comparison/equal.hpp>
27 #include <boost/log/detail/config.hpp>
28 #include <boost/log/detail/parameter_tools.hpp>
29 #include <boost/log/core/record_view.hpp>
30 #include <boost/log/sinks/basic_sink_backend.hpp>
31 #include <boost/log/sinks/frontend_requirements.hpp>
32 #include <boost/log/exceptions.hpp>
33 #include <boost/log/detail/header.hpp>
34 
35 #ifdef BOOST_HAS_PRAGMA_ONCE
36 #pragma once
37 #endif
38 
39 namespace boost {
40 
41 BOOST_LOG_OPEN_NAMESPACE
42 
43 namespace sinks {
44 
45 #ifndef BOOST_LOG_DOXYGEN_PASS
46 
47 #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1(n, data)\
48     template< typename T0 >\
49     explicit text_ipc_message_queue_backend(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\
50         m_queue(arg0) {}
51 
52 #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N(n, data)\
53     template< BOOST_PP_ENUM_PARAMS(n, typename T) >\
54     explicit text_ipc_message_queue_backend(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\
55         m_queue(BOOST_PP_ENUM_PARAMS(n, arg)) {}
56 
57 #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL(z, n, data)\
58     BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N)(n, data)
59 
60 #endif // BOOST_LOG_DOXYGEN_PASS
61 
62 /*!
63  * \brief An implementation of a text interprocess message queue sink backend and
64  *        a supporting interprocess message queue.
65  *
66  * The sink backend sends formatted log messages to an interprocess message queue
67  * which can be extracted by a viewer process. Methods of this class are not
68  * thread-safe, unless otherwise specified.
69  */
70 template< typename QueueT >
71 class text_ipc_message_queue_backend :
72     public basic_formatted_sink_backend< char, concurrent_feeding >
73 {
74     //! Base type
75     typedef basic_formatted_sink_backend< char, concurrent_feeding > base_type;
76 
77 public:
78     //! Character type
79     typedef base_type::char_type char_type;
80     //! String type to be used as a message text holder
81     typedef base_type::string_type string_type;
82     //! Interprocess message queue type
83     typedef QueueT queue_type;
84 
85 private:
86     //! Interprocess queue
87     queue_type m_queue;
88 
89 public:
90     /*!
91      * Default constructor. The method constructs the backend using the default-constructed
92      * interprocess message queue. The queue may need additional setup in order to be able
93      * to send messages.
94      */
text_ipc_message_queue_backend()95     text_ipc_message_queue_backend() BOOST_NOEXCEPT
96     {
97     }
98 
99     /*!
100      * Initializing constructor. The method constructs the backend using the provided
101      * interprocess message queue. The constructor moves from the provided queue.
102      */
text_ipc_message_queue_backend(BOOST_RV_REF (queue_type)queue)103     explicit text_ipc_message_queue_backend(BOOST_RV_REF(queue_type) queue) BOOST_NOEXCEPT :
104         m_queue(static_cast< BOOST_RV_REF(queue_type) >(queue))
105     {
106     }
107 
108     /*!
109      * Constructor that passes arbitrary named parameters to the interprocess queue constructor.
110      * Refer to the queue documentation for the list of supported parameters.
111      */
112 #ifndef BOOST_LOG_DOXYGEN_PASS
113     BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL, ~)
114 #else
115     template< typename... Args >
116     explicit text_ipc_message_queue_backend(Args&&... args);
117 #endif
118 
119     /*!
120      * The method returns a reference to the managed \c queue_type object.
121      *
122      * \return A reference to the managed \c queue_type object.
123      */
message_queue()124     queue_type& message_queue() BOOST_NOEXCEPT { return m_queue; }
125 
126     /*!
127      * The method returns a constant reference to the managed \c queue_type object.
128      *
129      * \return A constant reference to the managed \c queue_type object.
130      */
message_queue() const131     queue_type const& message_queue() const BOOST_NOEXCEPT { return m_queue; }
132 
133     /*!
134      * Tests whether the object is associated with any message queue. Only when the backend has
135      * an associated message queue, will any message be sent.
136      *
137      * \return \c true if the object is associated with a message queue, and \c false otherwise.
138      */
is_open() const139     bool is_open() const BOOST_NOEXCEPT { return m_queue.is_open(); }
140 
141     /*!
142      * The method writes the message to the backend. Concurrent calls to this method
143      * are allowed. Therefore, the backend may be used with unlocked frontend. <tt>stop_local()</tt>
144      * can be used to have a blocked <tt>consume()</tt> call return and prevent future
145      * calls to <tt>consume()</tt> from blocking.
146      */
consume(record_view const &,string_type const & formatted_message)147     void consume(record_view const&, string_type const& formatted_message)
148     {
149         if (m_queue.is_open())
150         {
151             typedef typename queue_type::size_type size_type;
152             const string_type::size_type size = formatted_message.size();
153             if (BOOST_UNLIKELY(size > static_cast< string_type::size_type >((std::numeric_limits< size_type >::max)())))
154                 BOOST_LOG_THROW_DESCR(limitation_error, "Message too long to send to an interprocess queue");
155             m_queue.send(formatted_message.data(), static_cast< size_type >(size));
156         }
157     }
158 };
159 
160 #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1
161 #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N
162 #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL
163 
164 } // namespace sinks
165 
166 BOOST_LOG_CLOSE_NAMESPACE // namespace log
167 
168 } // namespace boost
169 
170 #include <boost/log/detail/footer.hpp>
171 
172 #endif // BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_
173