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