stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork
This commit is contained in:
@@ -0,0 +1,514 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 async_frontend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 14.07.2009
|
||||
*
|
||||
* The header contains implementation of asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_
|
||||
|
||||
#include <exception> // std::terminate
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: Asynchronous sink frontend is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/atomic.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared_object.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/comparison/equal.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
#include <boost/log/detail/locking_ptr.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/sinks/basic_sink_frontend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/sinks/unbounded_fifo_queue.hpp>
|
||||
#include <boost/log/keywords/start_thread.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\
|
||||
template< typename T0 >\
|
||||
explicit asynchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\
|
||||
base_type(true),\
|
||||
queue_base_type(arg0),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(arg0)),\
|
||||
m_StopRequested(false),\
|
||||
m_FlushRequested(false)\
|
||||
{\
|
||||
if (arg0[keywords::start_thread | true])\
|
||||
start_feeding_thread();\
|
||||
}\
|
||||
template< typename T0 >\
|
||||
explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, T0 const& arg0) :\
|
||||
base_type(true),\
|
||||
queue_base_type(arg0),\
|
||||
m_pBackend(backend),\
|
||||
m_StopRequested(false),\
|
||||
m_FlushRequested(false)\
|
||||
{\
|
||||
if (arg0[keywords::start_thread | true])\
|
||||
start_feeding_thread();\
|
||||
}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\
|
||||
template< BOOST_PP_ENUM_PARAMS(n, typename T) >\
|
||||
explicit asynchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\
|
||||
base_type(true),\
|
||||
queue_base_type((BOOST_PP_ENUM_PARAMS(n, arg))),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))),\
|
||||
m_StopRequested(false),\
|
||||
m_FlushRequested(false)\
|
||||
{\
|
||||
if ((BOOST_PP_ENUM_PARAMS(n, arg))[keywords::start_thread | true])\
|
||||
start_feeding_thread();\
|
||||
}\
|
||||
template< BOOST_PP_ENUM_PARAMS(n, typename T) >\
|
||||
explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\
|
||||
base_type(true),\
|
||||
queue_base_type((BOOST_PP_ENUM_PARAMS(n, arg))),\
|
||||
m_pBackend(backend),\
|
||||
m_StopRequested(false),\
|
||||
m_FlushRequested(false)\
|
||||
{\
|
||||
if ((BOOST_PP_ENUM_PARAMS(n, arg))[keywords::start_thread | true])\
|
||||
start_feeding_thread();\
|
||||
}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\
|
||||
BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data)
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* \brief Asynchronous logging sink frontend
|
||||
*
|
||||
* The frontend starts a separate thread on construction. All logging records are passed
|
||||
* to the backend in this dedicated thread only.
|
||||
*/
|
||||
template< typename SinkBackendT, typename QueueingStrategyT = unbounded_fifo_queue >
|
||||
class asynchronous_sink :
|
||||
public aux::make_sink_frontend_base< SinkBackendT >::type,
|
||||
public QueueingStrategyT
|
||||
{
|
||||
typedef typename aux::make_sink_frontend_base< SinkBackendT >::type base_type;
|
||||
typedef QueueingStrategyT queue_base_type;
|
||||
|
||||
private:
|
||||
//! Backend synchronization mutex type
|
||||
typedef boost::recursive_mutex backend_mutex_type;
|
||||
//! Frontend synchronization mutex type
|
||||
typedef typename base_type::mutex_type frontend_mutex_type;
|
||||
|
||||
//! A scope guard that implements thread ID management
|
||||
class scoped_thread_id
|
||||
{
|
||||
private:
|
||||
frontend_mutex_type& m_Mutex;
|
||||
condition_variable_any& m_Cond;
|
||||
thread::id& m_ThreadID;
|
||||
boost::atomic< bool >& m_StopRequested;
|
||||
|
||||
public:
|
||||
//! Initializing constructor
|
||||
scoped_thread_id(frontend_mutex_type& mut, condition_variable_any& cond, thread::id& tid, boost::atomic< bool >& sr)
|
||||
: m_Mutex(mut), m_Cond(cond), m_ThreadID(tid), m_StopRequested(sr)
|
||||
{
|
||||
lock_guard< frontend_mutex_type > lock(m_Mutex);
|
||||
if (m_ThreadID != thread::id())
|
||||
BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread");
|
||||
m_ThreadID = this_thread::get_id();
|
||||
}
|
||||
//! Initializing constructor
|
||||
scoped_thread_id(unique_lock< frontend_mutex_type >& l, condition_variable_any& cond, thread::id& tid, boost::atomic< bool >& sr)
|
||||
: m_Mutex(*l.mutex()), m_Cond(cond), m_ThreadID(tid), m_StopRequested(sr)
|
||||
{
|
||||
unique_lock< frontend_mutex_type > lock(move(l));
|
||||
if (m_ThreadID != thread::id())
|
||||
BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread");
|
||||
m_ThreadID = this_thread::get_id();
|
||||
}
|
||||
//! Destructor
|
||||
~scoped_thread_id()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock_guard< frontend_mutex_type > lock(m_Mutex);
|
||||
m_StopRequested.store(false, boost::memory_order_release);
|
||||
m_ThreadID = thread::id();
|
||||
m_Cond.notify_all();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DELETED_FUNCTION(scoped_thread_id(scoped_thread_id const&))
|
||||
BOOST_DELETED_FUNCTION(scoped_thread_id& operator= (scoped_thread_id const&))
|
||||
};
|
||||
|
||||
//! A scope guard that resets a flag on destructor
|
||||
class scoped_flag
|
||||
{
|
||||
private:
|
||||
frontend_mutex_type& m_Mutex;
|
||||
condition_variable_any& m_Cond;
|
||||
boost::atomic< bool >& m_Flag;
|
||||
|
||||
public:
|
||||
explicit scoped_flag(frontend_mutex_type& mut, condition_variable_any& cond, boost::atomic< bool >& f) :
|
||||
m_Mutex(mut), m_Cond(cond), m_Flag(f)
|
||||
{
|
||||
}
|
||||
~scoped_flag()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock_guard< frontend_mutex_type > lock(m_Mutex);
|
||||
m_Flag.store(false, boost::memory_order_release);
|
||||
m_Cond.notify_all();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_DELETED_FUNCTION(scoped_flag(scoped_flag const&))
|
||||
BOOST_DELETED_FUNCTION(scoped_flag& operator= (scoped_flag const&))
|
||||
};
|
||||
|
||||
public:
|
||||
//! Sink implementation type
|
||||
typedef SinkBackendT sink_backend_type;
|
||||
//! \cond
|
||||
BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value), "Asynchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met");
|
||||
//! \endcond
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
//! A pointer type that locks the backend until it's destroyed
|
||||
typedef boost::log::aux::locking_ptr< sink_backend_type, backend_mutex_type > locked_backend_ptr;
|
||||
|
||||
#else // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
//! A pointer type that locks the backend until it's destroyed
|
||||
typedef implementation_defined locked_backend_ptr;
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
private:
|
||||
//! Synchronization mutex
|
||||
backend_mutex_type m_BackendMutex;
|
||||
//! Pointer to the backend
|
||||
const shared_ptr< sink_backend_type > m_pBackend;
|
||||
|
||||
//! Dedicated record feeding thread
|
||||
thread m_DedicatedFeedingThread;
|
||||
//! Feeding thread ID
|
||||
thread::id m_FeedingThreadID;
|
||||
//! Condition variable to implement blocking operations
|
||||
condition_variable_any m_BlockCond;
|
||||
|
||||
//! The flag indicates that the feeding loop has to be stopped
|
||||
boost::atomic< bool > m_StopRequested;
|
||||
//! The flag indicates that queue flush has been requested
|
||||
boost::atomic< bool > m_FlushRequested;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. Constructs the sink backend instance.
|
||||
* Requires the backend to be default-constructible.
|
||||
*
|
||||
* \param start_thread If \c true, the frontend creates a thread to feed
|
||||
* log records to the backend. Otherwise no thread is
|
||||
* started and it is assumed that the user will call
|
||||
* either \c run or \c feed_records himself.
|
||||
*/
|
||||
asynchronous_sink(bool start_thread = true) :
|
||||
base_type(true),
|
||||
m_pBackend(boost::make_shared< sink_backend_type >()),
|
||||
m_StopRequested(false),
|
||||
m_FlushRequested(false)
|
||||
{
|
||||
if (start_thread)
|
||||
start_feeding_thread();
|
||||
}
|
||||
/*!
|
||||
* Constructor attaches user-constructed backend instance
|
||||
*
|
||||
* \param backend Pointer to the backend instance.
|
||||
* \param start_thread If \c true, the frontend creates a thread to feed
|
||||
* log records to the backend. Otherwise no thread is
|
||||
* started and it is assumed that the user will call
|
||||
* either \c run or \c feed_records himself.
|
||||
*
|
||||
* \pre \a backend is not \c NULL.
|
||||
*/
|
||||
explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, bool start_thread = true) :
|
||||
base_type(true),
|
||||
m_pBackend(backend),
|
||||
m_StopRequested(false),
|
||||
m_FlushRequested(false)
|
||||
{
|
||||
if (start_thread)
|
||||
start_feeding_thread();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructor that passes arbitrary named parameters to the interprocess sink backend constructor.
|
||||
* Refer to the backend documentation for the list of supported parameters.
|
||||
*
|
||||
* The frontend uses the following named parameters:
|
||||
*
|
||||
* \li start_thread - If \c true, the frontend creates a thread to feed
|
||||
* log records to the backend. Otherwise no thread is
|
||||
* started and it is assumed that the user will call
|
||||
* either \c run or \c feed_records himself.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~)
|
||||
#else
|
||||
template< typename... Args >
|
||||
explicit asynchronous_sink(Args&&... args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Destructor. Implicitly stops the dedicated feeding thread, if one is running.
|
||||
*/
|
||||
~asynchronous_sink() BOOST_NOEXCEPT
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::this_thread::disable_interruption no_interrupts;
|
||||
stop();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Locking accessor to the attached backend
|
||||
*/
|
||||
locked_backend_ptr locked_backend()
|
||||
{
|
||||
return locked_backend_ptr(m_pBackend, m_BackendMutex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Enqueues the log record to the backend
|
||||
*/
|
||||
void consume(record_view const& rec)
|
||||
{
|
||||
if (BOOST_UNLIKELY(m_FlushRequested.load(boost::memory_order_acquire)))
|
||||
{
|
||||
unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex());
|
||||
// Wait until flush is done
|
||||
while (m_FlushRequested.load(boost::memory_order_acquire))
|
||||
m_BlockCond.wait(lock);
|
||||
}
|
||||
queue_base_type::enqueue(rec);
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method attempts to pass logging record to the backend
|
||||
*/
|
||||
bool try_consume(record_view const& rec)
|
||||
{
|
||||
if (!m_FlushRequested.load(boost::memory_order_acquire))
|
||||
{
|
||||
return queue_base_type::try_enqueue(rec);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method starts record feeding loop and effectively blocks until either of this happens:
|
||||
*
|
||||
* \li the thread is interrupted due to either standard thread interruption or a call to \c stop
|
||||
* \li an exception is thrown while processing a log record in the backend, and the exception is
|
||||
* not terminated by the exception handler, if one is installed
|
||||
*
|
||||
* \pre The sink frontend must be constructed without spawning a dedicated thread
|
||||
*/
|
||||
void run()
|
||||
{
|
||||
// First check that no other thread is running
|
||||
scoped_thread_id guard(base_type::frontend_mutex(), m_BlockCond, m_FeedingThreadID, m_StopRequested);
|
||||
|
||||
// Now start the feeding loop
|
||||
while (true)
|
||||
{
|
||||
do_feed_records();
|
||||
if (!m_StopRequested.load(boost::memory_order_acquire))
|
||||
{
|
||||
// Block until new record is available
|
||||
record_view rec;
|
||||
if (queue_base_type::dequeue_ready(rec))
|
||||
base_type::feed_record(rec, m_BackendMutex, *m_pBackend);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method softly interrupts record feeding loop. This method must be called when the \c run
|
||||
* method execution has to be interrupted. Unlike regular thread interruption, calling
|
||||
* \c stop will not interrupt the record processing in the middle. Instead, the sink frontend
|
||||
* will attempt to finish its business with the record in progress and return afterwards.
|
||||
* This method can be called either if the sink was created with a dedicated thread,
|
||||
* or if the feeding loop was initiated by user.
|
||||
*
|
||||
* \note Returning from this method does not guarantee that there are no records left buffered
|
||||
* in the sink frontend. It is possible that log records keep coming during and after this
|
||||
* method is called. At some point of execution of this method log records stop being processed,
|
||||
* and all records that come after this point are put into the queue. These records will be
|
||||
* processed upon further calls to \c run or \c feed_records.
|
||||
*/
|
||||
void stop()
|
||||
{
|
||||
unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex());
|
||||
if (m_FeedingThreadID != thread::id() || m_DedicatedFeedingThread.joinable())
|
||||
{
|
||||
try
|
||||
{
|
||||
m_StopRequested.store(true, boost::memory_order_release);
|
||||
queue_base_type::interrupt_dequeue();
|
||||
while (m_StopRequested.load(boost::memory_order_acquire))
|
||||
m_BlockCond.wait(lock);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
m_StopRequested.store(false, boost::memory_order_release);
|
||||
throw;
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
m_DedicatedFeedingThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method feeds log records that may have been buffered to the backend and returns
|
||||
*
|
||||
* \pre The sink frontend must be constructed without spawning a dedicated thread
|
||||
*/
|
||||
void feed_records()
|
||||
{
|
||||
// First check that no other thread is running
|
||||
scoped_thread_id guard(base_type::frontend_mutex(), m_BlockCond, m_FeedingThreadID, m_StopRequested);
|
||||
|
||||
// Now start the feeding loop
|
||||
do_feed_records();
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method feeds all log records that may have been buffered to the backend and returns.
|
||||
* Unlike \c feed_records, in case of ordering queueing the method also feeds records
|
||||
* that were enqueued during the ordering window, attempting to empty the queue completely.
|
||||
*/
|
||||
void flush()
|
||||
{
|
||||
unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex());
|
||||
if (m_FeedingThreadID != thread::id() || m_DedicatedFeedingThread.joinable())
|
||||
{
|
||||
// There is already a thread feeding records, let it do the job
|
||||
m_FlushRequested.store(true, boost::memory_order_release);
|
||||
queue_base_type::interrupt_dequeue();
|
||||
while (!m_StopRequested.load(boost::memory_order_acquire) && m_FlushRequested.load(boost::memory_order_acquire))
|
||||
m_BlockCond.wait(lock);
|
||||
|
||||
// The condition may have been signalled when the feeding thread was finishing.
|
||||
// In that case records may not have been flushed, and we do the flush ourselves.
|
||||
if (m_FeedingThreadID != thread::id())
|
||||
return;
|
||||
}
|
||||
|
||||
m_FlushRequested.store(true, boost::memory_order_release);
|
||||
|
||||
// Flush records ourselves. The guard releases the lock.
|
||||
scoped_thread_id guard(lock, m_BlockCond, m_FeedingThreadID, m_StopRequested);
|
||||
|
||||
do_feed_records();
|
||||
}
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! The method spawns record feeding thread
|
||||
void start_feeding_thread()
|
||||
{
|
||||
boost::thread(boost::bind(&asynchronous_sink::run, this)).swap(m_DedicatedFeedingThread);
|
||||
}
|
||||
|
||||
//! The record feeding loop
|
||||
void do_feed_records()
|
||||
{
|
||||
while (!m_StopRequested.load(boost::memory_order_acquire))
|
||||
{
|
||||
record_view rec;
|
||||
bool dequeued = false;
|
||||
if (BOOST_LIKELY(!m_FlushRequested.load(boost::memory_order_acquire)))
|
||||
dequeued = queue_base_type::try_dequeue_ready(rec);
|
||||
else
|
||||
dequeued = queue_base_type::try_dequeue(rec);
|
||||
|
||||
if (dequeued)
|
||||
base_type::feed_record(rec, m_BackendMutex, *m_pBackend);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (BOOST_UNLIKELY(m_FlushRequested.load(boost::memory_order_acquire)))
|
||||
{
|
||||
scoped_flag guard(base_type::frontend_mutex(), m_BlockCond, m_FlushRequested);
|
||||
base_type::flush_backend(m_BackendMutex, *m_pBackend);
|
||||
}
|
||||
}
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,290 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 attribute_mapping.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 07.11.2008
|
||||
*
|
||||
* The header contains facilities that are used in different sinks to map attribute values
|
||||
* used throughout the application to values used with the specific native logging API.
|
||||
* These tools are mostly needed to map application severity levels on native levels,
|
||||
* required by OS-specific sink backends.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_ATTRIBUTE_MAPPING_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_ATTRIBUTE_MAPPING_HPP_INCLUDED_
|
||||
|
||||
#include <map>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/tagged_integer.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/attributes/attribute_name.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/attributes/value_visitation.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
//! Base class for attribute mapping function objects
|
||||
template< typename MappedT >
|
||||
struct basic_mapping
|
||||
{
|
||||
//! Mapped value type
|
||||
typedef MappedT mapped_type;
|
||||
//! Result type
|
||||
typedef mapped_type result_type;
|
||||
};
|
||||
|
||||
namespace aux {
|
||||
|
||||
//! Attribute value visitor
|
||||
template< typename MappedT >
|
||||
struct direct_mapping_visitor
|
||||
{
|
||||
typedef void result_type;
|
||||
typedef MappedT mapped_type;
|
||||
|
||||
explicit direct_mapping_visitor(mapped_type& extracted) :
|
||||
m_Extracted(extracted)
|
||||
{
|
||||
}
|
||||
template< typename T >
|
||||
void operator() (T const& val) const
|
||||
{
|
||||
m_Extracted = mapped_type(val);
|
||||
}
|
||||
|
||||
private:
|
||||
mapped_type& m_Extracted;
|
||||
};
|
||||
// Specialization for the tagged integer
|
||||
template< typename IntT, typename TagT >
|
||||
struct direct_mapping_visitor< boost::log::aux::tagged_integer< IntT, TagT > >
|
||||
{
|
||||
typedef void result_type;
|
||||
typedef boost::log::aux::tagged_integer< IntT, TagT > mapped_type;
|
||||
|
||||
explicit direct_mapping_visitor(mapped_type& extracted) :
|
||||
m_Extracted(extracted)
|
||||
{
|
||||
}
|
||||
template< typename T >
|
||||
void operator() (T const& val) const
|
||||
{
|
||||
mapped_type v = { static_cast< IntT >(val) };
|
||||
m_Extracted = v;
|
||||
}
|
||||
|
||||
private:
|
||||
mapped_type& m_Extracted;
|
||||
};
|
||||
|
||||
} // namespace aux
|
||||
|
||||
/*!
|
||||
* \brief Straightforward mapping
|
||||
*
|
||||
* This type of mapping assumes that attribute with a particular name always
|
||||
* provides values that map directly onto the native values. The mapping
|
||||
* simply returns the extracted attribute value converted to the native value.
|
||||
*/
|
||||
template< typename MappedT, typename AttributeValueT = int >
|
||||
class basic_direct_mapping :
|
||||
public basic_mapping< MappedT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_direct_mapping< MappedT > base_type;
|
||||
|
||||
public:
|
||||
//! Attribute contained value type
|
||||
typedef AttributeValueT attribute_value_type;
|
||||
//! Mapped value type
|
||||
typedef typename base_type::mapped_type mapped_type;
|
||||
|
||||
private:
|
||||
//! Attribute name
|
||||
const attribute_name m_Name;
|
||||
//! Visitor invoker for the attribute value
|
||||
value_visitor_invoker< attribute_value_type > m_Invoker;
|
||||
//! Default native value
|
||||
mapped_type m_DefaultValue;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
* \param default_value The default native value that is returned if the attribute value is not found
|
||||
*/
|
||||
explicit basic_direct_mapping(attribute_name const& name, mapped_type const& default_value) :
|
||||
m_Name(name),
|
||||
m_DefaultValue(default_value)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Extraction operator
|
||||
*
|
||||
* \param rec A log record to extract value from
|
||||
* \return An extracted attribute value
|
||||
*/
|
||||
mapped_type operator() (record_view const& rec) const
|
||||
{
|
||||
mapped_type res = m_DefaultValue;
|
||||
aux::direct_mapping_visitor< mapped_type > vis(res);
|
||||
m_Invoker(m_Name, rec.attribute_values(), vis);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Customizable mapping
|
||||
*
|
||||
* The class allows to setup a custom mapping between an attribute and native values.
|
||||
* The mapping should be initialized similarly to the standard \c map container, by using
|
||||
* indexing operator and assignment.
|
||||
*
|
||||
* \note Unlike many other components of the library, exact type of the attribute value
|
||||
* must be specified in the template parameter \c AttributeValueT. Type sequences
|
||||
* are not supported.
|
||||
*/
|
||||
template< typename MappedT, typename AttributeValueT = int >
|
||||
class basic_custom_mapping :
|
||||
public basic_mapping< MappedT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_mapping< MappedT > base_type;
|
||||
|
||||
public:
|
||||
//! Attribute contained value type
|
||||
typedef AttributeValueT attribute_value_type;
|
||||
//! Mapped value type
|
||||
typedef typename base_type::mapped_type mapped_type;
|
||||
|
||||
private:
|
||||
//! \cond
|
||||
|
||||
//! Mapping type
|
||||
typedef std::map< attribute_value_type, mapped_type > mapping_type;
|
||||
//! Smart reference class for implementing insertion into the map
|
||||
class reference_proxy;
|
||||
friend class reference_proxy;
|
||||
class reference_proxy
|
||||
{
|
||||
mapping_type& m_Mapping;
|
||||
attribute_value_type m_Key;
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
reference_proxy(mapping_type& mapping, attribute_value_type const& key) : m_Mapping(mapping), m_Key(key) {}
|
||||
//! Insertion
|
||||
reference_proxy const& operator= (mapped_type const& val) const
|
||||
{
|
||||
m_Mapping[m_Key] = val;
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//! Attribute value visitor
|
||||
struct visitor;
|
||||
friend struct visitor;
|
||||
struct visitor
|
||||
{
|
||||
typedef void result_type;
|
||||
|
||||
visitor(mapping_type const& mapping, mapped_type& extracted) :
|
||||
m_Mapping(mapping),
|
||||
m_Extracted(extracted)
|
||||
{
|
||||
}
|
||||
template< typename T >
|
||||
void operator() (T const& val) const
|
||||
{
|
||||
typename mapping_type::const_iterator it = m_Mapping.find(val);
|
||||
if (it != m_Mapping.end())
|
||||
m_Extracted = it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
mapping_type const& m_Mapping;
|
||||
mapped_type& m_Extracted;
|
||||
};
|
||||
|
||||
//! \endcond
|
||||
|
||||
private:
|
||||
//! Attribute name
|
||||
const attribute_name m_Name;
|
||||
//! Visitor invoker for the attribute value
|
||||
value_visitor_invoker< attribute_value_type > m_Invoker;
|
||||
//! Default native value
|
||||
mapped_type m_DefaultValue;
|
||||
//! Conversion mapping
|
||||
mapping_type m_Mapping;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
* \param default_value The default native value that is returned if the conversion cannot be performed
|
||||
*/
|
||||
explicit basic_custom_mapping(attribute_name const& name, mapped_type const& default_value) :
|
||||
m_Name(name),
|
||||
m_DefaultValue(default_value)
|
||||
{
|
||||
}
|
||||
/*!
|
||||
* Extraction operator. Extracts the attribute value and attempts to map it onto
|
||||
* the native value.
|
||||
*
|
||||
* \param rec A log record to extract value from
|
||||
* \return A mapped value, if mapping was successful, or the default value if
|
||||
* mapping did not succeed.
|
||||
*/
|
||||
mapped_type operator() (record_view const& rec) const
|
||||
{
|
||||
mapped_type res = m_DefaultValue;
|
||||
visitor vis(m_Mapping, res);
|
||||
m_Invoker(m_Name, rec.attribute_values(), vis);
|
||||
return res;
|
||||
}
|
||||
/*!
|
||||
* Insertion operator
|
||||
*
|
||||
* \param key Attribute value to be mapped
|
||||
* \return An object of unspecified type that allows to insert a new mapping through assignment.
|
||||
* The \a key argument becomes the key attribute value, and the assigned value becomes the
|
||||
* mapped native value.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
reference_proxy operator[] (attribute_value_type const& key)
|
||||
#else
|
||||
implementation_defined operator[] (attribute_value_type const& key)
|
||||
#endif
|
||||
{
|
||||
return reference_proxy(m_Mapping, key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_ATTRIBUTE_MAPPING_HPP_INCLUDED_
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 basic_sink_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 04.11.2007
|
||||
*
|
||||
* The header contains implementation of base classes for sink backends.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_BASIC_SINK_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_BASIC_SINK_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Base class for a logging sink backend
|
||||
*
|
||||
* The \c basic_sink_backend class template defines a number of types that
|
||||
* all sink backends are required to define. All sink backends have to derive from the class.
|
||||
*/
|
||||
template< typename FrontendRequirementsT >
|
||||
struct basic_sink_backend
|
||||
{
|
||||
//! Frontend requirements tag
|
||||
typedef FrontendRequirementsT frontend_requirements;
|
||||
|
||||
BOOST_DEFAULTED_FUNCTION(basic_sink_backend(), {})
|
||||
|
||||
BOOST_DELETED_FUNCTION(basic_sink_backend(basic_sink_backend const&))
|
||||
BOOST_DELETED_FUNCTION(basic_sink_backend& operator= (basic_sink_backend const&))
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief A base class for a logging sink backend with message formatting support
|
||||
*
|
||||
* The \c basic_formatted_sink_backend class template indicates to the frontend that
|
||||
* the backend requires logging record formatting.
|
||||
*
|
||||
* The class allows to request encoding conversion in case if the sink backend
|
||||
* requires the formatted string in some particular encoding (e.g. if underlying API
|
||||
* supports only narrow or wide characters). In order to perform conversion one
|
||||
* should specify the desired final character type in the \c TargetCharT template
|
||||
* parameter.
|
||||
*/
|
||||
template<
|
||||
typename CharT,
|
||||
typename FrontendRequirementsT = synchronized_feeding
|
||||
>
|
||||
struct basic_formatted_sink_backend :
|
||||
public basic_sink_backend<
|
||||
typename combine_requirements< FrontendRequirementsT, formatted_records >::type
|
||||
>
|
||||
{
|
||||
private:
|
||||
typedef basic_sink_backend<
|
||||
typename combine_requirements< FrontendRequirementsT, formatted_records >::type
|
||||
> base_type;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef CharT char_type;
|
||||
//! Formatted string type
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
//! Frontend requirements
|
||||
typedef typename base_type::frontend_requirements frontend_requirements;
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_BASIC_SINK_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 basic_sink_frontend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 14.07.2009
|
||||
*
|
||||
* The header contains implementation of a base class for sink frontends.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
|
||||
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/code_conversion.hpp>
|
||||
#include <boost/log/detail/attachable_sstream_buf.hpp>
|
||||
#include <boost/log/detail/fake_mutex.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/sinks/sink.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/expressions/filter.hpp>
|
||||
#include <boost/log/expressions/formatter.hpp>
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/log/detail/locks.hpp>
|
||||
#include <boost/log/detail/light_rw_mutex.hpp>
|
||||
#endif // !defined(BOOST_LOG_NO_THREADS)
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
//! A base class for a logging sink frontend
|
||||
class BOOST_LOG_NO_VTABLE basic_sink_frontend :
|
||||
public sink
|
||||
{
|
||||
//! Base type
|
||||
typedef sink base_type;
|
||||
|
||||
public:
|
||||
//! An exception handler type
|
||||
typedef base_type::exception_handler_type exception_handler_type;
|
||||
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
protected:
|
||||
//! Mutex type
|
||||
typedef boost::log::aux::light_rw_mutex mutex_type;
|
||||
|
||||
private:
|
||||
//! Synchronization mutex
|
||||
mutable mutex_type m_Mutex;
|
||||
#endif
|
||||
|
||||
private:
|
||||
//! Filter
|
||||
filter m_Filter;
|
||||
//! Exception handler
|
||||
exception_handler_type m_ExceptionHandler;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Initializing constructor
|
||||
*
|
||||
* \param cross_thread The flag indicates whether the sink passes log records between different threads
|
||||
*/
|
||||
explicit basic_sink_frontend(bool cross_thread) : sink(cross_thread)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method sets sink-specific filter functional object
|
||||
*/
|
||||
template< typename FunT >
|
||||
void set_filter(FunT const& filter)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
m_Filter = filter;
|
||||
}
|
||||
/*!
|
||||
* The method resets the filter
|
||||
*/
|
||||
void reset_filter()
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
m_Filter.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method sets an exception handler function
|
||||
*/
|
||||
template< typename FunT >
|
||||
void set_exception_handler(FunT const& handler)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
m_ExceptionHandler = handler;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method resets the exception handler function
|
||||
*/
|
||||
void reset_exception_handler()
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
m_ExceptionHandler.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method returns \c true if no filter is set or the attribute values pass the filter
|
||||
*
|
||||
* \param attrs A set of attribute values of a logging record
|
||||
*/
|
||||
bool will_consume(attribute_value_set const& attrs)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
try
|
||||
{
|
||||
return m_Filter(attrs);
|
||||
}
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
catch (...)
|
||||
{
|
||||
if (m_ExceptionHandler.empty())
|
||||
throw;
|
||||
m_ExceptionHandler();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
//! Returns reference to the frontend mutex
|
||||
mutex_type& frontend_mutex() const { return m_Mutex; }
|
||||
#endif
|
||||
|
||||
//! Returns reference to the exception handler
|
||||
exception_handler_type& exception_handler() { return m_ExceptionHandler; }
|
||||
//! Returns reference to the exception handler
|
||||
exception_handler_type const& exception_handler() const { return m_ExceptionHandler; }
|
||||
|
||||
//! Feeds log record to the backend
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
|
||||
{
|
||||
try
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
|
||||
backend.consume(rec);
|
||||
}
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
catch (...)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
if (m_ExceptionHandler.empty())
|
||||
throw;
|
||||
m_ExceptionHandler();
|
||||
}
|
||||
}
|
||||
|
||||
//! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
try
|
||||
{
|
||||
if (!backend_mutex.try_lock())
|
||||
return false;
|
||||
}
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
|
||||
if (this->exception_handler().empty())
|
||||
throw;
|
||||
this->exception_handler()();
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
|
||||
#endif
|
||||
// No need to lock anything in the feed_record method
|
||||
boost::log::aux::fake_mutex m;
|
||||
feed_record(rec, m, backend);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Flushes record buffers in the backend, if one supports it
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
void flush_backend(BackendMutexT& backend_mutex, BackendT& backend)
|
||||
{
|
||||
typedef typename BackendT::frontend_requirements frontend_requirements;
|
||||
flush_backend_impl(backend_mutex, backend,
|
||||
typename has_requirement< frontend_requirements, flushing >::type());
|
||||
}
|
||||
|
||||
private:
|
||||
//! Flushes record buffers in the backend (the actual implementation)
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, mpl::true_)
|
||||
{
|
||||
try
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
|
||||
backend.flush();
|
||||
}
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
catch (...)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
|
||||
if (m_ExceptionHandler.empty())
|
||||
throw;
|
||||
m_ExceptionHandler();
|
||||
}
|
||||
}
|
||||
//! Flushes record buffers in the backend (stub for backends that don't support flushing)
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
void flush_backend_impl(BackendMutexT&, BackendT&, mpl::false_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//! A base class for a logging sink frontend with formatting support
|
||||
template< typename CharT >
|
||||
class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend :
|
||||
public basic_sink_frontend
|
||||
{
|
||||
typedef basic_sink_frontend base_type;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef CharT char_type;
|
||||
//! Formatted string type
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
|
||||
//! Formatter function object type
|
||||
typedef basic_formatter< char_type > formatter_type;
|
||||
//! Output stream type
|
||||
typedef typename formatter_type::stream_type stream_type;
|
||||
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
protected:
|
||||
//! Mutex type
|
||||
typedef typename base_type::mutex_type mutex_type;
|
||||
#endif
|
||||
|
||||
private:
|
||||
struct formatting_context
|
||||
{
|
||||
class cleanup_guard
|
||||
{
|
||||
private:
|
||||
formatting_context& m_context;
|
||||
|
||||
public:
|
||||
explicit cleanup_guard(formatting_context& ctx) BOOST_NOEXCEPT : m_context(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
~cleanup_guard()
|
||||
{
|
||||
m_context.m_FormattedRecord.clear();
|
||||
m_context.m_FormattingStream.rdbuf()->max_size(m_context.m_FormattedRecord.max_size());
|
||||
m_context.m_FormattingStream.rdbuf()->storage_overflow(false);
|
||||
m_context.m_FormattingStream.clear();
|
||||
}
|
||||
|
||||
BOOST_DELETED_FUNCTION(cleanup_guard(cleanup_guard const&))
|
||||
BOOST_DELETED_FUNCTION(cleanup_guard& operator=(cleanup_guard const&))
|
||||
};
|
||||
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
//! Object version
|
||||
const unsigned int m_Version;
|
||||
#endif
|
||||
//! Formatted log record storage
|
||||
string_type m_FormattedRecord;
|
||||
//! Formatting stream
|
||||
stream_type m_FormattingStream;
|
||||
//! Formatter functor
|
||||
formatter_type m_Formatter;
|
||||
|
||||
formatting_context() :
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
m_Version(0),
|
||||
#endif
|
||||
m_FormattingStream(m_FormattedRecord)
|
||||
{
|
||||
m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
}
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
formatting_context(unsigned int version, std::locale const& loc, formatter_type const& formatter) :
|
||||
m_Version(version),
|
||||
m_FormattingStream(m_FormattedRecord),
|
||||
m_Formatter(formatter)
|
||||
{
|
||||
m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
m_FormattingStream.imbue(loc);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
private:
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
|
||||
//! State version
|
||||
volatile unsigned int m_Version;
|
||||
|
||||
//! Formatter functor
|
||||
formatter_type m_Formatter;
|
||||
//! Locale to perform formatting
|
||||
std::locale m_Locale;
|
||||
|
||||
//! Formatting state
|
||||
thread_specific_ptr< formatting_context > m_pContext;
|
||||
|
||||
#else
|
||||
|
||||
//! Formatting state
|
||||
formatting_context m_Context;
|
||||
|
||||
#endif // !defined(BOOST_LOG_NO_THREADS)
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Initializing constructor
|
||||
*
|
||||
* \param cross_thread The flag indicates whether the sink passes log records between different threads
|
||||
*/
|
||||
explicit basic_formatting_sink_frontend(bool cross_thread) :
|
||||
basic_sink_frontend(cross_thread)
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
, m_Version(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method sets sink-specific formatter function object
|
||||
*/
|
||||
template< typename FunT >
|
||||
void set_formatter(FunT const& formatter)
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
|
||||
m_Formatter = formatter;
|
||||
++m_Version;
|
||||
#else
|
||||
m_Context.m_Formatter = formatter;
|
||||
#endif
|
||||
}
|
||||
/*!
|
||||
* The method resets the formatter
|
||||
*/
|
||||
void reset_formatter()
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
|
||||
m_Formatter.reset();
|
||||
++m_Version;
|
||||
#else
|
||||
m_Context.m_Formatter.reset();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method returns the current locale used for formatting
|
||||
*/
|
||||
std::locale getloc() const
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
|
||||
return m_Locale;
|
||||
#else
|
||||
return m_Context.m_FormattingStream.getloc();
|
||||
#endif
|
||||
}
|
||||
/*!
|
||||
* The method sets the locale used for formatting
|
||||
*/
|
||||
void imbue(std::locale const& loc)
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
|
||||
m_Locale = loc;
|
||||
++m_Version;
|
||||
#else
|
||||
m_Context.m_FormattingStream.imbue(loc);
|
||||
#endif
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Returns reference to the formatter
|
||||
formatter_type& formatter()
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
return m_Formatter;
|
||||
#else
|
||||
return m_Context.m_Formatter;
|
||||
#endif
|
||||
}
|
||||
|
||||
//! Feeds log record to the backend
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
|
||||
{
|
||||
formatting_context* context;
|
||||
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
context = m_pContext.get();
|
||||
if (!context || context->m_Version != m_Version)
|
||||
{
|
||||
{
|
||||
boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());
|
||||
context = new formatting_context(m_Version, m_Locale, m_Formatter);
|
||||
}
|
||||
m_pContext.reset(context);
|
||||
}
|
||||
#else
|
||||
context = &m_Context;
|
||||
#endif
|
||||
|
||||
typename formatting_context::cleanup_guard cleanup(*context);
|
||||
|
||||
try
|
||||
{
|
||||
// Perform the formatting
|
||||
context->m_Formatter(rec, context->m_FormattingStream);
|
||||
context->m_FormattingStream.flush();
|
||||
|
||||
// Feed the record
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
|
||||
backend.consume(rec, context->m_FormattedRecord);
|
||||
}
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
catch (...)
|
||||
{
|
||||
BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());)
|
||||
if (this->exception_handler().empty())
|
||||
throw;
|
||||
this->exception_handler()();
|
||||
}
|
||||
}
|
||||
|
||||
//! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
|
||||
template< typename BackendMutexT, typename BackendT >
|
||||
bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
|
||||
{
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
try
|
||||
{
|
||||
if (!backend_mutex.try_lock())
|
||||
return false;
|
||||
}
|
||||
catch (thread_interrupted&)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
|
||||
if (this->exception_handler().empty())
|
||||
throw;
|
||||
this->exception_handler()();
|
||||
return false;
|
||||
}
|
||||
|
||||
boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
|
||||
#endif
|
||||
// No need to lock anything in the feed_record method
|
||||
boost::log::aux::fake_mutex m;
|
||||
feed_record(rec, m, backend);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace aux {
|
||||
|
||||
template<
|
||||
typename BackendT,
|
||||
bool RequiresFormattingV = has_requirement<
|
||||
typename BackendT::frontend_requirements,
|
||||
formatted_records
|
||||
>::value
|
||||
>
|
||||
struct make_sink_frontend_base
|
||||
{
|
||||
typedef basic_sink_frontend type;
|
||||
};
|
||||
template< typename BackendT >
|
||||
struct make_sink_frontend_base< BackendT, true >
|
||||
{
|
||||
typedef basic_formatting_sink_frontend< typename BackendT::char_type > type;
|
||||
};
|
||||
|
||||
} // namespace aux
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 block_on_overflow.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 04.01.2012
|
||||
*
|
||||
* The header contains implementation of \c block_on_overflow strategy for handling
|
||||
* queue overflows in bounded queues for the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: This header content is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <boost/intrusive/options.hpp>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <boost/intrusive/list_hook.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Blocking strategy for handling log record queue overflows
|
||||
*
|
||||
* This strategy will cause enqueueing threads to block when the
|
||||
* log record queue overflows. The blocked threads will be woken as
|
||||
* soon as there appears free space in the queue, in the same order
|
||||
* they attempted to enqueue records.
|
||||
*/
|
||||
class block_on_overflow
|
||||
{
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
private:
|
||||
typedef intrusive::list_base_hook<
|
||||
intrusive::link_mode< intrusive::auto_unlink >
|
||||
> thread_context_hook_t;
|
||||
|
||||
struct thread_context :
|
||||
public thread_context_hook_t
|
||||
{
|
||||
condition_variable cond;
|
||||
bool result;
|
||||
|
||||
thread_context() : result(true) {}
|
||||
};
|
||||
|
||||
typedef intrusive::list<
|
||||
thread_context,
|
||||
intrusive::base_hook< thread_context_hook_t >,
|
||||
intrusive::constant_time_size< false >
|
||||
> thread_contexts;
|
||||
|
||||
private:
|
||||
//! Blocked threads
|
||||
thread_contexts m_thread_contexts;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor.
|
||||
*/
|
||||
BOOST_DEFAULTED_FUNCTION(block_on_overflow(), {})
|
||||
|
||||
/*!
|
||||
* This method is called by the queue when overflow is detected.
|
||||
*
|
||||
* \param lock An internal lock that protects the queue
|
||||
*
|
||||
* \retval true Attempt to enqueue the record again.
|
||||
* \retval false Discard the record.
|
||||
*/
|
||||
template< typename LockT >
|
||||
bool on_overflow(record_view const&, LockT& lock)
|
||||
{
|
||||
thread_context context;
|
||||
m_thread_contexts.push_back(context);
|
||||
do
|
||||
{
|
||||
context.cond.wait(lock);
|
||||
}
|
||||
while (context.is_linked());
|
||||
|
||||
return context.result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by the queue when there appears a free space.
|
||||
* The internal lock protecting the queue is locked when calling this method.
|
||||
*/
|
||||
void on_queue_space_available()
|
||||
{
|
||||
if (!m_thread_contexts.empty())
|
||||
{
|
||||
m_thread_contexts.front().cond.notify_one();
|
||||
m_thread_contexts.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by the queue to interrupt any possible waits in \c on_overflow.
|
||||
* The internal lock protecting the queue is locked when calling this method.
|
||||
*/
|
||||
void interrupt()
|
||||
{
|
||||
while (!m_thread_contexts.empty())
|
||||
{
|
||||
thread_context& context = m_thread_contexts.front();
|
||||
context.result = false;
|
||||
context.cond.notify_one();
|
||||
m_thread_contexts.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
// Copying prohibited
|
||||
BOOST_DELETED_FUNCTION(block_on_overflow(block_on_overflow const&))
|
||||
BOOST_DELETED_FUNCTION(block_on_overflow& operator= (block_on_overflow const&))
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_BLOCK_ON_OVERFLOW_HPP_INCLUDED_
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 bounded_fifo_queue.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 04.01.2012
|
||||
*
|
||||
* The header contains implementation of bounded FIFO queueing strategy for
|
||||
* the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: This header content is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <queue>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Bounded FIFO log record queueing strategy
|
||||
*
|
||||
* The \c bounded_fifo_queue class is intended to be used with
|
||||
* the \c asynchronous_sink frontend as a log record queueing strategy.
|
||||
*
|
||||
* This strategy describes log record queueing logic.
|
||||
* The queue has a limited capacity, upon reaching which the enqueue operation will
|
||||
* invoke the overflow handling strategy specified in the \c OverflowStrategyT
|
||||
* template parameter to handle the situation. The library provides overflow handling
|
||||
* strategies for most common cases: \c drop_on_overflow will silently discard the log record,
|
||||
* and \c block_on_overflow will put the enqueueing thread to wait until there is space
|
||||
* in the queue.
|
||||
*
|
||||
* The log record queue imposes no ordering over the queued
|
||||
* elements aside from the order in which they are enqueued.
|
||||
*/
|
||||
template< std::size_t MaxQueueSizeV, typename OverflowStrategyT >
|
||||
class bounded_fifo_queue :
|
||||
private OverflowStrategyT
|
||||
{
|
||||
private:
|
||||
typedef OverflowStrategyT overflow_strategy;
|
||||
typedef std::queue< record_view > queue_type;
|
||||
typedef boost::mutex mutex_type;
|
||||
|
||||
private:
|
||||
//! Synchronization primitive
|
||||
mutex_type m_mutex;
|
||||
//! Condition to block the consuming thread on
|
||||
condition_variable m_cond;
|
||||
//! Log record queue
|
||||
queue_type m_queue;
|
||||
//! Interruption flag
|
||||
bool m_interruption_requested;
|
||||
|
||||
protected:
|
||||
//! Default constructor
|
||||
bounded_fifo_queue() : m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
//! Initializing constructor
|
||||
template< typename ArgsT >
|
||||
explicit bounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! Enqueues log record to the queue
|
||||
void enqueue(record_view const& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex);
|
||||
std::size_t size = m_queue.size();
|
||||
for (; size >= MaxQueueSizeV; size = m_queue.size())
|
||||
{
|
||||
if (!overflow_strategy::on_overflow(rec, lock))
|
||||
return;
|
||||
}
|
||||
|
||||
m_queue.push(rec);
|
||||
if (size == 0)
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
//! Attempts to enqueue log record to the queue
|
||||
bool try_enqueue(record_view const& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex, try_to_lock);
|
||||
if (lock.owns_lock())
|
||||
{
|
||||
const std::size_t size = m_queue.size();
|
||||
|
||||
// Do not invoke the bounding strategy in case of overflow as it may block
|
||||
if (size < MaxQueueSizeV)
|
||||
{
|
||||
m_queue.push(rec);
|
||||
if (size == 0)
|
||||
m_cond.notify_one();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
|
||||
bool try_dequeue_ready(record_view& rec)
|
||||
{
|
||||
return try_dequeue(rec);
|
||||
}
|
||||
|
||||
//! Attempts to dequeue log record from the queue, does not block if the queue is empty
|
||||
bool try_dequeue(record_view& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
const std::size_t size = m_queue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
rec.swap(m_queue.front());
|
||||
m_queue.pop();
|
||||
overflow_strategy::on_queue_space_available();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Dequeues log record from the queue, blocks if the queue is empty
|
||||
bool dequeue_ready(record_view& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex);
|
||||
|
||||
while (!m_interruption_requested)
|
||||
{
|
||||
const std::size_t size = m_queue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
rec.swap(m_queue.front());
|
||||
m_queue.pop();
|
||||
overflow_strategy::on_queue_space_available();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
m_interruption_requested = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Wakes a thread possibly blocked in the \c dequeue method
|
||||
void interrupt_dequeue()
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
m_interruption_requested = true;
|
||||
overflow_strategy::interrupt();
|
||||
m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_BOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 bounded_ordering_queue.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 06.01.2012
|
||||
*
|
||||
* The header contains implementation of bounded ordering queueing strategy for
|
||||
* the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_BOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_BOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: This header content is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/log/detail/timestamp.hpp>
|
||||
#include <boost/log/detail/enqueued_record.hpp>
|
||||
#include <boost/log/keywords/order.hpp>
|
||||
#include <boost/log/keywords/ordering_window.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Bounded ordering log record queueing strategy
|
||||
*
|
||||
* The \c bounded_ordering_queue class is intended to be used with
|
||||
* the \c asynchronous_sink frontend as a log record queueing strategy.
|
||||
*
|
||||
* This strategy provides the following properties to the record queueing mechanism:
|
||||
*
|
||||
* \li The queue has limited capacity specified by the \c MaxQueueSizeV template parameter.
|
||||
* \li Upon reaching the size limit, the queue invokes the overflow handling strategy
|
||||
* specified in the \c OverflowStrategyT template parameter to handle the situation.
|
||||
* The library provides overflow handling strategies for most common cases:
|
||||
* \c drop_on_overflow will silently discard the log record, and \c block_on_overflow
|
||||
* will put the enqueueing thread to wait until there is space in the queue.
|
||||
* \li The queue has a fixed latency window. This means that each log record put
|
||||
* into the queue will normally not be dequeued for a certain period of time.
|
||||
* \li The queue performs stable record ordering within the latency window.
|
||||
* The ordering predicate can be specified in the \c OrderT template parameter.
|
||||
*/
|
||||
template< typename OrderT, std::size_t MaxQueueSizeV, typename OverflowStrategyT >
|
||||
class bounded_ordering_queue :
|
||||
private OverflowStrategyT
|
||||
{
|
||||
private:
|
||||
typedef OverflowStrategyT overflow_strategy;
|
||||
typedef boost::mutex mutex_type;
|
||||
typedef sinks::aux::enqueued_record enqueued_record;
|
||||
|
||||
typedef std::priority_queue<
|
||||
enqueued_record,
|
||||
std::vector< enqueued_record >,
|
||||
enqueued_record::order< OrderT >
|
||||
> queue_type;
|
||||
|
||||
private:
|
||||
//! Ordering window duration, in milliseconds
|
||||
const uint64_t m_ordering_window;
|
||||
//! Synchronization primitive
|
||||
mutex_type m_mutex;
|
||||
//! Condition to block the consuming thread on
|
||||
condition_variable m_cond;
|
||||
//! Log record queue
|
||||
queue_type m_queue;
|
||||
//! Interruption flag
|
||||
bool m_interruption_requested;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Returns ordering window size specified during initialization
|
||||
*/
|
||||
posix_time::time_duration get_ordering_window() const
|
||||
{
|
||||
return posix_time::milliseconds(m_ordering_window);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns default ordering window size.
|
||||
* The default window size is specific to the operating system thread scheduling mechanism.
|
||||
*/
|
||||
static posix_time::time_duration get_default_ordering_window()
|
||||
{
|
||||
// The main idea behind this parameter is that the ordering window should be large enough
|
||||
// to allow the frontend to order records from different threads on an attribute
|
||||
// that contains system time. Thus this value should be:
|
||||
// * No less than the minimum time resolution quant that Boost.DateTime provides on the current OS.
|
||||
// For instance, on Windows it defaults to around 15-16 ms.
|
||||
// * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to
|
||||
// switch threads on any known OS. It can be tuned for other platforms as needed.
|
||||
return posix_time::milliseconds(30);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Initializing constructor
|
||||
template< typename ArgsT >
|
||||
explicit bounded_ordering_queue(ArgsT const& args) :
|
||||
m_ordering_window(args[keywords::ordering_window || &bounded_ordering_queue::get_default_ordering_window].total_milliseconds()),
|
||||
m_queue(args[keywords::order]),
|
||||
m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! Enqueues log record to the queue
|
||||
void enqueue(record_view const& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex);
|
||||
std::size_t size = m_queue.size();
|
||||
for (; size >= MaxQueueSizeV; size = m_queue.size())
|
||||
{
|
||||
if (!overflow_strategy::on_overflow(rec, lock))
|
||||
return;
|
||||
}
|
||||
|
||||
m_queue.push(enqueued_record(rec));
|
||||
if (size == 0)
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
//! Attempts to enqueue log record to the queue
|
||||
bool try_enqueue(record_view const& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex, try_to_lock);
|
||||
if (lock.owns_lock())
|
||||
{
|
||||
const std::size_t size = m_queue.size();
|
||||
|
||||
// Do not invoke the bounding strategy in case of overflow as it may block
|
||||
if (size < MaxQueueSizeV)
|
||||
{
|
||||
m_queue.push(enqueued_record(rec));
|
||||
if (size == 0)
|
||||
m_cond.notify_one();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
|
||||
bool try_dequeue_ready(record_view& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
const std::size_t size = m_queue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
const boost::log::aux::timestamp now = boost::log::aux::get_timestamp();
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window)
|
||||
{
|
||||
// We got a new element
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
overflow_strategy::on_queue_space_available();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue log record from the queue, does not block if the queue is empty
|
||||
bool try_dequeue(record_view& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
const std::size_t size = m_queue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
overflow_strategy::on_queue_space_available();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Dequeues log record from the queue, blocks if the queue is empty
|
||||
bool dequeue_ready(record_view& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex);
|
||||
|
||||
while (!m_interruption_requested)
|
||||
{
|
||||
const std::size_t size = m_queue.size();
|
||||
if (size > 0)
|
||||
{
|
||||
const boost::log::aux::timestamp now = boost::log::aux::get_timestamp();
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
const uint64_t difference = (now - elem.m_timestamp).milliseconds();
|
||||
if (difference >= m_ordering_window)
|
||||
{
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
overflow_strategy::on_queue_space_available();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait until the element becomes ready to be processed
|
||||
m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
m_interruption_requested = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Wakes a thread possibly blocked in the \c dequeue method
|
||||
void interrupt_dequeue()
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
m_interruption_requested = true;
|
||||
overflow_strategy::interrupt();
|
||||
m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_BOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 debug_output_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 07.11.2008
|
||||
*
|
||||
* The header contains a logging sink backend that outputs log records to the debugger.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_DEBUG_OUTPUT_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_DEBUG_OUTPUT_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT
|
||||
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a logging sink backend that outputs to the debugger
|
||||
*
|
||||
* The sink uses Windows API in order to write log records as debug messages, if the
|
||||
* application process is run under debugger. The sink backend also provides a specific
|
||||
* filter that allows to check whether the debugger is available and thus elide unnecessary
|
||||
* formatting.
|
||||
*/
|
||||
template< typename CharT >
|
||||
class basic_debug_output_backend :
|
||||
public basic_formatted_sink_backend< CharT, concurrent_feeding >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend< CharT, concurrent_feeding > base_type;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef typename base_type::char_type char_type;
|
||||
//! String type to be used as a message text holder
|
||||
typedef typename base_type::string_type string_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor. Initializes the sink backend.
|
||||
*/
|
||||
BOOST_LOG_API basic_debug_output_backend();
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
BOOST_LOG_API ~basic_debug_output_backend();
|
||||
|
||||
/*!
|
||||
* The method passes the formatted message to debugger
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
};
|
||||
|
||||
#ifdef BOOST_LOG_USE_CHAR
|
||||
typedef basic_debug_output_backend< char > debug_output_backend; //!< Convenience typedef for narrow-character logging
|
||||
#endif
|
||||
#ifdef BOOST_LOG_USE_WCHAR_T
|
||||
typedef basic_debug_output_backend< wchar_t > wdebug_output_backend; //!< Convenience typedef for wide-character logging
|
||||
#endif
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_WITHOUT_DEBUG_OUTPUT
|
||||
|
||||
#endif // BOOST_LOG_SINKS_DEBUG_OUTPUT_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 drop_on_overflow.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 04.01.2012
|
||||
*
|
||||
* The header contains implementation of \c drop_on_overflow strategy for handling
|
||||
* queue overflows in bounded queues for the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_DROP_ON_OVERFLOW_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_DROP_ON_OVERFLOW_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Log record dropping strategy
|
||||
*
|
||||
* This strategy will cause log records to be discarded in case of
|
||||
* queue overflow in bounded asynchronous sinks. It should not be used
|
||||
* if losing log records is not acceptable.
|
||||
*/
|
||||
class drop_on_overflow
|
||||
{
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
public:
|
||||
/*!
|
||||
* This method is called by the queue when overflow is detected.
|
||||
*
|
||||
* \retval true Attempt to enqueue the record again.
|
||||
* \retval false Discard the record.
|
||||
*/
|
||||
template< typename LockT >
|
||||
static bool on_overflow(record_view const&, LockT&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by the queue when there appears a free space.
|
||||
*/
|
||||
static void on_queue_space_available()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* This method is called by the queue to interrupt any possible waits in \c on_overflow.
|
||||
*/
|
||||
static void interrupt()
|
||||
{
|
||||
}
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_DROP_ON_OVERFLOW_HPP_INCLUDED_
|
||||
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 event_log_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 07.11.2008
|
||||
*
|
||||
* The header contains a logging sink backend that uses Windows NT event log API
|
||||
* for signaling application events.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/detail/light_function.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/keywords/message_file.hpp>
|
||||
#include <boost/log/keywords/log_name.hpp>
|
||||
#include <boost/log/keywords/log_source.hpp>
|
||||
#include <boost/log/keywords/registration.hpp>
|
||||
#include <boost/log/keywords/target.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/sinks/attribute_mapping.hpp>
|
||||
#include <boost/log/sinks/event_log_constants.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/expressions/formatter.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
namespace event_log {
|
||||
|
||||
//! Event log source registration modes
|
||||
enum registration_mode
|
||||
{
|
||||
never, //!< Never register event source, even if it's not registered
|
||||
on_demand, //!< Register if the source is not registered yet
|
||||
forced //!< Register always, event if the source is already registered
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Straightforward event type mapping
|
||||
*
|
||||
* This type of mapping assumes that attribute with a particular name always
|
||||
* provides values that map directly onto the native event types. The mapping
|
||||
* simply returns the extracted attribute value converted to the native event type.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class direct_event_type_mapping :
|
||||
public basic_direct_mapping< event_type, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_direct_mapping< event_type, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit direct_event_type_mapping(attribute_name const& name) :
|
||||
base_type(name, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Customizable event type mapping
|
||||
*
|
||||
* The class allows to setup a custom mapping between an attribute and native event types.
|
||||
* The mapping should be initialized similarly to the standard \c map container, by using
|
||||
* indexing operator and assignment.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class custom_event_type_mapping :
|
||||
public basic_custom_mapping< event_type, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_custom_mapping< event_type, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit custom_event_type_mapping(attribute_name const& name) :
|
||||
base_type(name, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Straightforward event ID mapping
|
||||
*
|
||||
* This type of mapping assumes that attribute with a particular name always
|
||||
* provides values that map directly onto the event identifiers. The mapping
|
||||
* simply returns the extracted attribute value converted to the event ID.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class direct_event_id_mapping :
|
||||
public basic_direct_mapping< event_id, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_direct_mapping< event_id, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit direct_event_id_mapping(attribute_name const& name) :
|
||||
base_type(name, make_event_id(0))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Customizable event ID mapping
|
||||
*
|
||||
* The class allows to setup a custom mapping between an attribute and event identifiers.
|
||||
* The mapping should be initialized similarly to the standard \c map container, by using
|
||||
* indexing operator and assignment.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class custom_event_id_mapping :
|
||||
public basic_custom_mapping< event_id, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_custom_mapping< event_id, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit custom_event_id_mapping(attribute_name const& name) :
|
||||
base_type(name, make_event_id(0))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Straightforward event category mapping
|
||||
*
|
||||
* This type of mapping assumes that attribute with a particular name always
|
||||
* provides values that map directly onto the event categories. The mapping
|
||||
* simply returns the extracted attribute value converted to the event category.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class direct_event_category_mapping :
|
||||
public basic_direct_mapping< event_category, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_direct_mapping< event_category, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit direct_event_category_mapping(attribute_name const& name) :
|
||||
base_type(name, make_event_category(0))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Customizable event category mapping
|
||||
*
|
||||
* The class allows to setup a custom mapping between an attribute and event categories.
|
||||
* The mapping should be initialized similarly to the standard \c map container, by using
|
||||
* indexing operator and assignment.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class custom_event_category_mapping :
|
||||
public basic_custom_mapping< event_category, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_custom_mapping< event_category, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit custom_event_category_mapping(attribute_name const& name) :
|
||||
base_type(name, make_event_category(0))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief An event composer
|
||||
*
|
||||
* This class is a function object that extracts event identifier from the attribute values set
|
||||
* and formats insertion strings for the particular event. Each insertion string is formatted with
|
||||
* a distinct formatter, which can be created just like regular sinks formatters.
|
||||
*
|
||||
* Before using, the composer must be initialized with the following information:
|
||||
* \li Event identifier extraction logic. One can use \c basic_direct_event_id_mapping or
|
||||
* \c basic_custom_event_id_mapping classes in order to create such extractor and pass it
|
||||
* to the composer constructor.
|
||||
* \li Event identifiers and insertion string formatters. The composer provides the following
|
||||
* syntax to provide this information:
|
||||
*
|
||||
* \code
|
||||
* event_composer comp;
|
||||
* comp[MY_EVENT_ID1] % formatter1 % ... % formatterN;
|
||||
* comp[MY_EVENT_ID2] % formatter1 % ... % formatterN;
|
||||
* ...
|
||||
* \endcode
|
||||
*
|
||||
* The event identifiers in square brackets are provided by the message compiler generated
|
||||
* header (the actual names are specified in the .mc file). The formatters represent
|
||||
* the insertion strings that will be used to replace placeholders in event messages,
|
||||
* thus the number and the order of the formatters must correspond to the message definition.
|
||||
*/
|
||||
template< typename CharT >
|
||||
class BOOST_LOG_API basic_event_composer
|
||||
{
|
||||
public:
|
||||
//! Character type
|
||||
typedef CharT char_type;
|
||||
//! String type to be used as a message text holder
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
|
||||
//! Event identifier mapper type
|
||||
typedef boost::log::aux::light_function< event_id (record_view const&) > event_id_mapper_type;
|
||||
|
||||
//! Type of an insertion composer (a formatter)
|
||||
typedef basic_formatter< char_type > formatter_type;
|
||||
//! Type of the composed insertions list
|
||||
typedef std::vector< string_type > insertion_list;
|
||||
|
||||
private:
|
||||
//! \cond
|
||||
|
||||
//! The class that implements formatting of insertion strings
|
||||
class insertion_composer;
|
||||
|
||||
//! Type of the events map
|
||||
typedef std::map< event_id, insertion_composer > event_map;
|
||||
|
||||
//! A smart reference that puts formatters into the composer
|
||||
class event_map_reference;
|
||||
friend class event_map_reference;
|
||||
class event_map_reference
|
||||
{
|
||||
private:
|
||||
//! Event identifier
|
||||
event_id m_ID;
|
||||
//! A reference to the object that created the reference
|
||||
basic_event_composer< char_type >& m_Owner;
|
||||
//! A hint for the owner to optimize insertion
|
||||
insertion_composer* m_Composer;
|
||||
|
||||
public:
|
||||
//! Initializing constructor
|
||||
explicit event_map_reference(event_id id, basic_event_composer< char_type >& owner) :
|
||||
m_ID(id),
|
||||
m_Owner(owner),
|
||||
m_Composer(0)
|
||||
{
|
||||
}
|
||||
//! The operator puts the formatter into the composer
|
||||
template< typename FormatterT >
|
||||
event_map_reference& operator% (FormatterT const& fmt)
|
||||
{
|
||||
m_Composer = m_Owner.add_formatter(m_ID, m_Composer, formatter_type(fmt));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
//! \endcond
|
||||
|
||||
private:
|
||||
//! The mapper that will extract the event identifier
|
||||
event_id_mapper_type m_EventIDMapper;
|
||||
//! The map of event identifiers and their insertion composers
|
||||
event_map m_EventMap;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. Creates an empty map of events.
|
||||
*
|
||||
* \param id_mapper An event identifier mapping function that will be used to extract event ID from attribute values
|
||||
*/
|
||||
explicit basic_event_composer(event_id_mapper_type const& id_mapper);
|
||||
/*!
|
||||
* Copy constructor. Performs a deep copy of the object.
|
||||
*/
|
||||
basic_event_composer(basic_event_composer const& that);
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
~basic_event_composer();
|
||||
|
||||
/*!
|
||||
* Assignment. Provides strong exception guarantee.
|
||||
*/
|
||||
basic_event_composer& operator= (basic_event_composer that);
|
||||
/*!
|
||||
* Swaps \c *this and \c that objects.
|
||||
*/
|
||||
void swap(basic_event_composer& that);
|
||||
/*!
|
||||
* Initiates creation of a new event description. The result of the operator can be used to
|
||||
* add formatters for insertion strings construction. The returned reference type is implementation detail.
|
||||
*
|
||||
* \param id Event identifier.
|
||||
*/
|
||||
event_map_reference operator[] (event_id id);
|
||||
/*!
|
||||
* Initiates creation of a new event description. The result of the operator can be used to
|
||||
* add formatters for insertion strings construction. The returned reference type is implementation detail.
|
||||
*
|
||||
* \param id Event identifier.
|
||||
*/
|
||||
event_map_reference operator[] (int id);
|
||||
/*!
|
||||
* Event composition operator. Extracts an event identifier from the attribute values by calling event ID mapper.
|
||||
* Then runs all formatters that were registered for the event with the extracted ID. The results of formatting
|
||||
* are returned in the \a insertions parameter.
|
||||
*
|
||||
* \param rec Log record view
|
||||
* \param insertions A sequence of formatted insertion strings
|
||||
* \return An event identifier that was extracted from \c attributes
|
||||
*/
|
||||
event_id operator() (record_view const& rec, insertion_list& insertions) const;
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! Adds a formatter to the insertion composers list
|
||||
insertion_composer* add_formatter(event_id id, insertion_composer* composer, formatter_type const& fmt);
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
#ifdef BOOST_LOG_USE_CHAR
|
||||
typedef basic_event_composer< char > event_composer; //!< Convenience typedef for narrow-character logging
|
||||
#endif
|
||||
#ifdef BOOST_LOG_USE_WCHAR_T
|
||||
typedef basic_event_composer< wchar_t > wevent_composer; //!< Convenience typedef for wide-character logging
|
||||
#endif
|
||||
|
||||
} // namespace event_log
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a simple logging sink backend that emits events into Windows NT event log
|
||||
*
|
||||
* The sink uses Windows NT 5 (Windows 2000) and later event log API to emit events
|
||||
* to an event log. The sink acts as an event source in terms of the API, it implements all needed resources
|
||||
* and source registration in the Windows registry that is needed for the event delivery.
|
||||
*
|
||||
* The backend performs message text formatting. The composed text is then passed as the first
|
||||
* and only string parameter of the event. The resource embedded into the backend describes the event
|
||||
* so that the parameter is inserted into the event description text, thus making it visible
|
||||
* in the event log.
|
||||
*
|
||||
* The backend allows to customize mapping of application severity levels to the native Windows event types.
|
||||
* This allows to write portable code even if OS-specific sinks, such as this one, are used.
|
||||
*
|
||||
* \note Since the backend registers itself into Windows registry as the resource file that contains
|
||||
* event description, it is important to keep the library binary in a stable place of the filesystem.
|
||||
* Otherwise Windows might not be able to load event resources from the library and display
|
||||
* events correctly.
|
||||
*
|
||||
* \note It is known that Windows is not able to find event resources in the application executable,
|
||||
* which is linked against the static build of the library. Users are advised to use dynamic
|
||||
* builds of the library to solve this problem.
|
||||
*/
|
||||
template< typename CharT >
|
||||
class basic_simple_event_log_backend :
|
||||
public basic_formatted_sink_backend< CharT, concurrent_feeding >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend< CharT, concurrent_feeding > base_type;
|
||||
//! Implementation type
|
||||
struct implementation;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef typename base_type::char_type char_type;
|
||||
//! String type to be used as a message text holder
|
||||
typedef typename base_type::string_type string_type;
|
||||
|
||||
//! Mapper type for the event type
|
||||
typedef boost::log::aux::light_function< event_log::event_type (record_view const&) > event_type_mapper_type;
|
||||
|
||||
private:
|
||||
//! Pointer to the backend implementation that hides various types from windows.h
|
||||
implementation* m_pImpl;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. Registers event source with name based on the application
|
||||
* executable file name in the Application log. If such a registration is already
|
||||
* present, it is not overridden.
|
||||
*/
|
||||
BOOST_LOG_API basic_simple_event_log_backend();
|
||||
/*!
|
||||
* Constructor. Registers event log source with the specified parameters.
|
||||
* The following named parameters are supported:
|
||||
*
|
||||
* \li \c target - Specifies an UNC path to the remote server which log records should be sent to.
|
||||
* The local machine will be used to process log records, if not specified.
|
||||
* \li \c log_name - Specifies the log in which the source should be registered.
|
||||
* The result of \c get_default_log_name is used, if the parameter is not specified.
|
||||
* \li \c log_source - Specifies the source name. The result of \c get_default_source_name
|
||||
* is used, if the parameter is not specified.
|
||||
* \li \c registration - Specifies the event source registration mode in the Windows registry.
|
||||
* Can have values of the \c registration_mode enum. Default value: \c on_demand.
|
||||
*
|
||||
* \param args A set of named parameters.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(basic_simple_event_log_backend, construct)
|
||||
#else
|
||||
template< typename... ArgsT >
|
||||
explicit basic_simple_event_log_backend(ArgsT... const& args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Destructor. Unregisters event source. The log source description is not removed from the Windows registry.
|
||||
*/
|
||||
BOOST_LOG_API ~basic_simple_event_log_backend();
|
||||
|
||||
/*!
|
||||
* The method installs the function object that maps application severity levels to WinAPI event types
|
||||
*/
|
||||
BOOST_LOG_API void set_event_type_mapper(event_type_mapper_type const& mapper);
|
||||
|
||||
/*!
|
||||
* \returns Default log name: Application
|
||||
*/
|
||||
BOOST_LOG_API static string_type get_default_log_name();
|
||||
/*!
|
||||
* \returns Default log source name that is based on the application executable file name and the sink name
|
||||
*/
|
||||
BOOST_LOG_API static string_type get_default_source_name();
|
||||
|
||||
/*!
|
||||
* The method puts the formatted message to the event log
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! Constructs backend implementation
|
||||
template< typename ArgsT >
|
||||
void construct(ArgsT const& args)
|
||||
{
|
||||
construct(
|
||||
args[keywords::target | string_type()],
|
||||
args[keywords::log_name || &basic_simple_event_log_backend::get_default_log_name],
|
||||
args[keywords::log_source || &basic_simple_event_log_backend::get_default_source_name],
|
||||
args[keywords::registration | event_log::on_demand]);
|
||||
}
|
||||
BOOST_LOG_API void construct(
|
||||
string_type const& target,
|
||||
string_type const& log_name,
|
||||
string_type const& source_name,
|
||||
event_log::registration_mode reg_mode);
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a logging sink backend that emits events into Windows NT event log
|
||||
*
|
||||
* The sink uses Windows NT 5 (Windows 2000) and later event log API to emit events
|
||||
* to an event log. The sink acts as an event source. Unlike \c basic_simple_event_log_backend,
|
||||
* this sink backend allows users to specify the custom event message file and supports
|
||||
* mapping attribute values onto several insertion strings. Although it requires considerably
|
||||
* more scaffolding than the simple backend, this allows to support localizable event descriptions.
|
||||
*
|
||||
* Besides the file name of the module with event resources, the backend provides the following
|
||||
* customizations:
|
||||
* \li Remote server UNC address, log name and source name. These parameters have similar meaning
|
||||
* to \c basic_simple_event_log_backend.
|
||||
* \li Event type and category mappings. These are function object that allow to map attribute
|
||||
* values to the according event parameters. One can use mappings in the \c event_log namespace.
|
||||
* \li Event composer. This function object extracts event identifier and formats string insertions,
|
||||
* that will be used by the API to compose the final event message text.
|
||||
*/
|
||||
template< typename CharT >
|
||||
class basic_event_log_backend :
|
||||
public basic_sink_backend< synchronized_feeding >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_sink_backend< synchronized_feeding > base_type;
|
||||
//! Implementation type
|
||||
struct implementation;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef CharT char_type;
|
||||
//! String type
|
||||
typedef std::basic_string< char_type > string_type;
|
||||
//! Type of the composed insertions list
|
||||
typedef std::vector< string_type > insertion_list;
|
||||
|
||||
//! Mapper type for the event type
|
||||
typedef boost::log::aux::light_function< event_log::event_type (record_view const&) > event_type_mapper_type;
|
||||
//! Mapper type for the event category
|
||||
typedef boost::log::aux::light_function< event_log::event_category (record_view const&) > event_category_mapper_type;
|
||||
//! Event composer type
|
||||
typedef boost::log::aux::light_function< event_log::event_id (record_view const&, insertion_list&) > event_composer_type;
|
||||
|
||||
private:
|
||||
//! Pointer to the backend implementation that hides various types from windows.h
|
||||
implementation* m_pImpl;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor. Registers event source with name based on the application
|
||||
* executable file name in the Application log. If such a registration is already
|
||||
* present, it is not overridden.
|
||||
*/
|
||||
template< typename T >
|
||||
explicit basic_event_log_backend(std::basic_string< T > const& message_file_name)
|
||||
{
|
||||
construct(keywords::message_file = message_file_name);
|
||||
}
|
||||
/*!
|
||||
* Constructor. Registers event source with name based on the application
|
||||
* executable file name in the Application log. If such a registration is already
|
||||
* present, it is not overridden.
|
||||
*/
|
||||
explicit basic_event_log_backend(filesystem::path const& message_file_name)
|
||||
{
|
||||
construct(keywords::message_file = message_file_name);
|
||||
}
|
||||
/*!
|
||||
* Constructor. Registers event log source with the specified parameters.
|
||||
* The following named parameters are supported:
|
||||
*
|
||||
* \li \c message_file - Specifies the file name that contains resources that
|
||||
* describe events and categories. This parameter is mandatory unless \c registration is \c never.
|
||||
* \li \c target - Specifies an UNC path to the remote server to which log records should be sent to.
|
||||
* The local machine will be used to process log records, if not specified.
|
||||
* \li \c log_name - Specifies the log in which the source should be registered.
|
||||
* The result of \c get_default_log_name is used, if the parameter is not specified.
|
||||
* \li \c log_source - Specifies the source name. The result of \c get_default_source_name
|
||||
* is used, if the parameter is not specified.
|
||||
* \li \c registration - Specifies the event source registration mode in the Windows registry.
|
||||
* Can have values of the \c registration_mode enum. Default value: \c on_demand.
|
||||
*
|
||||
* \param args A set of named parameters.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(basic_event_log_backend, construct)
|
||||
#else
|
||||
template< typename... ArgsT >
|
||||
explicit basic_event_log_backend(ArgsT... const& args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Destructor. Unregisters event source. The log source description is not removed from the Windows registry.
|
||||
*/
|
||||
BOOST_LOG_API ~basic_event_log_backend();
|
||||
|
||||
/*!
|
||||
* The method creates an event in the event log
|
||||
*
|
||||
* \param rec Log record to consume
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec);
|
||||
|
||||
/*!
|
||||
* The method installs the function object that maps application severity levels to WinAPI event types
|
||||
*/
|
||||
BOOST_LOG_API void set_event_type_mapper(event_type_mapper_type const& mapper);
|
||||
|
||||
/*!
|
||||
* The method installs the function object that extracts event category from attribute values
|
||||
*/
|
||||
BOOST_LOG_API void set_event_category_mapper(event_category_mapper_type const& mapper);
|
||||
|
||||
/*!
|
||||
* The method installs the function object that extracts event identifier from the attributes and creates
|
||||
* insertion strings that will replace placeholders in the event message.
|
||||
*/
|
||||
BOOST_LOG_API void set_event_composer(event_composer_type const& composer);
|
||||
|
||||
/*!
|
||||
* \returns Default log name: Application
|
||||
*/
|
||||
BOOST_LOG_API static string_type get_default_log_name();
|
||||
/*!
|
||||
* \returns Default log source name that is based on the application executable file name and the sink name
|
||||
*/
|
||||
BOOST_LOG_API static string_type get_default_source_name();
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! Constructs backend implementation
|
||||
template< typename ArgsT >
|
||||
void construct(ArgsT const& args)
|
||||
{
|
||||
construct(
|
||||
filesystem::path(args[keywords::message_file | filesystem::path()]),
|
||||
args[keywords::target | string_type()],
|
||||
args[keywords::log_name || &basic_event_log_backend::get_default_log_name],
|
||||
args[keywords::log_source || &basic_event_log_backend::get_default_source_name],
|
||||
args[keywords::registration | event_log::on_demand]);
|
||||
}
|
||||
BOOST_LOG_API void construct(
|
||||
filesystem::path const& message_file_name,
|
||||
string_type const& target,
|
||||
string_type const& log_name,
|
||||
string_type const& source_name,
|
||||
event_log::registration_mode reg_mode);
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
#ifdef BOOST_LOG_USE_CHAR
|
||||
typedef basic_simple_event_log_backend< char > simple_event_log_backend; //!< Convenience typedef for narrow-character logging
|
||||
typedef basic_event_log_backend< char > event_log_backend; //!< Convenience typedef for narrow-character logging
|
||||
#endif
|
||||
#ifdef BOOST_LOG_USE_WCHAR_T
|
||||
typedef basic_simple_event_log_backend< wchar_t > wsimple_event_log_backend; //!< Convenience typedef for wide-character logging
|
||||
typedef basic_event_log_backend< wchar_t > wevent_log_backend; //!< Convenience typedef for wide-character logging
|
||||
#endif
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_WITHOUT_EVENT_LOG
|
||||
|
||||
#endif // BOOST_LOG_SINKS_EVENT_LOG_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 event_log_constants.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 07.11.2008
|
||||
*
|
||||
* The header contains definition of constants related to Windows NT Event Log API.
|
||||
* The constants can be used in other places without the event log backend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_EVENT_LOG_CONSTANTS_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_EVENT_LOG_CONSTANTS_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_EVENT_LOG
|
||||
|
||||
#include <boost/log/detail/tagged_integer.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
namespace event_log {
|
||||
|
||||
struct event_id_tag;
|
||||
//! A tagged integral type that represents event identifier for the Windows API
|
||||
typedef boost::log::aux::tagged_integer< unsigned int, event_id_tag > event_id;
|
||||
/*!
|
||||
* The function constructs event identifier from an integer
|
||||
*/
|
||||
inline event_id make_event_id(unsigned int id)
|
||||
{
|
||||
event_id iden = { id };
|
||||
return iden;
|
||||
}
|
||||
|
||||
struct event_category_tag;
|
||||
//! A tagged integral type that represents event category for the Windows API
|
||||
typedef boost::log::aux::tagged_integer< unsigned short, event_category_tag > event_category;
|
||||
/*!
|
||||
* The function constructs event category from an integer
|
||||
*/
|
||||
inline event_category make_event_category(unsigned short cat)
|
||||
{
|
||||
event_category category = { cat };
|
||||
return category;
|
||||
}
|
||||
|
||||
//! Windows event types
|
||||
enum event_type
|
||||
{
|
||||
success = 0, //!< Equivalent to EVENTLOG_SUCCESS
|
||||
info = 4, //!< Equivalent to EVENTLOG_INFORMATION_TYPE
|
||||
warning = 2, //!< Equivalent to EVENTLOG_WARNING_TYPE
|
||||
error = 1 //!< Equivalent to EVENTLOG_ERROR_TYPE
|
||||
};
|
||||
|
||||
/*!
|
||||
* The function constructs log record level from an integer
|
||||
*/
|
||||
BOOST_LOG_API event_type make_event_type(unsigned short lev);
|
||||
|
||||
} // namespace event_log
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_WITHOUT_EVENT_LOG
|
||||
|
||||
#endif // BOOST_LOG_SINKS_EVENT_LOG_CONSTANTS_HPP_INCLUDED_
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 sinks/frontend_requirements.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 22.04.2007
|
||||
*
|
||||
* The header contains definition of requirement tags that sink backend may declare
|
||||
* with regard to frontends. These requirements ensure that a backend will not
|
||||
* be used with an incompatible frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_FRONTEND_REQUIREMENTS_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_FRONTEND_REQUIREMENTS_HPP_INCLUDED_
|
||||
|
||||
#include <boost/mpl/aux_/na.hpp>
|
||||
#include <boost/mpl/placeholders.hpp>
|
||||
#include <boost/mpl/inherit.hpp>
|
||||
#include <boost/mpl/inherit_linearly.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_COMBINE_REQUIREMENTS_LIMIT
|
||||
//! The macro specifies the maximum number of requirements that can be combined with the \c combine_requirements metafunction
|
||||
#define BOOST_LOG_COMBINE_REQUIREMENTS_LIMIT 5
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* The sink backend expects pre-synchronized calls, all needed synchronization is implemented
|
||||
* in the frontend (IOW, only one thread is feeding records to the backend concurrently, but
|
||||
* it is possible for several threads to write sequentially). Note that if a frontend supports
|
||||
* synchronized record feeding, it will also report capable of concurrent record feeding.
|
||||
*/
|
||||
struct synchronized_feeding {};
|
||||
|
||||
#if !defined(BOOST_LOG_NO_THREADS)
|
||||
|
||||
/*!
|
||||
* The sink backend ensures all needed synchronization, it is capable to handle multithreaded calls
|
||||
*/
|
||||
struct concurrent_feeding : synchronized_feeding {};
|
||||
|
||||
#else // !defined(BOOST_LOG_NO_THREADS)
|
||||
|
||||
// If multithreading is disabled, threading models become redundant
|
||||
typedef synchronized_feeding concurrent_feeding;
|
||||
|
||||
#endif // !defined(BOOST_LOG_NO_THREADS)
|
||||
|
||||
/*!
|
||||
* The sink backend requires the frontend to perform log record formatting before feeding
|
||||
*/
|
||||
struct formatted_records {};
|
||||
|
||||
/*!
|
||||
* The sink backend supports flushing
|
||||
*/
|
||||
struct flushing {};
|
||||
|
||||
#ifdef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* The metafunction combines multiple requirement tags into one type. The resulting type will
|
||||
* satisfy all specified requirements (i.e. \c has_requirement metafunction will return positive result).
|
||||
*/
|
||||
template< typename... RequirementsT >
|
||||
struct combine_requirements;
|
||||
|
||||
#else
|
||||
|
||||
template< BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_LOG_COMBINE_REQUIREMENTS_LIMIT, typename ReqT, mpl::na) >
|
||||
struct combine_requirements :
|
||||
mpl::inherit_linearly<
|
||||
mpl::vector< BOOST_PP_ENUM_PARAMS(BOOST_LOG_COMBINE_REQUIREMENTS_LIMIT, ReqT) >,
|
||||
mpl::inherit2< mpl::_1, mpl::_2 >
|
||||
>
|
||||
{
|
||||
};
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* A helper metafunction to check if a requirement is satisfied. The \c TestedT template argument
|
||||
* should be the type combining one or several requirements and \c RequiredT is the requirement
|
||||
* to test against. The metafunction will yield a positive result if \c TestedT supports \c RequiredT.
|
||||
*/
|
||||
template< typename TestedT, typename RequiredT >
|
||||
struct has_requirement :
|
||||
public is_base_of< RequiredT, TestedT >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_FRONTEND_REQUIREMENTS_HPP_INCLUDED_
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 sink.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 22.04.2007
|
||||
*
|
||||
* The header contains an interface declaration for all sinks. This interface is used by the
|
||||
* logging core to feed log records to sinks.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_SINK_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_SINK_HPP_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/light_function.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
//! A base class for a logging sink frontend
|
||||
class BOOST_LOG_NO_VTABLE sink
|
||||
{
|
||||
public:
|
||||
//! An exception handler type
|
||||
typedef boost::log::aux::light_function< void () > exception_handler_type;
|
||||
|
||||
private:
|
||||
//! The flag indicates that the sink passes log records across thread boundaries
|
||||
const bool m_cross_thread;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor
|
||||
*/
|
||||
explicit sink(bool cross_thread) : m_cross_thread(cross_thread)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~sink() {}
|
||||
|
||||
/*!
|
||||
* The method returns \c true if no filter is set or the attribute values pass the filter
|
||||
*
|
||||
* \param attributes A set of attribute values of a logging record
|
||||
*/
|
||||
virtual bool will_consume(attribute_value_set const& attributes) = 0;
|
||||
|
||||
/*!
|
||||
* The method puts logging record to the sink
|
||||
*
|
||||
* \param rec Logging record to consume
|
||||
*/
|
||||
virtual void consume(record_view const& rec) = 0;
|
||||
|
||||
/*!
|
||||
* The method attempts to put logging record to the sink. The method may be used by the
|
||||
* core in order to determine the most efficient order of sinks to feed records to in
|
||||
* case of heavy contention. Sink implementations may implement try/backoff logic in
|
||||
* order to improve overall logging throughput.
|
||||
*
|
||||
* \param rec Logging record to consume
|
||||
* \return \c true, if the record was consumed, \c false, if not.
|
||||
*/
|
||||
virtual bool try_consume(record_view const& rec)
|
||||
{
|
||||
consume(rec);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method performs flushing of any internal buffers that may hold log records. The method
|
||||
* may take considerable time to complete and may block both the calling thread and threads
|
||||
* attempting to put new records into the sink while this call is in progress.
|
||||
*/
|
||||
virtual void flush() = 0;
|
||||
|
||||
/*!
|
||||
* The method indicates that the sink passes log records between different threads. This information is
|
||||
* needed by the logging core to detach log records from all thread-specific resources before passing it
|
||||
* to the sink.
|
||||
*/
|
||||
bool is_cross_thread() const BOOST_NOEXCEPT { return m_cross_thread; }
|
||||
|
||||
BOOST_DELETED_FUNCTION(sink(sink const&))
|
||||
BOOST_DELETED_FUNCTION(sink& operator= (sink const&))
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_SINK_HPP_INCLUDED_
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 sync_frontend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 14.07.2009
|
||||
*
|
||||
* The header contains implementation of synchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: Synchronous sink frontend is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared_object.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/comparison/equal.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/log/detail/locking_ptr.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/sinks/basic_sink_frontend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\
|
||||
template< typename T0 >\
|
||||
explicit synchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\
|
||||
base_type(false),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\
|
||||
template< BOOST_PP_ENUM_PARAMS(n, typename T) >\
|
||||
explicit synchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\
|
||||
base_type(false),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\
|
||||
BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data)
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* \brief Synchronous logging sink frontend
|
||||
*
|
||||
* The sink frontend serializes threads before passing logging records to the backend
|
||||
*/
|
||||
template< typename SinkBackendT >
|
||||
class synchronous_sink :
|
||||
public aux::make_sink_frontend_base< SinkBackendT >::type
|
||||
{
|
||||
typedef typename aux::make_sink_frontend_base< SinkBackendT >::type base_type;
|
||||
|
||||
private:
|
||||
//! Synchronization mutex type
|
||||
typedef boost::recursive_mutex backend_mutex_type;
|
||||
|
||||
public:
|
||||
//! Sink implementation type
|
||||
typedef SinkBackendT sink_backend_type;
|
||||
//! \cond
|
||||
BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value), "Synchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met");
|
||||
//! \endcond
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
//! A pointer type that locks the backend until it's destroyed
|
||||
typedef boost::log::aux::locking_ptr< sink_backend_type, backend_mutex_type > locked_backend_ptr;
|
||||
|
||||
#else // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
//! A pointer type that locks the backend until it's destroyed
|
||||
typedef implementation_defined locked_backend_ptr;
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
private:
|
||||
//! Synchronization mutex
|
||||
backend_mutex_type m_BackendMutex;
|
||||
//! Pointer to the backend
|
||||
const shared_ptr< sink_backend_type > m_pBackend;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. Constructs the sink backend instance.
|
||||
* Requires the backend to be default-constructible.
|
||||
*/
|
||||
synchronous_sink() :
|
||||
base_type(false),
|
||||
m_pBackend(boost::make_shared< sink_backend_type >())
|
||||
{
|
||||
}
|
||||
/*!
|
||||
* Constructor attaches user-constructed backend instance
|
||||
*
|
||||
* \param backend Pointer to the backend instance
|
||||
*
|
||||
* \pre \a backend is not \c NULL.
|
||||
*/
|
||||
explicit synchronous_sink(shared_ptr< sink_backend_type > const& backend) :
|
||||
base_type(false),
|
||||
m_pBackend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructor that passes arbitrary named parameters to the interprocess sink backend constructor.
|
||||
* Refer to the backend documentation for the list of supported parameters.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~)
|
||||
#else
|
||||
template< typename... Args >
|
||||
explicit synchronous_sink(Args&&... args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Locking accessor to the attached backend
|
||||
*/
|
||||
locked_backend_ptr locked_backend()
|
||||
{
|
||||
return locked_backend_ptr(m_pBackend, m_BackendMutex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Passes the log record to the backend
|
||||
*/
|
||||
void consume(record_view const& rec)
|
||||
{
|
||||
base_type::feed_record(rec, m_BackendMutex, *m_pBackend);
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method attempts to pass logging record to the backend
|
||||
*/
|
||||
bool try_consume(record_view const& rec)
|
||||
{
|
||||
return base_type::try_feed_record(rec, m_BackendMutex, *m_pBackend);
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method performs flushing of any internal buffers that may hold log records. The method
|
||||
* may take considerable time to complete and may block both the calling thread and threads
|
||||
* attempting to put new records into the sink while this call is in progress.
|
||||
*/
|
||||
void flush()
|
||||
{
|
||||
base_type::flush_backend(m_BackendMutex, *m_pBackend);
|
||||
}
|
||||
};
|
||||
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 syslog_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 08.01.2008
|
||||
*
|
||||
* The header contains implementation of a Syslog sink backend along with its setup facilities.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_SYSLOG
|
||||
|
||||
#include <string>
|
||||
#include <boost/log/detail/asio_fwd.hpp>
|
||||
#include <boost/log/detail/light_function.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/syslog_constants.hpp>
|
||||
#include <boost/log/sinks/attribute_mapping.hpp>
|
||||
#include <boost/log/attributes/attribute_value_set.hpp>
|
||||
#include <boost/log/keywords/facility.hpp>
|
||||
#include <boost/log/keywords/use_impl.hpp>
|
||||
#include <boost/log/keywords/ident.hpp>
|
||||
#include <boost/log/keywords/ip_version.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
//! Supported IP protocol versions
|
||||
enum ip_versions
|
||||
{
|
||||
v4,
|
||||
v6
|
||||
};
|
||||
|
||||
namespace syslog {
|
||||
|
||||
//! The enumeration defined the possible implementation types for the syslog backend
|
||||
enum impl_types
|
||||
{
|
||||
#ifdef BOOST_LOG_USE_NATIVE_SYSLOG
|
||||
native = 0 //!< Use native syslog API
|
||||
#ifndef BOOST_LOG_NO_ASIO
|
||||
,
|
||||
#endif
|
||||
#endif
|
||||
#ifndef BOOST_LOG_NO_ASIO
|
||||
udp_socket_based = 1 //!< Use UDP sockets, according to RFC3164
|
||||
#endif
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Straightforward severity level mapping
|
||||
*
|
||||
* This type of mapping assumes that attribute with a particular name always
|
||||
* provides values that map directly onto the Syslog levels. The mapping
|
||||
* simply returns the extracted attribute value converted to the Syslog severity level.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class direct_severity_mapping :
|
||||
public basic_direct_mapping< level, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_direct_mapping< level, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit direct_severity_mapping(attribute_name const& name) :
|
||||
base_type(name, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Customizable severity level mapping
|
||||
*
|
||||
* The class allows to setup a custom mapping between an attribute and Syslog severity levels.
|
||||
* The mapping should be initialized similarly to the standard \c map container, by using
|
||||
* indexing operator and assignment.
|
||||
*/
|
||||
template< typename AttributeValueT = int >
|
||||
class custom_severity_mapping :
|
||||
public basic_custom_mapping< level, AttributeValueT >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_custom_mapping< level, AttributeValueT > base_type;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor
|
||||
*
|
||||
* \param name Attribute name
|
||||
*/
|
||||
explicit custom_severity_mapping(attribute_name const& name) :
|
||||
base_type(name, info)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace syslog
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a syslog sink backend
|
||||
*
|
||||
* The backend provides support for the syslog protocol, defined in RFC3164.
|
||||
* The backend sends log records to a remote host via UDP. The host name can
|
||||
* be specified by calling the \c set_target_address method. By default log
|
||||
* records will be sent to localhost:514. The local address can be specified
|
||||
* as well, by calling the \c set_local_address method. By default syslog
|
||||
* packets will be sent from any local address available.
|
||||
*
|
||||
* It is safe to create several sink backends with the same local addresses -
|
||||
* the backends within the process will share the same socket. The same applies
|
||||
* to different processes that use the syslog backends to send records from
|
||||
* the same socket. However, it is not guaranteed to work if some third party
|
||||
* facility is using the socket.
|
||||
*
|
||||
* On systems with native syslog implementation it may be preferable to utilize
|
||||
* the POSIX syslog API instead of direct socket management in order to bypass
|
||||
* possible security limitations that may be in action. To do so one has to pass
|
||||
* the <tt>use_impl = native</tt> to the backend constructor. Note, however,
|
||||
* that in that case you will only have one chance to specify syslog facility and
|
||||
* process identification string - on the first native syslog backend construction.
|
||||
* Other native syslog backends will ignore these parameters.
|
||||
* Obviously, the \c set_local_address and \c set_target_address
|
||||
* methods have no effect for native backends. Using <tt>use_impl = native</tt>
|
||||
* on platforms with no native support for POSIX syslog API will have no effect.
|
||||
*/
|
||||
class syslog_backend :
|
||||
public basic_formatted_sink_backend< char >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend< char > base_type;
|
||||
//! Implementation type
|
||||
struct implementation;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef base_type::char_type char_type;
|
||||
//! String type that is used to pass message test
|
||||
typedef base_type::string_type string_type;
|
||||
|
||||
//! Syslog severity level mapper type
|
||||
typedef boost::log::aux::light_function< syslog::level (record_view const&) > severity_mapper_type;
|
||||
|
||||
private:
|
||||
//! Pointer to the implementation
|
||||
implementation* m_pImpl;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor. Creates a UDP socket-based backend with <tt>syslog::user</tt> facility code.
|
||||
* IPv4 protocol will be used.
|
||||
*/
|
||||
BOOST_LOG_API syslog_backend();
|
||||
/*!
|
||||
* Constructor. Creates a sink backend with the specified named parameters.
|
||||
* The following named parameters are supported:
|
||||
*
|
||||
* \li \c facility - Specifies the facility code. If not specified, <tt>syslog::user</tt> will be used.
|
||||
* \li \c use_impl - Specifies the backend implementation. Can be one of:
|
||||
* \li \c native - Use the native syslog API, if available. If no native API
|
||||
* is available, it is equivalent to \c udp_socket_based.
|
||||
* \li \c udp_socket_based - Use the UDP socket-based implementation, conforming to
|
||||
* RFC3164 protocol specification. This is the default.
|
||||
* \li \c ip_version - Specifies IP protocol version to use, in case if socket-based implementation
|
||||
* is used. Can be either \c v4 (the default one) or \c v6.
|
||||
* \li \c ident - Process identification string. This parameter is only supported by native syslog implementation.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(syslog_backend, construct)
|
||||
#else
|
||||
template< typename... ArgsT >
|
||||
explicit syslog_backend(ArgsT... const& args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
BOOST_LOG_API ~syslog_backend();
|
||||
|
||||
/*!
|
||||
* The method installs the function object that maps application severity levels to syslog levels
|
||||
*/
|
||||
BOOST_LOG_API void set_severity_mapper(severity_mapper_type const& mapper);
|
||||
|
||||
#if !defined(BOOST_LOG_NO_ASIO)
|
||||
|
||||
/*!
|
||||
* The method sets the local host name which log records will be sent from. The host name
|
||||
* is resolved to obtain the final IP address.
|
||||
*
|
||||
* \note Does not have effect if the backend was constructed to use native syslog API
|
||||
*
|
||||
* \param addr The local address
|
||||
* \param port The local port number
|
||||
*/
|
||||
BOOST_LOG_API void set_local_address(std::string const& addr, unsigned short port = 514);
|
||||
/*!
|
||||
* The method sets the local address which log records will be sent from.
|
||||
*
|
||||
* \note Does not have effect if the backend was constructed to use native syslog API
|
||||
*
|
||||
* \param addr The local address
|
||||
* \param port The local port number
|
||||
*/
|
||||
BOOST_LOG_API void set_local_address(boost::asio::ip::address const& addr, unsigned short port = 514);
|
||||
|
||||
/*!
|
||||
* The method sets the remote host name where log records will be sent to. The host name
|
||||
* is resolved to obtain the final IP address.
|
||||
*
|
||||
* \note Does not have effect if the backend was constructed to use native syslog API
|
||||
*
|
||||
* \param addr The remote host address
|
||||
* \param port The port number on the remote host
|
||||
*/
|
||||
BOOST_LOG_API void set_target_address(std::string const& addr, unsigned short port = 514);
|
||||
/*!
|
||||
* The method sets the address of the remote host where log records will be sent to.
|
||||
*
|
||||
* \note Does not have effect if the backend was constructed to use native syslog API
|
||||
*
|
||||
* \param addr The remote host address
|
||||
* \param port The port number on the remote host
|
||||
*/
|
||||
BOOST_LOG_API void set_target_address(boost::asio::ip::address const& addr, unsigned short port = 514);
|
||||
|
||||
#endif // !defined(BOOST_LOG_NO_ASIO)
|
||||
|
||||
/*!
|
||||
* The method passes the formatted message to the syslog API or sends to a syslog server
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! The method creates the backend implementation
|
||||
template< typename ArgsT >
|
||||
void construct(ArgsT const& args)
|
||||
{
|
||||
construct(
|
||||
args[keywords::facility | syslog::user],
|
||||
#if !defined(BOOST_LOG_NO_ASIO)
|
||||
args[keywords::use_impl | syslog::udp_socket_based],
|
||||
#else
|
||||
args[keywords::use_impl | syslog::native],
|
||||
#endif
|
||||
args[keywords::ip_version | v4],
|
||||
args[keywords::ident | std::string()]);
|
||||
}
|
||||
BOOST_LOG_API void construct(
|
||||
syslog::facility facility, syslog::impl_types use_impl, ip_versions ip_version, std::string const& ident);
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_WITHOUT_SYSLOG
|
||||
|
||||
#endif // BOOST_LOG_SINKS_SYSLOG_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 syslog_constants.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 08.01.2008
|
||||
*
|
||||
* The header contains definition of constants related to Syslog API. The constants can be
|
||||
* used in other places without the Syslog backend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_SYSLOG_CONSTANTS_HPP_INCLUDED_HPP_
|
||||
#define BOOST_LOG_SINKS_SYSLOG_CONSTANTS_HPP_INCLUDED_HPP_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_LOG_WITHOUT_SYSLOG
|
||||
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
namespace syslog {
|
||||
|
||||
//! Syslog record levels
|
||||
enum level
|
||||
{
|
||||
emergency = 0, //!< Equivalent to LOG_EMERG in syslog API
|
||||
alert = 1, //!< Equivalent to LOG_ALERT in syslog API
|
||||
critical = 2, //!< Equivalent to LOG_CRIT in syslog API
|
||||
error = 3, //!< Equivalent to LOG_ERROR in syslog API
|
||||
warning = 4, //!< Equivalent to LOG_WARNING in syslog API
|
||||
notice = 5, //!< Equivalent to LOG_NOTICE in syslog API
|
||||
info = 6, //!< Equivalent to LOG_INFO in syslog API
|
||||
debug = 7 //!< Equivalent to LOG_DEBUG in syslog API
|
||||
};
|
||||
|
||||
/*!
|
||||
* The function constructs log record level from an integer
|
||||
*/
|
||||
BOOST_LOG_API level make_level(int lev);
|
||||
|
||||
//! Syslog facility codes
|
||||
enum facility
|
||||
{
|
||||
kernel = 0 * 8, //!< Kernel messages
|
||||
user = 1 * 8, //!< User-level messages. Equivalent to LOG_USER in syslog API.
|
||||
mail = 2 * 8, //!< Mail system messages. Equivalent to LOG_MAIL in syslog API.
|
||||
daemon = 3 * 8, //!< System daemons. Equivalent to LOG_DAEMON in syslog API.
|
||||
security0 = 4 * 8, //!< Security/authorization messages
|
||||
syslogd = 5 * 8, //!< Messages from the syslogd daemon. Equivalent to LOG_SYSLOG in syslog API.
|
||||
printer = 6 * 8, //!< Line printer subsystem. Equivalent to LOG_LPR in syslog API.
|
||||
news = 7 * 8, //!< Network news subsystem. Equivalent to LOG_NEWS in syslog API.
|
||||
uucp = 8 * 8, //!< Messages from UUCP subsystem. Equivalent to LOG_UUCP in syslog API.
|
||||
clock0 = 9 * 8, //!< Messages from the clock daemon
|
||||
security1 = 10 * 8, //!< Security/authorization messages
|
||||
ftp = 11 * 8, //!< Messages from FTP daemon
|
||||
ntp = 12 * 8, //!< Messages from NTP daemon
|
||||
log_audit = 13 * 8, //!< Security/authorization messages
|
||||
log_alert = 14 * 8, //!< Security/authorization messages
|
||||
clock1 = 15 * 8, //!< Messages from the clock daemon
|
||||
local0 = 16 * 8, //!< For local use. Equivalent to LOG_LOCAL0 in syslog API
|
||||
local1 = 17 * 8, //!< For local use. Equivalent to LOG_LOCAL1 in syslog API
|
||||
local2 = 18 * 8, //!< For local use. Equivalent to LOG_LOCAL2 in syslog API
|
||||
local3 = 19 * 8, //!< For local use. Equivalent to LOG_LOCAL3 in syslog API
|
||||
local4 = 20 * 8, //!< For local use. Equivalent to LOG_LOCAL4 in syslog API
|
||||
local5 = 21 * 8, //!< For local use. Equivalent to LOG_LOCAL5 in syslog API
|
||||
local6 = 22 * 8, //!< For local use. Equivalent to LOG_LOCAL6 in syslog API
|
||||
local7 = 23 * 8 //!< For local use. Equivalent to LOG_LOCAL7 in syslog API
|
||||
};
|
||||
|
||||
/*!
|
||||
* The function constructs log source facility from an integer
|
||||
*/
|
||||
BOOST_LOG_API facility make_facility(int fac);
|
||||
|
||||
} // namespace syslog
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_WITHOUT_SYSLOG
|
||||
|
||||
#endif // BOOST_LOG_SINKS_SYSLOG_CONSTANTS_HPP_INCLUDED_HPP_
|
||||
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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_file_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 09.06.2009
|
||||
*
|
||||
* The header contains implementation of a text file sink backend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <ostream>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/date_time/date_defs.hpp>
|
||||
#include <boost/date_time/special_defs.hpp>
|
||||
#include <boost/date_time/gregorian/greg_day.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/keywords/max_size.hpp>
|
||||
#include <boost/log/keywords/max_files.hpp>
|
||||
#include <boost/log/keywords/min_free_space.hpp>
|
||||
#include <boost/log/keywords/target.hpp>
|
||||
#include <boost/log/keywords/file_name.hpp>
|
||||
#include <boost/log/keywords/open_mode.hpp>
|
||||
#include <boost/log/keywords/auto_flush.hpp>
|
||||
#include <boost/log/keywords/rotation_size.hpp>
|
||||
#include <boost/log/keywords/time_based_rotation.hpp>
|
||||
#include <boost/log/keywords/enable_final_rotation.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/light_function.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
namespace file {
|
||||
|
||||
//! The enumeration of the stored files scan methods
|
||||
enum scan_method
|
||||
{
|
||||
no_scan, //!< Don't scan for stored files
|
||||
scan_matching, //!< Scan for files with names matching the specified mask
|
||||
scan_all //!< Scan for all files in the directory
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Base class for file collectors
|
||||
*
|
||||
* All file collectors, supported by file sink backends, should inherit this class.
|
||||
*/
|
||||
struct BOOST_LOG_NO_VTABLE collector
|
||||
{
|
||||
/*!
|
||||
* Default constructor
|
||||
*/
|
||||
BOOST_DEFAULTED_FUNCTION(collector(), {})
|
||||
|
||||
/*!
|
||||
* Virtual destructor
|
||||
*/
|
||||
virtual ~collector() {}
|
||||
|
||||
/*!
|
||||
* The function stores the specified file in the storage. May lead to an older file
|
||||
* deletion and a long file moving.
|
||||
*
|
||||
* \param src_path The name of the file to be stored
|
||||
*/
|
||||
virtual void store_file(filesystem::path const& src_path) = 0;
|
||||
|
||||
/*!
|
||||
* Scans the target directory for the files that have already been stored. The found
|
||||
* files are added to the collector in order to be tracked and erased, if needed.
|
||||
*
|
||||
* The function may scan the directory in two ways: it will either consider every
|
||||
* file in the directory a log file, or will only consider files with names that
|
||||
* match the specified pattern. The pattern may contain the following placeholders:
|
||||
*
|
||||
* \li %y, %Y, %m, %d - date components, in Boost.DateTime meaning.
|
||||
* \li %H, %M, %S, %f - time components, in Boost.DateTime meaning.
|
||||
* \li %N - numeric file counter. May also contain width specification
|
||||
* in printf-compatible form (e.g. %5N). The resulting number will always be zero-filled.
|
||||
* \li %% - a percent sign
|
||||
*
|
||||
* All other placeholders are not supported.
|
||||
*
|
||||
* \param method The method of scanning. If \c no_scan is specified, the call has no effect.
|
||||
* \param pattern The file name pattern if \a method is \c scan_matching. Otherwise the parameter
|
||||
* is not used.
|
||||
* \param counter If not \c NULL and \a method is \c scan_matching, the method suggests initial value
|
||||
* of a file counter that may be used in the file name pattern. The parameter
|
||||
* is not used otherwise.
|
||||
* \return The number of found files.
|
||||
*
|
||||
* \note In case if \a method is \c scan_matching the effect of this function is highly dependent
|
||||
* on the \a pattern definition. It is recommended to choose patterns with easily
|
||||
* distinguished placeholders (i.e. having delimiters between them). Otherwise
|
||||
* either some files can be mistakenly found or not found, which in turn may lead
|
||||
* to an incorrect file deletion.
|
||||
*/
|
||||
virtual uintmax_t scan_for_files(
|
||||
scan_method method, filesystem::path const& pattern = filesystem::path(), unsigned int* counter = 0) = 0;
|
||||
|
||||
BOOST_DELETED_FUNCTION(collector(collector const&))
|
||||
BOOST_DELETED_FUNCTION(collector& operator= (collector const&))
|
||||
};
|
||||
|
||||
namespace aux {
|
||||
|
||||
//! Creates and returns a file collector with the specified parameters
|
||||
BOOST_LOG_API shared_ptr< collector > make_collector(
|
||||
filesystem::path const& target_dir,
|
||||
uintmax_t max_size,
|
||||
uintmax_t min_free_space,
|
||||
uintmax_t max_files = (std::numeric_limits< uintmax_t >::max)()
|
||||
);
|
||||
template< typename ArgsT >
|
||||
inline shared_ptr< collector > make_collector(ArgsT const& args)
|
||||
{
|
||||
return aux::make_collector(
|
||||
filesystem::path(args[keywords::target]),
|
||||
args[keywords::max_size | (std::numeric_limits< uintmax_t >::max)()],
|
||||
args[keywords::min_free_space | static_cast< uintmax_t >(0)],
|
||||
args[keywords::max_files | (std::numeric_limits< uintmax_t >::max)()]);
|
||||
}
|
||||
|
||||
} // namespace aux
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
template< typename T1 >
|
||||
inline shared_ptr< collector > make_collector(T1 const& a1)
|
||||
{
|
||||
return aux::make_collector(a1);
|
||||
}
|
||||
template< typename T1, typename T2 >
|
||||
inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2)
|
||||
{
|
||||
return aux::make_collector((a1, a2));
|
||||
}
|
||||
template< typename T1, typename T2, typename T3 >
|
||||
inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 const& a3)
|
||||
{
|
||||
return aux::make_collector((a1, a2, a3));
|
||||
}
|
||||
template< typename T1, typename T2, typename T3, typename T4 >
|
||||
inline shared_ptr< collector > make_collector(T1 const& a1, T2 const& a2, T3 const& a3, T4 const& a4)
|
||||
{
|
||||
return aux::make_collector((a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/*!
|
||||
* The function creates a file collector for the specified target directory.
|
||||
* Each target directory is managed by a single file collector, so if
|
||||
* this function is called several times for the same directory,
|
||||
* it will return a reference to the same file collector. It is safe
|
||||
* to use the same collector in different sinks, even in a multithreaded
|
||||
* application.
|
||||
*
|
||||
* One can specify certain restrictions for the stored files, such as
|
||||
* maximum total size or minimum free space left in the target directory.
|
||||
* If any of the specified restrictions is not met, the oldest stored file
|
||||
* is deleted. If the same collector is requested more than once with
|
||||
* different restrictions, the collector will act according to the most strict
|
||||
* combination of all specified restrictions.
|
||||
*
|
||||
* The following named parameters are supported:
|
||||
*
|
||||
* \li \c target - Specifies the target directory for the files being stored in. This parameter
|
||||
* is mandatory.
|
||||
* \li \c max_size - Specifies the maximum total size, in bytes, of stored files that the collector
|
||||
* will try not to exceed. If the size exceeds this threshold the oldest file(s) is
|
||||
* deleted to free space. Note that the threshold may be exceeded if the size of
|
||||
* individual files exceed the \c max_size value. The threshold is not maintained,
|
||||
* if not specified.
|
||||
* \li \c min_free_space - Specifies the minimum free space, in bytes, in the target directory that
|
||||
* the collector tries to maintain. If the threshold is exceeded, the oldest
|
||||
* file(s) is deleted to free space. The threshold is not maintained, if not
|
||||
* specified.
|
||||
* \li \c max_files - Specifies the maximum number of log files stored. If the number of files exceeds
|
||||
* this threshold, the oldest file(s) is deleted to free space. The threshhold is
|
||||
* not maintained if not specified.
|
||||
*
|
||||
* \return The file collector.
|
||||
*/
|
||||
template< typename... ArgsT >
|
||||
shared_ptr< collector > make_collector(ArgsT... const& args);
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* The class represents the time point of log file rotation. One can specify one of three
|
||||
* types of time point based rotation:
|
||||
*
|
||||
* \li rotation takes place every day, at the specified time
|
||||
* \li rotation takes place on the specified day of every week, at the specified time
|
||||
* \li rotation takes place on the specified day of every month, at the specified time
|
||||
*
|
||||
* The time points are considered to be local time.
|
||||
*/
|
||||
class rotation_at_time_point
|
||||
{
|
||||
public:
|
||||
typedef bool result_type;
|
||||
|
||||
private:
|
||||
enum day_kind
|
||||
{
|
||||
not_specified,
|
||||
weekday,
|
||||
monthday
|
||||
};
|
||||
|
||||
day_kind m_DayKind : 2;
|
||||
unsigned char m_Day : 6;
|
||||
unsigned char m_Hour, m_Minute, m_Second;
|
||||
|
||||
mutable posix_time::ptime m_Previous;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Creates a rotation time point of every day at the specified time
|
||||
*
|
||||
* \param hour The rotation hour, should be within 0 and 23
|
||||
* \param minute The rotation minute, should be within 0 and 59
|
||||
* \param second The rotation second, should be within 0 and 59
|
||||
*/
|
||||
BOOST_LOG_API explicit rotation_at_time_point(unsigned char hour, unsigned char minute, unsigned char second);
|
||||
|
||||
/*!
|
||||
* Creates a rotation time point of each specified weekday at the specified time
|
||||
*
|
||||
* \param wday The weekday of the rotation
|
||||
* \param hour The rotation hour, should be within 0 and 23
|
||||
* \param minute The rotation minute, should be within 0 and 59
|
||||
* \param second The rotation second, should be within 0 and 59
|
||||
*/
|
||||
BOOST_LOG_API explicit rotation_at_time_point(
|
||||
date_time::weekdays wday,
|
||||
unsigned char hour = 0,
|
||||
unsigned char minute = 0,
|
||||
unsigned char second = 0);
|
||||
|
||||
/*!
|
||||
* Creates a rotation time point of each specified day of month at the specified time
|
||||
*
|
||||
* \param mday The monthday of the rotation, should be within 1 and 31
|
||||
* \param hour The rotation hour, should be within 0 and 23
|
||||
* \param minute The rotation minute, should be within 0 and 59
|
||||
* \param second The rotation second, should be within 0 and 59
|
||||
*/
|
||||
BOOST_LOG_API explicit rotation_at_time_point(
|
||||
gregorian::greg_day mday,
|
||||
unsigned char hour = 0,
|
||||
unsigned char minute = 0,
|
||||
unsigned char second = 0);
|
||||
|
||||
/*!
|
||||
* Checks if it's time to rotate the file
|
||||
*/
|
||||
BOOST_LOG_API bool operator() () const;
|
||||
};
|
||||
|
||||
/*!
|
||||
* The class represents the time interval of log file rotation. The log file will be rotated
|
||||
* after the specified time interval has passed.
|
||||
*/
|
||||
class rotation_at_time_interval
|
||||
{
|
||||
public:
|
||||
typedef bool result_type;
|
||||
|
||||
private:
|
||||
posix_time::time_duration m_Interval;
|
||||
mutable posix_time::ptime m_Previous;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Creates a rotation time interval of the specified duration
|
||||
*
|
||||
* \param interval The interval of the rotation, should be no less than 1 second
|
||||
*/
|
||||
explicit rotation_at_time_interval(posix_time::time_duration const& interval) :
|
||||
m_Interval(interval)
|
||||
{
|
||||
BOOST_ASSERT(!interval.is_special());
|
||||
BOOST_ASSERT(interval.total_seconds() > 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Checks if it's time to rotate the file
|
||||
*/
|
||||
BOOST_LOG_API bool operator() () const;
|
||||
};
|
||||
|
||||
} // namespace file
|
||||
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a text file logging sink backend
|
||||
*
|
||||
* The sink backend puts formatted log records to a text file.
|
||||
* The sink supports file rotation and advanced file control, such as
|
||||
* size and file count restriction.
|
||||
*/
|
||||
class text_file_backend :
|
||||
public basic_formatted_sink_backend<
|
||||
char,
|
||||
combine_requirements< synchronized_feeding, flushing >::type
|
||||
>
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend<
|
||||
char,
|
||||
combine_requirements< synchronized_feeding, flushing >::type
|
||||
> 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;
|
||||
//! Stream type
|
||||
typedef std::basic_ostream< char_type > stream_type;
|
||||
|
||||
//! File open handler
|
||||
typedef boost::log::aux::light_function< void (stream_type&) > open_handler_type;
|
||||
//! File close handler
|
||||
typedef boost::log::aux::light_function< void (stream_type&) > close_handler_type;
|
||||
|
||||
//! Predicate that defines the time-based condition for file rotation
|
||||
typedef boost::log::aux::light_function< bool () > time_based_rotation_predicate;
|
||||
|
||||
private:
|
||||
//! \cond
|
||||
|
||||
struct implementation;
|
||||
implementation* m_pImpl;
|
||||
|
||||
//! \endcond
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. The constructed sink backend uses default values of all the parameters.
|
||||
*/
|
||||
BOOST_LOG_API text_file_backend();
|
||||
|
||||
/*!
|
||||
* Constructor. Creates a sink backend with the specified named parameters.
|
||||
* The following named parameters are supported:
|
||||
*
|
||||
* \li \c file_name - Specifies the file name pattern where logs are actually written to. The pattern may
|
||||
* contain directory and file name portions, but only the file name may contain
|
||||
* placeholders. The backend supports Boost.DateTime placeholders for injecting
|
||||
* current time and date into the file name. Also, an additional %N placeholder is
|
||||
* supported, it will be replaced with an integral increasing file counter. The placeholder
|
||||
* may also contain width specification in the printf-compatible form (e.g. %5N). The
|
||||
* printed file counter will always be zero-filled. If \c file_name is not specified,
|
||||
* pattern "%5N.log" will be used.
|
||||
* \li \c open_mode - File open mode. The mode should be presented in form of mask compatible to
|
||||
* <tt>std::ios_base::openmode</tt>. If not specified, <tt>trunc | out</tt> will be used.
|
||||
* \li \c rotation_size - Specifies the approximate size, in characters written, of the temporary file
|
||||
* upon which the file is passed to the file collector. Note the size does
|
||||
* not count any possible character conversions that may take place during
|
||||
* writing to the file. If not specified, the file won't be rotated upon reaching
|
||||
* any size.
|
||||
* \li \c time_based_rotation - Specifies the predicate for time-based file rotation.
|
||||
* No time-based file rotations will be performed, if not specified.
|
||||
* \li \c enable_final_rotation - Specifies a flag, whether or not perform log file rotation on
|
||||
* sink backend destruction. By default, is \c true.
|
||||
* \li \c auto_flush - Specifies a flag, whether or not to automatically flush the file after each
|
||||
* written log record. By default, is \c false.
|
||||
*
|
||||
* \note Read the caution note regarding file name pattern in the <tt>sinks::file::collector::scan_for_files</tt>
|
||||
* documentation.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(text_file_backend, construct)
|
||||
#else
|
||||
template< typename... ArgsT >
|
||||
explicit text_file_backend(ArgsT... const& args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
BOOST_LOG_API ~text_file_backend();
|
||||
|
||||
/*!
|
||||
* The method sets file name wildcard for the files being written. The wildcard supports
|
||||
* date and time injection into the file name.
|
||||
*
|
||||
* \param pattern The name pattern for the file being written.
|
||||
*/
|
||||
template< typename PathT >
|
||||
void set_file_name_pattern(PathT const& pattern)
|
||||
{
|
||||
set_file_name_pattern_internal(filesystem::path(pattern));
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method sets the file open mode
|
||||
*
|
||||
* \param mode File open mode
|
||||
*/
|
||||
BOOST_LOG_API void set_open_mode(std::ios_base::openmode mode);
|
||||
|
||||
/*!
|
||||
* The method sets the log file collector function. The function is called
|
||||
* on file rotation and is being passed the written file name.
|
||||
*
|
||||
* \param collector The file collector function object
|
||||
*/
|
||||
BOOST_LOG_API void set_file_collector(shared_ptr< file::collector > const& collector);
|
||||
|
||||
/*!
|
||||
* The method sets file opening handler. The handler will be called every time
|
||||
* the backend opens a new temporary file. The handler may write a header to the
|
||||
* opened file in order to maintain file validity.
|
||||
*
|
||||
* \param handler The file open handler function object
|
||||
*/
|
||||
BOOST_LOG_API void set_open_handler(open_handler_type const& handler);
|
||||
|
||||
/*!
|
||||
* The method sets file closing handler. The handler will be called every time
|
||||
* the backend closes a temporary file. The handler may write a footer to the
|
||||
* opened file in order to maintain file validity.
|
||||
*
|
||||
* \param handler The file close handler function object
|
||||
*/
|
||||
BOOST_LOG_API void set_close_handler(close_handler_type const& handler);
|
||||
|
||||
/*!
|
||||
* The method sets maximum file size. When the size is reached, file rotation is performed.
|
||||
*
|
||||
* \note The size does not count any possible character translations that may happen in
|
||||
* the underlying API. This may result in greater actual sizes of the written files.
|
||||
*
|
||||
* \param size The maximum file size, in characters.
|
||||
*/
|
||||
BOOST_LOG_API void set_rotation_size(uintmax_t size);
|
||||
|
||||
/*!
|
||||
* The method sets the predicate that defines the time-based condition for file rotation.
|
||||
*
|
||||
* \note The rotation always occurs on writing a log record, so the rotation is
|
||||
* not strictly bound to the specified condition.
|
||||
*
|
||||
* \param predicate The predicate that defines the time-based condition for file rotation.
|
||||
* If empty, no time-based rotation will take place.
|
||||
*/
|
||||
BOOST_LOG_API void set_time_based_rotation(time_based_rotation_predicate const& predicate);
|
||||
|
||||
/*!
|
||||
* The method allows to enable or disable log file rotation on sink destruction.
|
||||
*
|
||||
* By default the sink backend will rotate the log file, if it's been written to, on
|
||||
* destruction.
|
||||
*
|
||||
* \param enable The flag indicates whether the final rotation should be performed.
|
||||
*/
|
||||
BOOST_LOG_API void enable_final_rotation(bool enable);
|
||||
|
||||
/*!
|
||||
* Sets the flag to automatically flush write buffers of the file being written after each log record.
|
||||
*
|
||||
* \param enable The flag indicates whether the automatic buffer flush should be performed.
|
||||
*/
|
||||
BOOST_LOG_API void auto_flush(bool enable = true);
|
||||
|
||||
/*!
|
||||
* \return The name of the currently open log file. If no file is open, returns an empty path.
|
||||
*/
|
||||
BOOST_LOG_API filesystem::path get_current_file_name() const;
|
||||
|
||||
/*!
|
||||
* Performs scanning of the target directory for log files that may have been left from
|
||||
* previous runs of the application. The found files are considered by the file collector
|
||||
* as if they were rotated.
|
||||
*
|
||||
* The file scan can be performed in two ways: either all files in the target directory will
|
||||
* be considered as log files, or only those files that satisfy the file name pattern.
|
||||
* See documentation on <tt>sinks::file::collector::scan_for_files</tt> for more information.
|
||||
*
|
||||
* \pre File collector and the proper file name pattern have already been set.
|
||||
*
|
||||
* \param method File scanning method
|
||||
* \param update_counter If \c true and \a method is \c scan_matching, the method attempts
|
||||
* to update the internal file counter according to the found files. The counter
|
||||
* is unaffected otherwise.
|
||||
* \return The number of files found.
|
||||
*
|
||||
* \note The method essentially delegates to the same-named function of the file collector.
|
||||
*/
|
||||
BOOST_LOG_API uintmax_t scan_for_files(
|
||||
file::scan_method method = file::scan_matching, bool update_counter = true);
|
||||
|
||||
/*!
|
||||
* The method writes the message to the sink
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
|
||||
/*!
|
||||
* The method flushes the currently open log file
|
||||
*/
|
||||
BOOST_LOG_API void flush();
|
||||
|
||||
/*!
|
||||
* The method rotates the file
|
||||
*/
|
||||
BOOST_LOG_API void rotate_file();
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! Constructor implementation
|
||||
template< typename ArgsT >
|
||||
void construct(ArgsT const& args)
|
||||
{
|
||||
construct(
|
||||
filesystem::path(args[keywords::file_name | filesystem::path()]),
|
||||
args[keywords::open_mode | (std::ios_base::trunc | std::ios_base::out)],
|
||||
args[keywords::rotation_size | (std::numeric_limits< uintmax_t >::max)()],
|
||||
args[keywords::time_based_rotation | time_based_rotation_predicate()],
|
||||
args[keywords::auto_flush | false],
|
||||
args[keywords::enable_final_rotation | true]);
|
||||
}
|
||||
//! Constructor implementation
|
||||
BOOST_LOG_API void construct(
|
||||
filesystem::path const& pattern,
|
||||
std::ios_base::openmode mode,
|
||||
uintmax_t rotation_size,
|
||||
time_based_rotation_predicate const& time_based_rotation,
|
||||
bool auto_flush,
|
||||
bool enable_final_rotation);
|
||||
|
||||
//! The method sets file name mask
|
||||
BOOST_LOG_API void set_file_name_pattern_internal(filesystem::path const& pattern);
|
||||
|
||||
//! Closes the currently open file
|
||||
void close_file();
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_TEXT_FILE_BACKEND_HPP_INCLUDED_
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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 <limits>
|
||||
#include <string>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/move/core.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/comparison/equal.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/exceptions.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#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. <tt>stop_local()</tt>
|
||||
* can be used to have a blocked <tt>consume()</tt> call return and prevent future
|
||||
* calls to <tt>consume()</tt> 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 <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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_multifile_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 09.06.2009
|
||||
*
|
||||
* The header contains implementation of a text multi-file sink backend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_TEXT_MULTIFILE_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_TEXT_MULTIFILE_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <ostream>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/light_function.hpp>
|
||||
#include <boost/log/detail/cleanup_scope_guard.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/utility/formatting_ostream.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
namespace file {
|
||||
|
||||
/*!
|
||||
* An adapter class that allows to use regular formatters as file name generators.
|
||||
*/
|
||||
template< typename FormatterT >
|
||||
class file_name_composer_adapter
|
||||
{
|
||||
public:
|
||||
//! Functor result type
|
||||
typedef filesystem::path result_type;
|
||||
//! File name character type
|
||||
typedef result_type::string_type::value_type native_char_type;
|
||||
//! The adopted formatter type
|
||||
typedef FormatterT formatter_type;
|
||||
//! Formatting stream type
|
||||
typedef basic_formatting_ostream< native_char_type > stream_type;
|
||||
|
||||
private:
|
||||
//! The adopted formatter
|
||||
formatter_type m_Formatter;
|
||||
//! Formatted file name storage
|
||||
mutable result_type::string_type m_FileName;
|
||||
//! Formatting stream
|
||||
mutable stream_type m_FormattingStream;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Initializing constructor
|
||||
*/
|
||||
explicit file_name_composer_adapter(formatter_type const& formatter, std::locale const& loc = std::locale()) :
|
||||
m_Formatter(formatter),
|
||||
m_FormattingStream(m_FileName)
|
||||
{
|
||||
m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
m_FormattingStream.imbue(loc);
|
||||
}
|
||||
/*!
|
||||
* Copy constructor
|
||||
*/
|
||||
file_name_composer_adapter(file_name_composer_adapter const& that) :
|
||||
m_Formatter(that.m_Formatter),
|
||||
m_FormattingStream(m_FileName)
|
||||
{
|
||||
m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
|
||||
m_FormattingStream.imbue(that.m_FormattingStream.getloc());
|
||||
}
|
||||
/*!
|
||||
* Assignment
|
||||
*/
|
||||
file_name_composer_adapter& operator= (file_name_composer_adapter const& that)
|
||||
{
|
||||
m_Formatter = that.m_Formatter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* The operator generates a file name based on the log record
|
||||
*/
|
||||
result_type operator() (record_view const& rec) const
|
||||
{
|
||||
boost::log::aux::cleanup_guard< stream_type > cleanup1(m_FormattingStream);
|
||||
boost::log::aux::cleanup_guard< result_type::string_type > cleanup2(m_FileName);
|
||||
|
||||
m_Formatter(rec, m_FormattingStream);
|
||||
m_FormattingStream.flush();
|
||||
|
||||
return result_type(m_FileName);
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* The function adopts a log record formatter into a file name generator
|
||||
*
|
||||
* \param fmt The formatter function object to adopt
|
||||
* \param loc The locale to use to character code conversion and formatting
|
||||
*/
|
||||
template< typename FormatterT >
|
||||
inline file_name_composer_adapter< FormatterT > as_file_name_composer(
|
||||
FormatterT const& fmt, std::locale const& loc = std::locale())
|
||||
{
|
||||
return file_name_composer_adapter< FormatterT >(fmt, loc);
|
||||
}
|
||||
|
||||
} // namespace file
|
||||
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a text multiple files logging sink backend
|
||||
*
|
||||
* The sink backend puts formatted log records to one of the text files.
|
||||
* The particular file is chosen upon each record's attribute values, which allows
|
||||
* to distribute records into individual files or to group records related to
|
||||
* some entity or process in a separate file.
|
||||
*/
|
||||
class text_multifile_backend :
|
||||
public basic_formatted_sink_backend< char >
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend< char > 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;
|
||||
|
||||
//! File name composer functor type
|
||||
typedef boost::log::aux::light_function< filesystem::path (record_view const&) > file_name_composer_type;
|
||||
|
||||
private:
|
||||
//! \cond
|
||||
|
||||
struct implementation;
|
||||
implementation* m_pImpl;
|
||||
|
||||
//! \endcond
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. The constructed sink backend has no file name composer and
|
||||
* thus will not write any files.
|
||||
*/
|
||||
BOOST_LOG_API text_multifile_backend();
|
||||
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
BOOST_LOG_API ~text_multifile_backend();
|
||||
|
||||
/*!
|
||||
* The method sets file name composer functional object. Log record formatters are accepted, too.
|
||||
*
|
||||
* \param composer File name composer functor
|
||||
*/
|
||||
template< typename ComposerT >
|
||||
void set_file_name_composer(ComposerT const& composer)
|
||||
{
|
||||
set_file_name_composer_internal(composer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method writes the message to the sink
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
|
||||
private:
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
//! The method sets the file name composer
|
||||
BOOST_LOG_API void set_file_name_composer_internal(file_name_composer_type const& composer);
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_TEXT_MULTIFILE_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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_ostream_backend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 22.04.2007
|
||||
*
|
||||
* The header contains implementation of a text output stream sink backend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_TEXT_OSTREAM_BACKEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_TEXT_OSTREAM_BACKEND_HPP_INCLUDED_
|
||||
|
||||
#include <ostream>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/sinks/basic_sink_backend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief An implementation of a text output stream logging sink backend
|
||||
*
|
||||
* The sink backend puts formatted log records to one or more text streams.
|
||||
*/
|
||||
template< typename CharT >
|
||||
class basic_text_ostream_backend :
|
||||
public basic_formatted_sink_backend<
|
||||
CharT,
|
||||
combine_requirements< synchronized_feeding, flushing >::type
|
||||
>
|
||||
{
|
||||
//! Base type
|
||||
typedef basic_formatted_sink_backend<
|
||||
CharT,
|
||||
combine_requirements< synchronized_feeding, flushing >::type
|
||||
> base_type;
|
||||
|
||||
public:
|
||||
//! Character type
|
||||
typedef typename base_type::char_type char_type;
|
||||
//! String type to be used as a message text holder
|
||||
typedef typename base_type::string_type string_type;
|
||||
//! Output stream type
|
||||
typedef std::basic_ostream< char_type > stream_type;
|
||||
|
||||
private:
|
||||
//! \cond
|
||||
|
||||
struct implementation;
|
||||
implementation* m_pImpl;
|
||||
|
||||
//! \endcond
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Constructor. No streams attached to the constructed backend, auto flush feature disabled.
|
||||
*/
|
||||
BOOST_LOG_API basic_text_ostream_backend();
|
||||
/*!
|
||||
* Destructor
|
||||
*/
|
||||
BOOST_LOG_API ~basic_text_ostream_backend();
|
||||
|
||||
/*!
|
||||
* The method adds a new stream to the sink.
|
||||
*
|
||||
* \param strm Pointer to the stream. Must not be NULL.
|
||||
*/
|
||||
BOOST_LOG_API void add_stream(shared_ptr< stream_type > const& strm);
|
||||
/*!
|
||||
* The method removes a stream from the sink. If the stream is not attached to the sink,
|
||||
* the method has no effect.
|
||||
*
|
||||
* \param strm Pointer to the stream. Must not be NULL.
|
||||
*/
|
||||
BOOST_LOG_API void remove_stream(shared_ptr< stream_type > const& strm);
|
||||
|
||||
/*!
|
||||
* Sets the flag to automatically flush buffers of all attached streams after each log record
|
||||
*/
|
||||
BOOST_LOG_API void auto_flush(bool f = true);
|
||||
|
||||
/*!
|
||||
* The method writes the message to the sink
|
||||
*/
|
||||
BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message);
|
||||
|
||||
/*!
|
||||
* The method flushes the associated streams
|
||||
*/
|
||||
BOOST_LOG_API void flush();
|
||||
};
|
||||
|
||||
#ifdef BOOST_LOG_USE_CHAR
|
||||
typedef basic_text_ostream_backend< char > text_ostream_backend; //!< Convenience typedef for narrow-character logging
|
||||
#endif
|
||||
#ifdef BOOST_LOG_USE_WCHAR_T
|
||||
typedef basic_text_ostream_backend< wchar_t > wtext_ostream_backend; //!< Convenience typedef for wide-character logging
|
||||
#endif
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_TEXT_OSTREAM_BACKEND_HPP_INCLUDED_
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 unbounded_fifo_queue.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 24.07.2011
|
||||
*
|
||||
* The header contains implementation of unbounded FIFO queueing strategy for
|
||||
* the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: This header content is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <boost/memory_order.hpp>
|
||||
#include <boost/atomic/atomic.hpp>
|
||||
#include <boost/log/detail/event.hpp>
|
||||
#include <boost/log/detail/threadsafe_queue.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Unbounded FIFO log record queueing strategy
|
||||
*
|
||||
* The \c unbounded_fifo_queue class is intended to be used with
|
||||
* the \c asynchronous_sink frontend as a log record queueing strategy.
|
||||
*
|
||||
* This strategy implements the simplest logic of log record buffering between
|
||||
* threads: the queue has no limits and imposes no ordering over the queued
|
||||
* elements aside from the order in which they are enqueued.
|
||||
* Because of this the queue provides decent performance and scalability,
|
||||
* however if sink backends can't consume log records fast enough the queue
|
||||
* may grow uncontrollably. When this is an issue, it is recommended to
|
||||
* use one of the bounded strategies.
|
||||
*/
|
||||
class unbounded_fifo_queue
|
||||
{
|
||||
private:
|
||||
typedef boost::log::aux::threadsafe_queue< record_view > queue_type;
|
||||
|
||||
private:
|
||||
//! Thread-safe queue
|
||||
queue_type m_queue;
|
||||
//! Event object to block on
|
||||
boost::log::aux::event m_event;
|
||||
//! Interruption flag
|
||||
boost::atomic< bool > m_interruption_requested;
|
||||
|
||||
protected:
|
||||
//! Default constructor
|
||||
unbounded_fifo_queue() : m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
//! Initializing constructor
|
||||
template< typename ArgsT >
|
||||
explicit unbounded_fifo_queue(ArgsT const&) : m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! Enqueues log record to the queue
|
||||
void enqueue(record_view const& rec)
|
||||
{
|
||||
m_queue.push(rec);
|
||||
m_event.set_signalled();
|
||||
}
|
||||
|
||||
//! Attempts to enqueue log record to the queue
|
||||
bool try_enqueue(record_view const& rec)
|
||||
{
|
||||
// Assume the call never blocks
|
||||
enqueue(rec);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty
|
||||
bool try_dequeue_ready(record_view& rec)
|
||||
{
|
||||
return m_queue.try_pop(rec);
|
||||
}
|
||||
|
||||
//! Attempts to dequeue log record from the queue, does not block if the queue is empty
|
||||
bool try_dequeue(record_view& rec)
|
||||
{
|
||||
return m_queue.try_pop(rec);
|
||||
}
|
||||
|
||||
//! Dequeues log record from the queue, blocks if the queue is empty
|
||||
bool dequeue_ready(record_view& rec)
|
||||
{
|
||||
// Try the fast way first
|
||||
if (m_queue.try_pop(rec))
|
||||
return true;
|
||||
|
||||
// Ok, we probably have to wait for new records
|
||||
while (true)
|
||||
{
|
||||
m_event.wait();
|
||||
if (m_interruption_requested.exchange(false, boost::memory_order_acquire))
|
||||
return false;
|
||||
if (m_queue.try_pop(rec))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//! Wakes a thread possibly blocked in the \c dequeue method
|
||||
void interrupt_dequeue()
|
||||
{
|
||||
m_interruption_requested.store(true, boost::memory_order_release);
|
||||
m_event.set_signalled();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_UNBOUNDED_FIFO_QUEUE_HPP_INCLUDED_
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 unbounded_ordering_queue.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 24.07.2011
|
||||
*
|
||||
* The header contains implementation of unbounded ordering record queueing strategy for
|
||||
* the asynchronous sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_UNBOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_UNBOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
|
||||
#include <boost/log/detail/config.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_LOG_NO_THREADS)
|
||||
#error Boost.Log: This header content is only supported in multithreaded environment
|
||||
#endif
|
||||
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/log/detail/timestamp.hpp>
|
||||
#include <boost/log/detail/enqueued_record.hpp>
|
||||
#include <boost/log/keywords/order.hpp>
|
||||
#include <boost/log/keywords/ordering_window.hpp>
|
||||
#include <boost/log/core/record_view.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
/*!
|
||||
* \brief Unbounded ordering log record queueing strategy
|
||||
*
|
||||
* The \c unbounded_ordering_queue class is intended to be used with
|
||||
* the \c asynchronous_sink frontend as a log record queueing strategy.
|
||||
*
|
||||
* This strategy provides the following properties to the record queueing mechanism:
|
||||
*
|
||||
* \li The queue has no size limits.
|
||||
* \li The queue has a fixed latency window. This means that each log record put
|
||||
* into the queue will normally not be dequeued for a certain period of time.
|
||||
* \li The queue performs stable record ordering within the latency window.
|
||||
* The ordering predicate can be specified in the \c OrderT template parameter.
|
||||
*
|
||||
* Since this queue has no size limits, it may grow uncontrollably if sink backends
|
||||
* dequeue log records not fast enough. When this is an issue, it is recommended to
|
||||
* use one of the bounded strategies.
|
||||
*/
|
||||
template< typename OrderT >
|
||||
class unbounded_ordering_queue
|
||||
{
|
||||
private:
|
||||
typedef boost::mutex mutex_type;
|
||||
typedef sinks::aux::enqueued_record enqueued_record;
|
||||
|
||||
typedef std::priority_queue<
|
||||
enqueued_record,
|
||||
std::vector< enqueued_record >,
|
||||
enqueued_record::order< OrderT >
|
||||
> queue_type;
|
||||
|
||||
private:
|
||||
//! Ordering window duration, in milliseconds
|
||||
const uint64_t m_ordering_window;
|
||||
//! Synchronization mutex
|
||||
mutex_type m_mutex;
|
||||
//! Condition for blocking
|
||||
condition_variable m_cond;
|
||||
//! Thread-safe queue
|
||||
queue_type m_queue;
|
||||
//! Interruption flag
|
||||
bool m_interruption_requested;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Returns ordering window size specified during initialization
|
||||
*/
|
||||
posix_time::time_duration get_ordering_window() const
|
||||
{
|
||||
return posix_time::milliseconds(m_ordering_window);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Returns default ordering window size.
|
||||
* The default window size is specific to the operating system thread scheduling mechanism.
|
||||
*/
|
||||
static posix_time::time_duration get_default_ordering_window()
|
||||
{
|
||||
// The main idea behind this parameter is that the ordering window should be large enough
|
||||
// to allow the frontend to order records from different threads on an attribute
|
||||
// that contains system time. Thus this value should be:
|
||||
// * No less than the minimum time resolution quant that Boost.DateTime provides on the current OS.
|
||||
// For instance, on Windows it defaults to around 15-16 ms.
|
||||
// * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to
|
||||
// switch threads on any known OS. It can be tuned for other platforms as needed.
|
||||
return posix_time::milliseconds(30);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Initializing constructor
|
||||
template< typename ArgsT >
|
||||
explicit unbounded_ordering_queue(ArgsT const& args) :
|
||||
m_ordering_window(args[keywords::ordering_window || &unbounded_ordering_queue::get_default_ordering_window].total_milliseconds()),
|
||||
m_queue(args[keywords::order]),
|
||||
m_interruption_requested(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! Enqueues log record to the queue
|
||||
void enqueue(record_view const& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
enqueue_unlocked(rec);
|
||||
}
|
||||
|
||||
//! Attempts to enqueue log record to the queue
|
||||
bool try_enqueue(record_view const& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex, try_to_lock);
|
||||
if (lock.owns_lock())
|
||||
{
|
||||
enqueue_unlocked(rec);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue a log record ready for processing from the queue, does not block if no log records are ready to be processed
|
||||
bool try_dequeue_ready(record_view& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
if (!m_queue.empty())
|
||||
{
|
||||
const boost::log::aux::timestamp now = boost::log::aux::get_timestamp();
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window)
|
||||
{
|
||||
// We got a new element
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Attempts to dequeue log record from the queue, does not block.
|
||||
bool try_dequeue(record_view& rec)
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
if (!m_queue.empty())
|
||||
{
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Dequeues log record from the queue, blocks if no log records are ready to be processed
|
||||
bool dequeue_ready(record_view& rec)
|
||||
{
|
||||
unique_lock< mutex_type > lock(m_mutex);
|
||||
while (!m_interruption_requested)
|
||||
{
|
||||
if (!m_queue.empty())
|
||||
{
|
||||
const boost::log::aux::timestamp now = boost::log::aux::get_timestamp();
|
||||
enqueued_record const& elem = m_queue.top();
|
||||
const uint64_t difference = (now - elem.m_timestamp).milliseconds();
|
||||
if (difference >= m_ordering_window)
|
||||
{
|
||||
// We got a new element
|
||||
rec = elem.m_record;
|
||||
m_queue.pop();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait until the element becomes ready to be processed
|
||||
m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for an element to come
|
||||
m_cond.wait(lock);
|
||||
}
|
||||
}
|
||||
m_interruption_requested = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Wakes a thread possibly blocked in the \c dequeue method
|
||||
void interrupt_dequeue()
|
||||
{
|
||||
lock_guard< mutex_type > lock(m_mutex);
|
||||
m_interruption_requested = true;
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
//! Enqueues a log record
|
||||
void enqueue_unlocked(record_view const& rec)
|
||||
{
|
||||
const bool was_empty = m_queue.empty();
|
||||
m_queue.push(enqueued_record(rec));
|
||||
if (was_empty)
|
||||
m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_UNBOUNDED_ORDERING_QUEUE_HPP_INCLUDED_
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright Andrey Semashev 2007 - 2015.
|
||||
* 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 unlocked_frontend.hpp
|
||||
* \author Andrey Semashev
|
||||
* \date 14.07.2009
|
||||
*
|
||||
* The header contains declaration of an unlocked sink frontend.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_LOG_SINKS_UNLOCKED_FRONTEND_HPP_INCLUDED_
|
||||
#define BOOST_LOG_SINKS_UNLOCKED_FRONTEND_HPP_INCLUDED_
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared_object.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/comparison/equal.hpp>
|
||||
#include <boost/log/detail/config.hpp>
|
||||
#include <boost/log/detail/parameter_tools.hpp>
|
||||
#include <boost/log/detail/fake_mutex.hpp>
|
||||
#include <boost/log/sinks/basic_sink_frontend.hpp>
|
||||
#include <boost/log/sinks/frontend_requirements.hpp>
|
||||
#include <boost/log/detail/header.hpp>
|
||||
|
||||
#ifdef BOOST_HAS_PRAGMA_ONCE
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
BOOST_LOG_OPEN_NAMESPACE
|
||||
|
||||
namespace sinks {
|
||||
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\
|
||||
template< typename T0 >\
|
||||
explicit unlocked_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\
|
||||
base_type(false),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\
|
||||
template< BOOST_PP_ENUM_PARAMS(n, typename T) >\
|
||||
explicit unlocked_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\
|
||||
base_type(false),\
|
||||
m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {}
|
||||
|
||||
#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\
|
||||
BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data)
|
||||
|
||||
#endif // BOOST_LOG_DOXYGEN_PASS
|
||||
|
||||
/*!
|
||||
* \brief Non-blocking logging sink frontend
|
||||
*
|
||||
* The sink frontend does not perform thread synchronization and
|
||||
* simply passes logging records to the sink backend.
|
||||
*/
|
||||
template< typename SinkBackendT >
|
||||
class unlocked_sink :
|
||||
public aux::make_sink_frontend_base< SinkBackendT >::type
|
||||
{
|
||||
typedef typename aux::make_sink_frontend_base< SinkBackendT >::type base_type;
|
||||
|
||||
public:
|
||||
//! Sink implementation type
|
||||
typedef SinkBackendT sink_backend_type;
|
||||
//! \cond
|
||||
BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, concurrent_feeding >::value), "Unlocked sink frontend is incompatible with the specified backend: thread synchronization requirements are not met");
|
||||
//! \endcond
|
||||
|
||||
//! Type of pointer to the backend
|
||||
typedef shared_ptr< sink_backend_type > locked_backend_ptr;
|
||||
|
||||
private:
|
||||
//! Pointer to the backend
|
||||
const shared_ptr< sink_backend_type > m_pBackend;
|
||||
|
||||
public:
|
||||
/*!
|
||||
* Default constructor. Constructs the sink backend instance.
|
||||
* Requires the backend to be default-constructible.
|
||||
*/
|
||||
unlocked_sink() :
|
||||
base_type(false),
|
||||
m_pBackend(boost::make_shared< sink_backend_type >())
|
||||
{
|
||||
}
|
||||
/*!
|
||||
* Constructor attaches user-constructed backend instance
|
||||
*
|
||||
* \param backend Pointer to the backend instance
|
||||
*
|
||||
* \pre \a backend is not \c NULL.
|
||||
*/
|
||||
explicit unlocked_sink(shared_ptr< sink_backend_type > const& backend) :
|
||||
base_type(false),
|
||||
m_pBackend(backend)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* Constructor that passes arbitrary named parameters to the interprocess sink backend constructor.
|
||||
* Refer to the backend documentation for the list of supported parameters.
|
||||
*/
|
||||
#ifndef BOOST_LOG_DOXYGEN_PASS
|
||||
BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~)
|
||||
#else
|
||||
template< typename... Args >
|
||||
explicit unlocked_sink(Args&&... args);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* Locking accessor to the attached backend.
|
||||
*
|
||||
* \note Does not do any actual locking, provided only for interface consistency
|
||||
* with other frontends.
|
||||
*/
|
||||
locked_backend_ptr locked_backend()
|
||||
{
|
||||
return m_pBackend;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Passes the log record to the backend
|
||||
*/
|
||||
void consume(record_view const& rec)
|
||||
{
|
||||
boost::log::aux::fake_mutex m;
|
||||
base_type::feed_record(rec, m, *m_pBackend);
|
||||
}
|
||||
|
||||
/*!
|
||||
* The method performs flushing of any internal buffers that may hold log records. The method
|
||||
* may take considerable time to complete and may block both the calling thread and threads
|
||||
* attempting to put new records into the sink while this call is in progress.
|
||||
*/
|
||||
void flush()
|
||||
{
|
||||
boost::log::aux::fake_mutex m;
|
||||
base_type::flush_backend(m, *m_pBackend);
|
||||
}
|
||||
};
|
||||
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N
|
||||
#undef BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL
|
||||
|
||||
} // namespace sinks
|
||||
|
||||
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/log/detail/footer.hpp>
|
||||
|
||||
#endif // BOOST_LOG_SINKS_UNLOCKED_FRONTEND_HPP_INCLUDED_
|
||||
Reference in New Issue
Block a user