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