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