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