comparison DEPENDENCIES/generic/include/boost/log/sinks/basic_sink_frontend.hpp @ 16:2665513ce2d3

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