annotate DEPENDENCIES/generic/include/boost/log/sinks/basic_sink_frontend.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 /*
Chris@101 2 * Copyright Andrey Semashev 2007 - 2015.
Chris@16 3 * Distributed under the Boost Software License, Version 1.0.
Chris@16 4 * (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 * http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6 */
Chris@16 7 /*!
Chris@16 8 * \file basic_sink_frontend.hpp
Chris@16 9 * \author Andrey Semashev
Chris@16 10 * \date 14.07.2009
Chris@16 11 *
Chris@16 12 * The header contains implementation of a base class for sink frontends.
Chris@16 13 */
Chris@16 14
Chris@16 15 #ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
Chris@16 16 #define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
Chris@16 17
Chris@16 18 #include <boost/mpl/bool.hpp>
Chris@16 19 #include <boost/log/detail/config.hpp>
Chris@16 20 #include <boost/log/detail/cleanup_scope_guard.hpp>
Chris@16 21 #include <boost/log/detail/code_conversion.hpp>
Chris@16 22 #include <boost/log/detail/attachable_sstream_buf.hpp>
Chris@16 23 #include <boost/log/detail/fake_mutex.hpp>
Chris@16 24 #include <boost/log/core/record_view.hpp>
Chris@16 25 #include <boost/log/sinks/sink.hpp>
Chris@16 26 #include <boost/log/sinks/frontend_requirements.hpp>
Chris@16 27 #include <boost/log/expressions/filter.hpp>
Chris@16 28 #include <boost/log/expressions/formatter.hpp>
Chris@16 29 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 30 #include <boost/thread/exceptions.hpp>
Chris@16 31 #include <boost/thread/tss.hpp>
Chris@16 32 #include <boost/thread/locks.hpp>
Chris@16 33 #include <boost/log/detail/locks.hpp>
Chris@16 34 #include <boost/log/detail/light_rw_mutex.hpp>
Chris@16 35 #endif // !defined(BOOST_LOG_NO_THREADS)
Chris@16 36 #include <boost/log/detail/header.hpp>
Chris@16 37
Chris@16 38 #ifdef BOOST_HAS_PRAGMA_ONCE
Chris@16 39 #pragma once
Chris@16 40 #endif
Chris@16 41
Chris@16 42 namespace boost {
Chris@16 43
Chris@16 44 BOOST_LOG_OPEN_NAMESPACE
Chris@16 45
Chris@16 46 namespace sinks {
Chris@16 47
Chris@16 48 //! A base class for a logging sink frontend
Chris@16 49 class BOOST_LOG_NO_VTABLE basic_sink_frontend :
Chris@16 50 public sink
Chris@16 51 {
Chris@16 52 //! Base type
Chris@16 53 typedef sink base_type;
Chris@16 54
Chris@16 55 public:
Chris@16 56 //! An exception handler type
Chris@16 57 typedef base_type::exception_handler_type exception_handler_type;
Chris@16 58
Chris@16 59 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 60 protected:
Chris@16 61 //! Mutex type
Chris@16 62 typedef boost::log::aux::light_rw_mutex mutex_type;
Chris@16 63
Chris@16 64 private:
Chris@16 65 //! Synchronization mutex
Chris@16 66 mutable mutex_type m_Mutex;
Chris@16 67 #endif
Chris@16 68
Chris@16 69 private:
Chris@16 70 //! Filter
Chris@16 71 filter m_Filter;
Chris@16 72 //! Exception handler
Chris@16 73 exception_handler_type m_ExceptionHandler;
Chris@16 74
Chris@16 75 public:
Chris@16 76 /*!
Chris@16 77 * \brief Initializing constructor
Chris@16 78 *
Chris@16 79 * \param cross_thread The flag indicates whether the sink passes log records between different threads
Chris@16 80 */
Chris@16 81 explicit basic_sink_frontend(bool cross_thread) : sink(cross_thread)
Chris@16 82 {
Chris@16 83 }
Chris@16 84
Chris@16 85 /*!
Chris@16 86 * The method sets sink-specific filter functional object
Chris@16 87 */
Chris@16 88 template< typename FunT >
Chris@16 89 void set_filter(FunT const& filter)
Chris@16 90 {
Chris@16 91 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 92 m_Filter = filter;
Chris@16 93 }
Chris@16 94 /*!
Chris@16 95 * The method resets the filter
Chris@16 96 */
Chris@16 97 void reset_filter()
Chris@16 98 {
Chris@16 99 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 100 m_Filter.reset();
Chris@16 101 }
Chris@16 102
Chris@16 103 /*!
Chris@16 104 * The method sets an exception handler function
Chris@16 105 */
Chris@16 106 template< typename FunT >
Chris@16 107 void set_exception_handler(FunT const& handler)
Chris@16 108 {
Chris@16 109 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 110 m_ExceptionHandler = handler;
Chris@16 111 }
Chris@16 112
Chris@16 113 /*!
Chris@16 114 * The method resets the exception handler function
Chris@16 115 */
Chris@16 116 void reset_exception_handler()
Chris@16 117 {
Chris@16 118 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 119 m_ExceptionHandler.clear();
Chris@16 120 }
Chris@16 121
Chris@16 122 /*!
Chris@16 123 * The method returns \c true if no filter is set or the attribute values pass the filter
Chris@16 124 *
Chris@16 125 * \param attrs A set of attribute values of a logging record
Chris@16 126 */
Chris@16 127 bool will_consume(attribute_value_set const& attrs)
Chris@16 128 {
Chris@16 129 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 130 try
Chris@16 131 {
Chris@16 132 return m_Filter(attrs);
Chris@16 133 }
Chris@16 134 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 135 catch (thread_interrupted&)
Chris@16 136 {
Chris@16 137 throw;
Chris@16 138 }
Chris@16 139 #endif
Chris@16 140 catch (...)
Chris@16 141 {
Chris@16 142 if (m_ExceptionHandler.empty())
Chris@16 143 throw;
Chris@16 144 m_ExceptionHandler();
Chris@16 145 return false;
Chris@16 146 }
Chris@16 147 }
Chris@16 148
Chris@16 149 protected:
Chris@16 150 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 151 //! Returns reference to the frontend mutex
Chris@16 152 mutex_type& frontend_mutex() const { return m_Mutex; }
Chris@16 153 #endif
Chris@16 154
Chris@16 155 //! Returns reference to the exception handler
Chris@16 156 exception_handler_type& exception_handler() { return m_ExceptionHandler; }
Chris@16 157 //! Returns reference to the exception handler
Chris@16 158 exception_handler_type const& exception_handler() const { return m_ExceptionHandler; }
Chris@16 159
Chris@16 160 //! Feeds log record to the backend
Chris@16 161 template< typename BackendMutexT, typename BackendT >
Chris@16 162 void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
Chris@16 163 {
Chris@16 164 try
Chris@16 165 {
Chris@16 166 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
Chris@16 167 backend.consume(rec);
Chris@16 168 }
Chris@16 169 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 170 catch (thread_interrupted&)
Chris@16 171 {
Chris@16 172 throw;
Chris@16 173 }
Chris@16 174 #endif
Chris@16 175 catch (...)
Chris@16 176 {
Chris@16 177 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 178 if (m_ExceptionHandler.empty())
Chris@16 179 throw;
Chris@16 180 m_ExceptionHandler();
Chris@16 181 }
Chris@16 182 }
Chris@16 183
Chris@16 184 //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
Chris@16 185 template< typename BackendMutexT, typename BackendT >
Chris@16 186 bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
Chris@16 187 {
Chris@16 188 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 189 unique_lock< BackendMutexT > lock;
Chris@16 190 try
Chris@16 191 {
Chris@16 192 unique_lock< BackendMutexT > tmp_lock(backend_mutex, try_to_lock);
Chris@16 193 if (!tmp_lock.owns_lock())
Chris@16 194 return false;
Chris@16 195 lock.swap(tmp_lock);
Chris@16 196 }
Chris@16 197 catch (thread_interrupted&)
Chris@16 198 {
Chris@16 199 throw;
Chris@16 200 }
Chris@16 201 catch (...)
Chris@16 202 {
Chris@16 203 boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
Chris@16 204 if (this->exception_handler().empty())
Chris@16 205 throw;
Chris@16 206 this->exception_handler()();
Chris@101 207 return false;
Chris@16 208 }
Chris@16 209 #endif
Chris@16 210 // No need to lock anything in the feed_record method
Chris@16 211 boost::log::aux::fake_mutex m;
Chris@16 212 feed_record(rec, m, backend);
Chris@16 213 return true;
Chris@16 214 }
Chris@16 215
Chris@16 216 //! Flushes record buffers in the backend, if one supports it
Chris@16 217 template< typename BackendMutexT, typename BackendT >
Chris@16 218 void flush_backend(BackendMutexT& backend_mutex, BackendT& backend)
Chris@16 219 {
Chris@16 220 typedef typename BackendT::frontend_requirements frontend_requirements;
Chris@16 221 flush_backend_impl(backend_mutex, backend,
Chris@16 222 typename has_requirement< frontend_requirements, flushing >::type());
Chris@16 223 }
Chris@16 224
Chris@16 225 private:
Chris@16 226 //! Flushes record buffers in the backend (the actual implementation)
Chris@16 227 template< typename BackendMutexT, typename BackendT >
Chris@16 228 void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, mpl::true_)
Chris@16 229 {
Chris@16 230 try
Chris@16 231 {
Chris@16 232 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
Chris@16 233 backend.flush();
Chris@16 234 }
Chris@16 235 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 236 catch (thread_interrupted&)
Chris@16 237 {
Chris@16 238 throw;
Chris@16 239 }
Chris@16 240 #endif
Chris@16 241 catch (...)
Chris@16 242 {
Chris@16 243 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
Chris@16 244 if (m_ExceptionHandler.empty())
Chris@16 245 throw;
Chris@16 246 m_ExceptionHandler();
Chris@16 247 }
Chris@16 248 }
Chris@16 249 //! Flushes record buffers in the backend (stub for backends that don't support flushing)
Chris@16 250 template< typename BackendMutexT, typename BackendT >
Chris@16 251 void flush_backend_impl(BackendMutexT&, BackendT&, mpl::false_)
Chris@16 252 {
Chris@16 253 }
Chris@16 254 };
Chris@16 255
Chris@16 256 //! A base class for a logging sink frontend with formatting support
Chris@16 257 template< typename CharT >
Chris@16 258 class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend :
Chris@16 259 public basic_sink_frontend
Chris@16 260 {
Chris@16 261 typedef basic_sink_frontend base_type;
Chris@16 262
Chris@16 263 public:
Chris@16 264 //! Character type
Chris@16 265 typedef CharT char_type;
Chris@16 266 //! Formatted string type
Chris@16 267 typedef std::basic_string< char_type > string_type;
Chris@16 268
Chris@16 269 //! Formatter function object type
Chris@16 270 typedef basic_formatter< char_type > formatter_type;
Chris@16 271 //! Output stream type
Chris@16 272 typedef typename formatter_type::stream_type stream_type;
Chris@16 273
Chris@16 274 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 275 protected:
Chris@16 276 //! Mutex type
Chris@16 277 typedef typename base_type::mutex_type mutex_type;
Chris@16 278 #endif
Chris@16 279
Chris@16 280 private:
Chris@16 281 struct formatting_context
Chris@16 282 {
Chris@16 283 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 284 //! Object version
Chris@16 285 const unsigned int m_Version;
Chris@16 286 #endif
Chris@16 287 //! Formatted log record storage
Chris@16 288 string_type m_FormattedRecord;
Chris@16 289 //! Formatting stream
Chris@16 290 stream_type m_FormattingStream;
Chris@16 291 //! Formatter functor
Chris@16 292 formatter_type m_Formatter;
Chris@16 293
Chris@16 294 formatting_context() :
Chris@16 295 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 296 m_Version(0),
Chris@16 297 #endif
Chris@16 298 m_FormattingStream(m_FormattedRecord)
Chris@16 299 {
Chris@16 300 m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
Chris@16 301 }
Chris@16 302 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 303 formatting_context(unsigned int version, std::locale const& loc, formatter_type const& formatter) :
Chris@16 304 m_Version(version),
Chris@16 305 m_FormattingStream(m_FormattedRecord),
Chris@16 306 m_Formatter(formatter)
Chris@16 307 {
Chris@16 308 m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
Chris@16 309 m_FormattingStream.imbue(loc);
Chris@16 310 }
Chris@16 311 #endif
Chris@16 312 };
Chris@16 313
Chris@16 314 private:
Chris@16 315 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 316
Chris@16 317 //! State version
Chris@16 318 volatile unsigned int m_Version;
Chris@16 319
Chris@16 320 //! Formatter functor
Chris@16 321 formatter_type m_Formatter;
Chris@16 322 //! Locale to perform formatting
Chris@16 323 std::locale m_Locale;
Chris@16 324
Chris@16 325 //! Formatting state
Chris@16 326 thread_specific_ptr< formatting_context > m_pContext;
Chris@16 327
Chris@16 328 #else
Chris@16 329
Chris@16 330 //! Formatting state
Chris@16 331 formatting_context m_Context;
Chris@16 332
Chris@16 333 #endif // !defined(BOOST_LOG_NO_THREADS)
Chris@16 334
Chris@16 335 public:
Chris@16 336 /*!
Chris@16 337 * \brief Initializing constructor
Chris@16 338 *
Chris@16 339 * \param cross_thread The flag indicates whether the sink passes log records between different threads
Chris@16 340 */
Chris@16 341 explicit basic_formatting_sink_frontend(bool cross_thread) :
Chris@16 342 basic_sink_frontend(cross_thread)
Chris@16 343 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 344 , m_Version(0)
Chris@16 345 #endif
Chris@16 346 {
Chris@16 347 }
Chris@16 348
Chris@16 349 /*!
Chris@16 350 * The method sets sink-specific formatter function object
Chris@16 351 */
Chris@16 352 template< typename FunT >
Chris@16 353 void set_formatter(FunT const& formatter)
Chris@16 354 {
Chris@16 355 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 356 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
Chris@16 357 m_Formatter = formatter;
Chris@16 358 ++m_Version;
Chris@16 359 #else
Chris@16 360 m_Context.m_Formatter = formatter;
Chris@16 361 #endif
Chris@16 362 }
Chris@16 363 /*!
Chris@16 364 * The method resets the formatter
Chris@16 365 */
Chris@16 366 void reset_formatter()
Chris@16 367 {
Chris@16 368 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 369 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
Chris@16 370 m_Formatter.reset();
Chris@16 371 ++m_Version;
Chris@16 372 #else
Chris@16 373 m_Context.m_Formatter.reset();
Chris@16 374 #endif
Chris@16 375 }
Chris@16 376
Chris@16 377 /*!
Chris@16 378 * The method returns the current locale used for formatting
Chris@16 379 */
Chris@16 380 std::locale getloc() const
Chris@16 381 {
Chris@16 382 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 383 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
Chris@16 384 return m_Locale;
Chris@16 385 #else
Chris@16 386 return m_Context.m_FormattingStream.getloc();
Chris@16 387 #endif
Chris@16 388 }
Chris@16 389 /*!
Chris@16 390 * The method sets the locale used for formatting
Chris@16 391 */
Chris@16 392 void imbue(std::locale const& loc)
Chris@16 393 {
Chris@16 394 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 395 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
Chris@16 396 m_Locale = loc;
Chris@16 397 ++m_Version;
Chris@16 398 #else
Chris@16 399 m_Context.m_FormattingStream.imbue(loc);
Chris@16 400 #endif
Chris@16 401 }
Chris@16 402
Chris@16 403 protected:
Chris@16 404 //! Returns reference to the formatter
Chris@16 405 formatter_type& formatter()
Chris@16 406 {
Chris@16 407 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 408 return m_Formatter;
Chris@16 409 #else
Chris@16 410 return m_Context.m_Formatter;
Chris@16 411 #endif
Chris@16 412 }
Chris@16 413
Chris@16 414 //! Feeds log record to the backend
Chris@16 415 template< typename BackendMutexT, typename BackendT >
Chris@16 416 void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
Chris@16 417 {
Chris@16 418 formatting_context* context;
Chris@16 419
Chris@16 420 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 421 context = m_pContext.get();
Chris@16 422 if (!context || context->m_Version != m_Version)
Chris@16 423 {
Chris@16 424 {
Chris@16 425 boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());
Chris@16 426 context = new formatting_context(m_Version, m_Locale, m_Formatter);
Chris@16 427 }
Chris@16 428 m_pContext.reset(context);
Chris@16 429 }
Chris@16 430 #else
Chris@16 431 context = &m_Context;
Chris@16 432 #endif
Chris@16 433
Chris@16 434 boost::log::aux::cleanup_guard< stream_type > cleanup1(context->m_FormattingStream);
Chris@16 435 boost::log::aux::cleanup_guard< string_type > cleanup2(context->m_FormattedRecord);
Chris@16 436
Chris@16 437 try
Chris@16 438 {
Chris@16 439 // Perform the formatting
Chris@16 440 context->m_Formatter(rec, context->m_FormattingStream);
Chris@16 441 context->m_FormattingStream.flush();
Chris@16 442
Chris@16 443 // Feed the record
Chris@16 444 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
Chris@16 445 backend.consume(rec, context->m_FormattedRecord);
Chris@16 446 }
Chris@16 447 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 448 catch (thread_interrupted&)
Chris@16 449 {
Chris@16 450 throw;
Chris@16 451 }
Chris@16 452 #endif
Chris@16 453 catch (...)
Chris@16 454 {
Chris@16 455 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());)
Chris@16 456 if (this->exception_handler().empty())
Chris@16 457 throw;
Chris@16 458 this->exception_handler()();
Chris@16 459 }
Chris@16 460 }
Chris@16 461
Chris@16 462 //! Attempts to feeds log record to the backend, does not block if \a backend_mutex is locked
Chris@16 463 template< typename BackendMutexT, typename BackendT >
Chris@16 464 bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
Chris@16 465 {
Chris@16 466 #if !defined(BOOST_LOG_NO_THREADS)
Chris@16 467 unique_lock< BackendMutexT > lock;
Chris@16 468 try
Chris@16 469 {
Chris@16 470 unique_lock< BackendMutexT > tmp_lock(backend_mutex, try_to_lock);
Chris@16 471 if (!tmp_lock.owns_lock())
Chris@16 472 return false;
Chris@16 473 lock.swap(tmp_lock);
Chris@16 474 }
Chris@16 475 catch (thread_interrupted&)
Chris@16 476 {
Chris@16 477 throw;
Chris@16 478 }
Chris@16 479 catch (...)
Chris@16 480 {
Chris@16 481 boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
Chris@16 482 if (this->exception_handler().empty())
Chris@16 483 throw;
Chris@16 484 this->exception_handler()();
Chris@101 485 return false;
Chris@16 486 }
Chris@16 487 #endif
Chris@16 488 // No need to lock anything in the feed_record method
Chris@16 489 boost::log::aux::fake_mutex m;
Chris@16 490 feed_record(rec, m, backend);
Chris@16 491 return true;
Chris@16 492 }
Chris@16 493 };
Chris@16 494
Chris@16 495 namespace aux {
Chris@16 496
Chris@16 497 template<
Chris@16 498 typename BackendT,
Chris@16 499 bool RequiresFormattingV = has_requirement<
Chris@16 500 typename BackendT::frontend_requirements,
Chris@16 501 formatted_records
Chris@16 502 >::value
Chris@16 503 >
Chris@16 504 struct make_sink_frontend_base
Chris@16 505 {
Chris@16 506 typedef basic_sink_frontend type;
Chris@16 507 };
Chris@16 508 template< typename BackendT >
Chris@16 509 struct make_sink_frontend_base< BackendT, true >
Chris@16 510 {
Chris@16 511 typedef basic_formatting_sink_frontend< typename BackendT::char_type > type;
Chris@16 512 };
Chris@16 513
Chris@16 514 } // namespace aux
Chris@16 515
Chris@16 516 } // namespace sinks
Chris@16 517
Chris@16 518 BOOST_LOG_CLOSE_NAMESPACE // namespace log
Chris@16 519
Chris@16 520 } // namespace boost
Chris@16 521
Chris@16 522 #include <boost/log/detail/footer.hpp>
Chris@16 523
Chris@16 524 #endif // BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_