File indexing completed on 2025-01-18 09:39:25
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
0016 #define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_
0017
0018 #include <boost/type_traits/integral_constant.hpp>
0019 #include <boost/log/detail/config.hpp>
0020 #include <boost/log/detail/code_conversion.hpp>
0021 #include <boost/log/detail/attachable_sstream_buf.hpp>
0022 #include <boost/log/detail/fake_mutex.hpp>
0023 #include <boost/log/core/record_view.hpp>
0024 #include <boost/log/sinks/sink.hpp>
0025 #include <boost/log/sinks/frontend_requirements.hpp>
0026 #include <boost/log/expressions/filter.hpp>
0027 #include <boost/log/expressions/formatter.hpp>
0028 #if !defined(BOOST_LOG_NO_THREADS)
0029 #include <boost/memory_order.hpp>
0030 #include <boost/atomic/atomic.hpp>
0031 #include <boost/thread/exceptions.hpp>
0032 #include <boost/thread/tss.hpp>
0033 #include <boost/log/detail/locks.hpp>
0034 #include <boost/log/detail/light_rw_mutex.hpp>
0035 #endif
0036 #include <boost/log/detail/header.hpp>
0037
0038 #ifdef BOOST_HAS_PRAGMA_ONCE
0039 #pragma once
0040 #endif
0041
0042 namespace boost {
0043
0044 BOOST_LOG_OPEN_NAMESPACE
0045
0046 namespace sinks {
0047
0048
0049 class BOOST_LOG_NO_VTABLE basic_sink_frontend :
0050 public sink
0051 {
0052
0053 typedef sink base_type;
0054
0055 public:
0056
0057 typedef base_type::exception_handler_type exception_handler_type;
0058
0059 #if !defined(BOOST_LOG_NO_THREADS)
0060 protected:
0061
0062 typedef boost::log::aux::light_rw_mutex mutex_type;
0063
0064 private:
0065
0066 mutable mutex_type m_Mutex;
0067 #endif
0068
0069 private:
0070
0071 filter m_Filter;
0072
0073 exception_handler_type m_ExceptionHandler;
0074
0075 public:
0076
0077
0078
0079
0080
0081 explicit basic_sink_frontend(bool cross_thread) : sink(cross_thread)
0082 {
0083 }
0084
0085
0086
0087
0088 template< typename FunT >
0089 void set_filter(FunT const& filter)
0090 {
0091 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0092 m_Filter = filter;
0093 }
0094
0095
0096
0097 void reset_filter()
0098 {
0099 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0100 m_Filter.reset();
0101 }
0102
0103
0104
0105
0106 template< typename FunT >
0107 void set_exception_handler(FunT const& handler)
0108 {
0109 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0110 m_ExceptionHandler = handler;
0111 }
0112
0113
0114
0115
0116 void reset_exception_handler()
0117 {
0118 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);)
0119 m_ExceptionHandler.clear();
0120 }
0121
0122
0123
0124
0125
0126
0127 bool will_consume(attribute_value_set const& attrs) BOOST_OVERRIDE
0128 {
0129 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0130 try
0131 {
0132 return m_Filter(attrs);
0133 }
0134 #if !defined(BOOST_LOG_NO_THREADS)
0135 catch (thread_interrupted&)
0136 {
0137 throw;
0138 }
0139 #endif
0140 catch (...)
0141 {
0142 if (m_ExceptionHandler.empty())
0143 throw;
0144 m_ExceptionHandler();
0145 return false;
0146 }
0147 }
0148
0149 protected:
0150 #if !defined(BOOST_LOG_NO_THREADS)
0151
0152 mutex_type& frontend_mutex() const { return m_Mutex; }
0153 #endif
0154
0155
0156 exception_handler_type& exception_handler() { return m_ExceptionHandler; }
0157
0158 exception_handler_type const& exception_handler() const { return m_ExceptionHandler; }
0159
0160
0161 template< typename BackendMutexT, typename BackendT >
0162 void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0163 {
0164 try
0165 {
0166 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0167 backend.consume(rec);
0168 }
0169 #if !defined(BOOST_LOG_NO_THREADS)
0170 catch (thread_interrupted&)
0171 {
0172 throw;
0173 }
0174 #endif
0175 catch (...)
0176 {
0177 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0178 if (m_ExceptionHandler.empty())
0179 throw;
0180 m_ExceptionHandler();
0181 }
0182 }
0183
0184
0185 template< typename BackendMutexT, typename BackendT >
0186 bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0187 {
0188 #if !defined(BOOST_LOG_NO_THREADS)
0189 try
0190 {
0191 if (!backend_mutex.try_lock())
0192 return false;
0193 }
0194 catch (thread_interrupted&)
0195 {
0196 throw;
0197 }
0198 catch (...)
0199 {
0200 boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
0201 if (this->exception_handler().empty())
0202 throw;
0203 this->exception_handler()();
0204 return false;
0205 }
0206
0207 boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
0208 #endif
0209
0210 boost::log::aux::fake_mutex m;
0211 feed_record(rec, m, backend);
0212 return true;
0213 }
0214
0215
0216 template< typename BackendMutexT, typename BackendT >
0217 void flush_backend(BackendMutexT& backend_mutex, BackendT& backend)
0218 {
0219 typedef typename BackendT::frontend_requirements frontend_requirements;
0220 flush_backend_impl(backend_mutex, backend,
0221 typename has_requirement< frontend_requirements, flushing >::type());
0222 }
0223
0224 private:
0225
0226 template< typename BackendMutexT, typename BackendT >
0227 void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, boost::true_type)
0228 {
0229 try
0230 {
0231 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0232 backend.flush();
0233 }
0234 #if !defined(BOOST_LOG_NO_THREADS)
0235 catch (thread_interrupted&)
0236 {
0237 throw;
0238 }
0239 #endif
0240 catch (...)
0241 {
0242 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);)
0243 if (m_ExceptionHandler.empty())
0244 throw;
0245 m_ExceptionHandler();
0246 }
0247 }
0248
0249 template< typename BackendMutexT, typename BackendT >
0250 void flush_backend_impl(BackendMutexT&, BackendT&, boost::false_type)
0251 {
0252 }
0253 };
0254
0255
0256 template< typename CharT >
0257 class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend :
0258 public basic_sink_frontend
0259 {
0260 typedef basic_sink_frontend base_type;
0261
0262 public:
0263
0264 typedef CharT char_type;
0265
0266 typedef std::basic_string< char_type > string_type;
0267
0268
0269 typedef basic_formatter< char_type > formatter_type;
0270
0271 typedef typename formatter_type::stream_type stream_type;
0272
0273 #if !defined(BOOST_LOG_NO_THREADS)
0274 protected:
0275
0276 typedef typename base_type::mutex_type mutex_type;
0277 #endif
0278
0279 private:
0280 struct formatting_context
0281 {
0282 class cleanup_guard
0283 {
0284 private:
0285 formatting_context& m_context;
0286
0287 public:
0288 explicit cleanup_guard(formatting_context& ctx) BOOST_NOEXCEPT : m_context(ctx)
0289 {
0290 }
0291
0292 ~cleanup_guard()
0293 {
0294 m_context.m_FormattedRecord.clear();
0295 m_context.m_FormattingStream.rdbuf()->max_size(m_context.m_FormattedRecord.max_size());
0296 m_context.m_FormattingStream.rdbuf()->storage_overflow(false);
0297 m_context.m_FormattingStream.clear();
0298 }
0299
0300 BOOST_DELETED_FUNCTION(cleanup_guard(cleanup_guard const&))
0301 BOOST_DELETED_FUNCTION(cleanup_guard& operator=(cleanup_guard const&))
0302 };
0303
0304 #if !defined(BOOST_LOG_NO_THREADS)
0305
0306 const unsigned int m_Version;
0307 #endif
0308
0309 string_type m_FormattedRecord;
0310
0311 stream_type m_FormattingStream;
0312
0313 formatter_type m_Formatter;
0314
0315 formatting_context() :
0316 #if !defined(BOOST_LOG_NO_THREADS)
0317 m_Version(0u),
0318 #endif
0319 m_FormattingStream(m_FormattedRecord)
0320 {
0321 m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
0322 }
0323 #if !defined(BOOST_LOG_NO_THREADS)
0324 formatting_context(unsigned int version, std::locale const& loc, formatter_type const& formatter) :
0325 m_Version(version),
0326 m_FormattingStream(m_FormattedRecord),
0327 m_Formatter(formatter)
0328 {
0329 m_FormattingStream.exceptions(std::ios_base::badbit | std::ios_base::failbit);
0330 m_FormattingStream.imbue(loc);
0331 }
0332 #endif
0333 };
0334
0335 private:
0336 #if !defined(BOOST_LOG_NO_THREADS)
0337
0338
0339 boost::atomic< unsigned int > m_Version;
0340
0341
0342 formatter_type m_Formatter;
0343
0344 std::locale m_Locale;
0345
0346
0347 thread_specific_ptr< formatting_context > m_pContext;
0348
0349 #else
0350
0351
0352 formatting_context m_Context;
0353
0354 #endif
0355
0356 public:
0357
0358
0359
0360
0361
0362 explicit basic_formatting_sink_frontend(bool cross_thread) :
0363 basic_sink_frontend(cross_thread)
0364 #if !defined(BOOST_LOG_NO_THREADS)
0365 , m_Version(0u)
0366 #endif
0367 {
0368 }
0369
0370
0371
0372
0373 template< typename FunT >
0374 void set_formatter(FunT const& formatter)
0375 {
0376 #if !defined(BOOST_LOG_NO_THREADS)
0377 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0378 m_Formatter = formatter;
0379 m_Version.opaque_add(1u, boost::memory_order_relaxed);
0380 #else
0381 m_Context.m_Formatter = formatter;
0382 #endif
0383 }
0384
0385
0386
0387 void reset_formatter()
0388 {
0389 #if !defined(BOOST_LOG_NO_THREADS)
0390 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0391 m_Formatter.reset();
0392 m_Version.opaque_add(1u, boost::memory_order_relaxed);
0393 #else
0394 m_Context.m_Formatter.reset();
0395 #endif
0396 }
0397
0398
0399
0400
0401 std::locale getloc() const
0402 {
0403 #if !defined(BOOST_LOG_NO_THREADS)
0404 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0405 return m_Locale;
0406 #else
0407 return m_Context.m_FormattingStream.getloc();
0408 #endif
0409 }
0410
0411
0412
0413 void imbue(std::locale const& loc)
0414 {
0415 #if !defined(BOOST_LOG_NO_THREADS)
0416 boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex());
0417 m_Locale = loc;
0418 m_Version.opaque_add(1u, boost::memory_order_relaxed);
0419 #else
0420 m_Context.m_FormattingStream.imbue(loc);
0421 #endif
0422 }
0423
0424 protected:
0425
0426 formatter_type& formatter()
0427 {
0428 #if !defined(BOOST_LOG_NO_THREADS)
0429 return m_Formatter;
0430 #else
0431 return m_Context.m_Formatter;
0432 #endif
0433 }
0434
0435
0436 template< typename BackendMutexT, typename BackendT >
0437 void feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0438 {
0439 formatting_context* context;
0440
0441 #if !defined(BOOST_LOG_NO_THREADS)
0442 context = m_pContext.get();
0443 if (!context || context->m_Version != m_Version.load(boost::memory_order_relaxed))
0444 {
0445 {
0446 boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());
0447 context = new formatting_context(m_Version.load(boost::memory_order_relaxed), m_Locale, m_Formatter);
0448 }
0449 m_pContext.reset(context);
0450 }
0451 #else
0452 context = &m_Context;
0453 #endif
0454
0455 typename formatting_context::cleanup_guard cleanup(*context);
0456
0457 try
0458 {
0459
0460 context->m_Formatter(rec, context->m_FormattingStream);
0461 context->m_FormattingStream.flush();
0462
0463
0464 BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);)
0465 backend.consume(rec, context->m_FormattedRecord);
0466 }
0467 #if !defined(BOOST_LOG_NO_THREADS)
0468 catch (thread_interrupted&)
0469 {
0470 throw;
0471 }
0472 #endif
0473 catch (...)
0474 {
0475 BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());)
0476 if (this->exception_handler().empty())
0477 throw;
0478 this->exception_handler()();
0479 }
0480 }
0481
0482
0483 template< typename BackendMutexT, typename BackendT >
0484 bool try_feed_record(record_view const& rec, BackendMutexT& backend_mutex, BackendT& backend)
0485 {
0486 #if !defined(BOOST_LOG_NO_THREADS)
0487 try
0488 {
0489 if (!backend_mutex.try_lock())
0490 return false;
0491 }
0492 catch (thread_interrupted&)
0493 {
0494 throw;
0495 }
0496 catch (...)
0497 {
0498 boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex());
0499 if (this->exception_handler().empty())
0500 throw;
0501 this->exception_handler()();
0502 return false;
0503 }
0504
0505 boost::log::aux::exclusive_auto_unlocker< BackendMutexT > unlocker(backend_mutex);
0506 #endif
0507
0508 boost::log::aux::fake_mutex m;
0509 feed_record(rec, m, backend);
0510 return true;
0511 }
0512 };
0513
0514 namespace aux {
0515
0516 template<
0517 typename BackendT,
0518 bool RequiresFormattingV = has_requirement<
0519 typename BackendT::frontend_requirements,
0520 formatted_records
0521 >::value
0522 >
0523 struct make_sink_frontend_base
0524 {
0525 typedef basic_sink_frontend type;
0526 };
0527 template< typename BackendT >
0528 struct make_sink_frontend_base< BackendT, true >
0529 {
0530 typedef basic_formatting_sink_frontend< typename BackendT::char_type > type;
0531 };
0532
0533 }
0534
0535 }
0536
0537 BOOST_LOG_CLOSE_NAMESPACE
0538
0539 }
0540
0541 #include <boost/log/detail/footer.hpp>
0542
0543 #endif