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