stabilize build system: depends, installer, boost/bdb fixes, cross targets groundwork

This commit is contained in:
2026-02-24 18:38:47 +00:00
parent da8c28aaeb
commit 65cb2619a7
13106 changed files with 2484322 additions and 1804 deletions
@@ -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_
@@ -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_