/* * Copyright Lingxi Li 2015. * Copyright Andrey Semashev 2016. * 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) */ /*! * \file text_ipc_message_queue_backend.hpp * \author Lingxi Li * \author Andrey Semashev * \date 14.10.2015 * * The header contains implementation of a text interprocess message queue sink * backend along with implementation of a supporting interprocess message queue. */ #ifndef BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once #endif namespace boost { BOOST_LOG_OPEN_NAMESPACE namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1(n, data)\ template< typename T0 >\ 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()) :\ m_queue(arg0) {} #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N(n, data)\ template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ explicit text_ipc_message_queue_backend(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ m_queue(BOOST_PP_ENUM_PARAMS(n, arg)) {} #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL(z, n, data)\ 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) #endif // BOOST_LOG_DOXYGEN_PASS /*! * \brief An implementation of a text interprocess message queue sink backend and * a supporting interprocess message queue. * * The sink backend sends formatted log messages to an interprocess message queue * which can be extracted by a viewer process. Methods of this class are not * thread-safe, unless otherwise specified. */ template< typename QueueT > class text_ipc_message_queue_backend : public basic_formatted_sink_backend< char, concurrent_feeding > { //! Base type typedef basic_formatted_sink_backend< char, concurrent_feeding > base_type; public: //! Character type typedef base_type::char_type char_type; //! String type to be used as a message text holder typedef base_type::string_type string_type; //! Interprocess message queue type typedef QueueT queue_type; private: //! Interprocess queue queue_type m_queue; public: /*! * Default constructor. The method constructs the backend using the default-constructed * interprocess message queue. The queue may need additional setup in order to be able * to send messages. */ text_ipc_message_queue_backend() BOOST_NOEXCEPT { } /*! * Initializing constructor. The method constructs the backend using the provided * interprocess message queue. The constructor moves from the provided queue. */ explicit text_ipc_message_queue_backend(BOOST_RV_REF(queue_type) queue) BOOST_NOEXCEPT : m_queue(static_cast< BOOST_RV_REF(queue_type) >(queue)) { } /*! * Constructor that passes arbitrary named parameters to the interprocess queue constructor. * Refer to the queue documentation for the list of supported parameters. */ #ifndef BOOST_LOG_DOXYGEN_PASS BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL, ~) #else template< typename... Args > explicit text_ipc_message_queue_backend(Args&&... args); #endif /*! * The method returns a reference to the managed \c queue_type object. * * \return A reference to the managed \c queue_type object. */ queue_type& message_queue() BOOST_NOEXCEPT { return m_queue; } /*! * The method returns a constant reference to the managed \c queue_type object. * * \return A constant reference to the managed \c queue_type object. */ queue_type const& message_queue() const BOOST_NOEXCEPT { return m_queue; } /*! * Tests whether the object is associated with any message queue. Only when the backend has * an associated message queue, will any message be sent. * * \return \c true if the object is associated with a message queue, and \c false otherwise. */ bool is_open() const BOOST_NOEXCEPT { return m_queue.is_open(); } /*! * The method writes the message to the backend. Concurrent calls to this method * are allowed. Therefore, the backend may be used with unlocked frontend. stop_local() * can be used to have a blocked consume() call return and prevent future * calls to consume() from blocking. */ void consume(record_view const&, string_type const& formatted_message) { if (m_queue.is_open()) { typedef typename queue_type::size_type size_type; const string_type::size_type size = formatted_message.size(); if (BOOST_UNLIKELY(size > static_cast< string_type::size_type >((std::numeric_limits< size_type >::max)()))) BOOST_LOG_THROW_DESCR(limitation_error, "Message too long to send to an interprocess queue"); m_queue.send(formatted_message.data(), static_cast< size_type >(size)); } } }; #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1 #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N #undef BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL } // namespace sinks BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost #include #endif // BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_