• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>Writing your own sources</title>
5<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
6<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
7<link rel="home" href="../../index.html" title="Chapter 1. Boost.Log v2">
8<link rel="up" href="../extension.html" title="Extending the library">
9<link rel="prev" href="../extension.html" title="Extending the library">
10<link rel="next" href="attributes.html" title="Writing your own attributes">
11</head>
12<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
13<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td></tr></table>
14<hr>
15<div class="spirit-nav">
16<a accesskey="p" href="../extension.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../extension.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="attributes.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
17</div>
18<div class="section">
19<div class="titlepage"><div><div><h3 class="title">
20<a name="log.extension.sources"></a><a class="link" href="sources.html" title="Writing your own sources">Writing your own sources</a>
21</h3></div></div></div>
22<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><code class="computeroutput"><a class="link" href="../../logging_sources.html#header.boost.log.sources.threading_models_hpp" title="Header &lt;boost/log/sources/threading_models.hpp&gt;">boost/log/sources/threading_models.hpp</a></code><span class="special">&gt;</span>
23<span class="preprocessor">#include</span> <span class="special">&lt;</span><code class="computeroutput"><a class="link" href="../../logging_sources.html#header.boost.log.sources.basic_logger_hpp" title="Header &lt;boost/log/sources/basic_logger.hpp&gt;">boost/log/sources/basic_logger.hpp</a></code><span class="special">&gt;</span>
24</pre>
25<p>
26        You can extend the library by developing your own sources and, for that matter,
27        ways of collecting log data. Basically, you have two choices of how to start:
28        you can either develop a new logger feature or design a whole new type of
29        source. The first approach is good if all you need is to tweak the functionality
30        of the existing loggers. The second approach is reasonable if the whole mechanism
31        of collecting logs by the provided loggers is unsuitable for your needs.
32      </p>
33<h5>
34<a name="log.extension.sources.h0"></a>
35        <span class="phrase"><a name="log.extension.sources.creating_a_new_logger_feature"></a></span><a class="link" href="sources.html#log.extension.sources.creating_a_new_logger_feature">Creating
36        a new logger feature</a>
37      </h5>
38<p>
39        Every logger provided by the library consists of a number of features that
40        can be combined with each other. Each feature is responsible for a single
41        and independent aspect of the logger functionality. For example, loggers
42        that provide the ability to assign severity levels to logging records include
43        the <code class="computeroutput"><a class="link" href="../../boost/log/sources/severity.html" title="Struct template severity">severity</a></code> feature.
44        You can implement your own feature and use it along with the ones provided
45        by the library.
46      </p>
47<p>
48        A logger feature should follow these basic requirements:
49      </p>
50<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
51<li class="listitem">
52            A logging feature should be a class template. It should have at least
53            one template parameter type (let's name it <code class="computeroutput"><span class="identifier">BaseT</span></code>).
54          </li>
55<li class="listitem">
56            The feature must publicly derive from the <code class="computeroutput"><span class="identifier">BaseT</span></code>
57            template parameter.
58          </li>
59<li class="listitem">
60            The feature must be default-constructible and copy-constructible.
61          </li>
62<li class="listitem">
63            The feature must be constructible with a single argument of a templated
64            type. The feature may not use this argument itself, but it should pass
65            this argument to the <code class="computeroutput"><span class="identifier">BaseT</span></code>
66            constructor.
67          </li>
68</ul></div>
69<p>
70        These requirements allow composition of a logger from a number of features
71        derived from each other. The root class of the features hierarchy will be
72        the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_logger.html" title="Class template basic_logger">basic_logger</a></code>
73        class template instance. This class implements most of the basic functionality
74        of loggers, like storing logger-specific attributes and providing the interface
75        for log message formatting. The hierarchy composition is done by the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_composite_logger.html" title="Class template basic_composite_logger">basic_composite_logger</a></code>
76        class template, which is instantiated on a sequence of features (don't worry,
77        this will be shown in an example in a few moments). The constructor with
78        a templated argument allows initializing features with named parameters,
79        using the <a href="http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html" target="_top">Boost.Parameter</a>
80        library.
81      </p>
82<p>
83        A logging feature may also contain internal data. In that case, to maintain
84        thread safety for the logger, the feature should follow these additional
85        guidelines:
86      </p>
87<div class="orderedlist"><ol class="orderedlist" type="1">
88<li class="listitem">
89            Usually there is no need to introduce a mutex or another synchronization
90            mechanism in each feature. Moreover, it is advised not to do so, because
91            the same feature can be used in both thread-safe and not thread-safe
92            loggers. Instead, features should use the threading model of the logger
93            as a synchronization primitive, similar to how they would use a mutex.
94            The threading model is accessible through the <code class="computeroutput"><span class="identifier">get_threading_model</span></code>
95            method, defined in the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_logger.html" title="Class template basic_logger">basic_logger</a></code>
96            class template.
97          </li>
98<li class="listitem">
99            If the feature has to override <code class="computeroutput"><span class="special">*</span><span class="identifier">_unlocked</span></code> methods of the protected
100            interface of the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_logger.html" title="Class template basic_logger">basic_logger</a></code>
101            class template (or the same part of the base feature interface), the
102            following should be considered with regard to such methods:
103            <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
104<li class="listitem">
105                  The public methods that eventually call these methods are implemented
106                  by the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_composite_logger.html" title="Class template basic_composite_logger">basic_composite_logger</a></code>
107                  class template. These implementations do the necessary locking
108                  and then pass control to the corresponding <code class="computeroutput"><span class="identifier">_unlocked</span></code>
109                  method of the base features.
110                </li>
111<li class="listitem">
112                  The thread safety requirements for these methods are expressed
113                  with lock types. These types are available as typedefs in each
114                  feature and the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_logger.html" title="Class template basic_logger">basic_logger</a></code>
115                  class template. If the feature exposes a protected function <code class="computeroutput"><span class="identifier">foo_unlocked</span></code>, it will also expose
116                  type <code class="computeroutput"><span class="identifier">foo_lock</span></code>,
117                  which will express the locking requirements of <code class="computeroutput"><span class="identifier">foo_unlocked</span></code>.
118                  The corresponding method <code class="computeroutput"><span class="identifier">foo</span></code>
119                  in the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_composite_logger.html" title="Class template basic_composite_logger">basic_composite_logger</a></code>
120                  class template will use this typedef in order to lock the threading
121                  model before calling <code class="computeroutput"><span class="identifier">foo_unlocked</span></code>.
122                </li>
123<li class="listitem">
124                  Feature constructors don't need locking, and thus there's no need
125                  for lock types for them.
126                </li>
127</ul></div>
128          </li>
129<li class="listitem">
130            The feature may implement a copy constructor. The argument of the constructor
131            is already locked with a shared lock when the constructor is called.
132            Naturally, the feature is expected to forward the copy constructor call
133            to the <code class="computeroutput"><span class="identifier">BaseT</span></code> class.
134          </li>
135<li class="listitem">
136            The feature need not implement an assignment operator. The assignment
137            will be automatically provided by the <code class="computeroutput"><a class="link" href="../../boost/log/sources/basic_composite_logger.html" title="Class template basic_composite_logger">basic_composite_logger</a></code>
138            class instance. However, the feature may provide a <code class="computeroutput"><span class="identifier">swap_unlocked</span></code>
139            method that will swap contents of this feature and the method argument,
140            and call similar method in the <code class="computeroutput"><span class="identifier">BaseT</span></code>
141            class. The automatically generated assignment operator will use this
142            method, along with copy constructor.
143          </li>
144</ol></div>
145<p>
146        In order to illustrate all these lengthy recommendations, let's implement
147        a simple logger feature. Suppose we want our logger to be able to tag individual
148        log records. In other words, the logger has to temporarily add an attribute
149        to its set of attributes, emit the logging record, and then automatically
150        remove the attribute. Somewhat similar functionality can be achieved with
151        scoped attributes, although the syntax may complicate wrapping it into a
152        neat macro:
153      </p>
154<pre class="programlisting"><span class="comment">// We want something equivalent to this</span>
155<span class="special">{</span>
156    <span class="identifier">BOOST_LOG_SCOPED_LOGGER_TAG</span><span class="special">(</span><span class="identifier">logger</span><span class="special">,</span> <span class="string">"Tag"</span><span class="special">,</span> <span class="string">"[GUI]"</span><span class="special">);</span>
157    <span class="identifier">BOOST_LOG</span><span class="special">(</span><span class="identifier">logger</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"The user has confirmed his choice"</span><span class="special">;</span>
158<span class="special">}</span>
159</pre>
160<p>
161        Let's declare our logger feature:
162      </p>
163<p>
164</p>
165<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span> <span class="special">&gt;</span>
166<span class="keyword">class</span> <span class="identifier">record_tagger_feature</span> <span class="special">:</span>
167    <span class="keyword">public</span> <span class="identifier">BaseT</span>                        <a class="co" name="log.extension.sources.c0" href="sources.html#log.extension.sources.c1"><img src="../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
168<span class="special">{</span>
169<span class="keyword">public</span><span class="special">:</span>
170    <span class="comment">// Let's import some types that we will need. These imports should be public,</span>
171    <span class="comment">// in order to allow other features that may derive from record_tagger to do the same.</span>
172    <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">char_type</span> <span class="identifier">char_type</span><span class="special">;</span>
173    <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">threading_model</span> <span class="identifier">threading_model</span><span class="special">;</span>
174
175<span class="keyword">public</span><span class="special">:</span>
176    <span class="comment">// Default constructor. Initializes m_Tag to an invalid value.</span>
177    <span class="identifier">record_tagger_feature</span><span class="special">();</span>
178    <span class="comment">// Copy constructor. Initializes m_Tag to a value, equivalent to that.m_Tag.</span>
179    <span class="identifier">record_tagger_feature</span><span class="special">(</span><span class="identifier">record_tagger_feature</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">that</span><span class="special">);</span>
180    <span class="comment">// Forwarding constructor with named parameters</span>
181    <span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ArgsT</span> <span class="special">&gt;</span>
182    <span class="identifier">record_tagger_feature</span><span class="special">(</span><span class="identifier">ArgsT</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">args</span><span class="special">);</span>
183
184    <span class="comment">// The method will require locking, so we have to define locking requirements for it.</span>
185    <span class="comment">// We use the strictest_lock trait in order to choose the most restricting lock type.</span>
186    <span class="keyword">typedef</span> <span class="keyword">typename</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">strictest_lock</span><span class="special">&lt;</span>
187        <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lock_guard</span><span class="special">&lt;</span> <span class="identifier">threading_model</span> <span class="special">&gt;,</span>
188        <span class="keyword">typename</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">open_record_lock</span><span class="special">,</span>
189        <span class="keyword">typename</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">add_attribute_lock</span><span class="special">,</span>
190        <span class="keyword">typename</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">remove_attribute_lock</span>
191    <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">open_record_lock</span><span class="special">;</span>
192
193<span class="keyword">protected</span><span class="special">:</span>
194    <span class="comment">// Lock-less implementation of operations</span>
195    <span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ArgsT</span> <span class="special">&gt;</span>
196    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">record</span> <span class="identifier">open_record_unlocked</span><span class="special">(</span><span class="identifier">ArgsT</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">args</span><span class="special">);</span>
197<span class="special">};</span>
198
199<span class="comment">// A convenience metafunction to specify the feature</span>
200<span class="comment">// in the list of features of the final logger later</span>
201<span class="keyword">struct</span> <span class="identifier">record_tagger</span> <span class="special">:</span>
202    <span class="keyword">public</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">mpl</span><span class="special">::</span><span class="identifier">quote1</span><span class="special">&lt;</span> <span class="identifier">record_tagger_feature</span> <span class="special">&gt;</span>
203<span class="special">{</span>
204<span class="special">};</span>
205</pre>
206<p>
207      </p>
208<div class="calloutlist"><table border="0" summary="Callout list"><tr>
209<td width="5%" valign="top" align="left"><p><a name="log.extension.sources.c1"></a><a href="#log.extension.sources.c0"><img src="../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
210<td valign="top" align="left"><p>
211            the feature should derive from other features or the basic_logger class
212          </p></td>
213</tr></table></div>
214<p>
215        You can see that we use the <code class="computeroutput"><a class="link" href="../../boost/log/strictest_lock.html" title="Struct template strictest_lock">strictest_lock</a></code>
216        template in order to define lock types that would fulfill the base class
217        thread safety requirements for methods that are to be called from the corresponding
218        methods of <code class="computeroutput"><span class="identifier">record_tagger_feature</span></code>.
219        The <code class="computeroutput"><span class="identifier">open_record_lock</span></code> definition
220        shows that the <code class="computeroutput"><span class="identifier">open_record_unlocked</span></code>
221        implementation for the <code class="computeroutput"><span class="identifier">record_tagger_feature</span></code>
222        feature requires exclusive lock (which <code class="computeroutput"><span class="identifier">lock_guard</span></code>
223        is) for the logger, but it also takes into account locking requirements of
224        the <code class="computeroutput"><span class="identifier">open_record_unlocked</span></code>,
225        <code class="computeroutput"><span class="identifier">add_attribute_unlocked</span></code> and
226        <code class="computeroutput"><span class="identifier">remove_attribute_unlocked</span></code>
227        methods of the base class, because it will have to call them. The generated
228        <code class="computeroutput"><span class="identifier">open_record</span></code> method of the
229        final logger class will make use of this typedef in order to automatically
230        acquire the corresponding lock type before forwarding to the <code class="computeroutput"><span class="identifier">open_record_unlocked</span></code> methods.
231      </p>
232<p>
233        Actually, in this particular example, there was no need to use the <code class="computeroutput"><a class="link" href="../../boost/log/strictest_lock.html" title="Struct template strictest_lock">strictest_lock</a></code> trait, because
234        all our methods require exclusive locking, which is already the strictest
235        one. However, this template may come in handy, should you use shared locking.
236      </p>
237<p>
238        The implementation of the public interface becomes quite trivial:
239      </p>
240<p>
241</p>
242<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span> <span class="special">&gt;</span>
243<span class="identifier">record_tagger_feature</span><span class="special">&lt;</span> <span class="identifier">BaseT</span> <span class="special">&gt;::</span><span class="identifier">record_tagger_feature</span><span class="special">()</span>
244<span class="special">{</span>
245<span class="special">}</span>
246
247<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span> <span class="special">&gt;</span>
248<span class="identifier">record_tagger_feature</span><span class="special">&lt;</span> <span class="identifier">BaseT</span> <span class="special">&gt;::</span><span class="identifier">record_tagger_feature</span><span class="special">(</span><span class="identifier">record_tagger_feature</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">that</span><span class="special">)</span> <span class="special">:</span>
249    <span class="identifier">BaseT</span><span class="special">(</span><span class="keyword">static_cast</span><span class="special">&lt;</span> <span class="identifier">BaseT</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="special">&gt;(</span><span class="identifier">that</span><span class="special">))</span>
250<span class="special">{</span>
251<span class="special">}</span>
252
253<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span> <span class="special">&gt;</span>
254<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ArgsT</span> <span class="special">&gt;</span>
255<span class="identifier">record_tagger_feature</span><span class="special">&lt;</span> <span class="identifier">BaseT</span> <span class="special">&gt;::</span><span class="identifier">record_tagger_feature</span><span class="special">(</span><span class="identifier">ArgsT</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">args</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">BaseT</span><span class="special">(</span><span class="identifier">args</span><span class="special">)</span>
256<span class="special">{</span>
257<span class="special">}</span>
258</pre>
259<p>
260      </p>
261<p>
262        Now, since all locking is extracted into the public interface, we have the
263        most of our feature logic to be implemented in the protected part of the
264        interface. In order to set up tag value in the logger, we will have to introduce
265        a new <a href="http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html" target="_top">Boost.Parameter</a>
266        keyword. Following recommendations from that library documentation, it's
267        better to introduce the keyword in a special namespace:
268      </p>
269<p>
270</p>
271<pre class="programlisting"><span class="keyword">namespace</span> <span class="identifier">my_keywords</span> <span class="special">{</span>
272
273    <span class="identifier">BOOST_PARAMETER_KEYWORD</span><span class="special">(</span><span class="identifier">tag_ns</span><span class="special">,</span> <span class="identifier">tag</span><span class="special">)</span>
274
275<span class="special">}</span>
276</pre>
277<p>
278      </p>
279<p>
280        Opening a new record can now look something like this:
281      </p>
282<p>
283</p>
284<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">BaseT</span> <span class="special">&gt;</span>
285<span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">ArgsT</span> <span class="special">&gt;</span>
286<span class="identifier">logging</span><span class="special">::</span><span class="identifier">record</span> <span class="identifier">record_tagger_feature</span><span class="special">&lt;</span> <span class="identifier">BaseT</span> <span class="special">&gt;::</span><span class="identifier">open_record_unlocked</span><span class="special">(</span><span class="identifier">ArgsT</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">args</span><span class="special">)</span>
287<span class="special">{</span>
288    <span class="comment">// Extract the named argument from the parameters pack</span>
289    <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">tag_value</span> <span class="special">=</span> <span class="identifier">args</span><span class="special">[</span><span class="identifier">my_keywords</span><span class="special">::</span><span class="identifier">tag</span> <span class="special">|</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">()];</span>
290
291    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_set</span><span class="special">&amp;</span> <span class="identifier">attrs</span> <span class="special">=</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">attributes</span><span class="special">();</span>
292    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_set</span><span class="special">::</span><span class="identifier">iterator</span> <span class="identifier">tag</span> <span class="special">=</span> <span class="identifier">attrs</span><span class="special">.</span><span class="identifier">end</span><span class="special">();</span>
293    <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">tag_value</span><span class="special">.</span><span class="identifier">empty</span><span class="special">())</span>
294    <span class="special">{</span>
295        <span class="comment">// Add the tag as a new attribute</span>
296        <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span>
297            <span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_set</span><span class="special">::</span><span class="identifier">iterator</span><span class="special">,</span>
298            <span class="keyword">bool</span>
299        <span class="special">&gt;</span> <span class="identifier">res</span> <span class="special">=</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">add_attribute_unlocked</span><span class="special">(</span><span class="string">"Tag"</span><span class="special">,</span>
300            <span class="identifier">attrs</span><span class="special">::</span><span class="identifier">constant</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">&gt;(</span><span class="identifier">tag_value</span><span class="special">));</span>
301        <span class="keyword">if</span> <span class="special">(</span><span class="identifier">res</span><span class="special">.</span><span class="identifier">second</span><span class="special">)</span>
302            <span class="identifier">tag</span> <span class="special">=</span> <span class="identifier">res</span><span class="special">.</span><span class="identifier">first</span><span class="special">;</span>
303    <span class="special">}</span>
304
305    <span class="comment">// In any case, after opening a record remove the tag from the attributes</span>
306    <span class="identifier">BOOST_SCOPE_EXIT_TPL</span><span class="special">((&amp;</span><span class="identifier">tag</span><span class="special">)(&amp;</span><span class="identifier">attrs</span><span class="special">))</span>
307    <span class="special">{</span>
308        <span class="keyword">if</span> <span class="special">(</span><span class="identifier">tag</span> <span class="special">!=</span> <span class="identifier">attrs</span><span class="special">.</span><span class="identifier">end</span><span class="special">())</span>
309            <span class="identifier">attrs</span><span class="special">.</span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">tag</span><span class="special">);</span>
310    <span class="special">}</span>
311    <span class="identifier">BOOST_SCOPE_EXIT_END</span>
312
313    <span class="comment">// Forward the call to the base feature</span>
314    <span class="keyword">return</span> <span class="identifier">BaseT</span><span class="special">::</span><span class="identifier">open_record_unlocked</span><span class="special">(</span><span class="identifier">args</span><span class="special">);</span>
315<span class="special">}</span>
316</pre>
317<p>
318      </p>
319<p>
320        Here we add a new attribute with the tag value, if one is specified in call
321        to <code class="computeroutput"><span class="identifier">open_record</span></code>. When a log
322        record is opened, all attribute values are acquired and locked after the
323        record, so we remove the tag from the attribute set with the <a href="http://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html" target="_top">Boost.ScopeExit</a>
324        block.
325      </p>
326<p>
327        Ok, we got our feature, and it's time to inject it into a logger. Assume
328        we want to combine it with the standard severity level logging. No problems:
329      </p>
330<p>
331</p>
332<pre class="programlisting"><span class="keyword">template</span><span class="special">&lt;</span> <span class="keyword">typename</span> <span class="identifier">LevelT</span> <span class="special">=</span> <span class="keyword">int</span> <span class="special">&gt;</span>
333<span class="keyword">class</span> <span class="identifier">my_logger</span> <span class="special">:</span>
334    <span class="keyword">public</span> <span class="identifier">src</span><span class="special">::</span><span class="identifier">basic_composite_logger</span><span class="special">&lt;</span>
335        <span class="keyword">char</span><span class="special">,</span>                           <a class="co" name="log.extension.sources.c2" href="sources.html#log.extension.sources.c3"><img src="../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
336        <span class="identifier">my_logger</span><span class="special">&lt;</span> <span class="identifier">LevelT</span> <span class="special">&gt;,</span>            <a class="co" name="log.extension.sources.c4" href="sources.html#log.extension.sources.c5"><img src="../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a>
337        <span class="identifier">src</span><span class="special">::</span><span class="identifier">single_thread_model</span><span class="special">,</span>       <a class="co" name="log.extension.sources.c6" href="sources.html#log.extension.sources.c7"><img src="../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a>
338        <span class="identifier">src</span><span class="special">::</span><span class="identifier">features</span><span class="special">&lt;</span>                  <a class="co" name="log.extension.sources.c8" href="sources.html#log.extension.sources.c9"><img src="../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a>
339            <span class="identifier">src</span><span class="special">::</span><span class="identifier">severity</span><span class="special">&lt;</span> <span class="identifier">LevelT</span> <span class="special">&gt;,</span>
340            <span class="identifier">record_tagger</span>
341        <span class="special">&gt;</span>
342    <span class="special">&gt;</span>
343<span class="special">{</span>
344    <span class="comment">// The following line will automatically generate forwarding constructors that</span>
345    <span class="comment">// will call to the corresponding constructors of the base class</span>
346    <span class="identifier">BOOST_LOG_FORWARD_LOGGER_MEMBERS_TEMPLATE</span><span class="special">(</span><span class="identifier">my_logger</span><span class="special">)</span>
347<span class="special">};</span>
348</pre>
349<p>
350      </p>
351<div class="calloutlist"><table border="0" summary="Callout list">
352<tr>
353<td width="5%" valign="top" align="left"><p><a name="log.extension.sources.c3"></a><a href="#log.extension.sources.c2"><img src="../../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
354<td valign="top" align="left"><p>
355            character type for the logger
356          </p></td>
357</tr>
358<tr>
359<td width="5%" valign="top" align="left"><p><a name="log.extension.sources.c5"></a><a href="#log.extension.sources.c4"><img src="../../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
360<td valign="top" align="left"><p>
361            final logger type
362          </p></td>
363</tr>
364<tr>
365<td width="5%" valign="top" align="left"><p><a name="log.extension.sources.c7"></a><a href="#log.extension.sources.c6"><img src="../../../../../../doc/src/images/callouts/3.png" alt="3" border="0"></a> </p></td>
366<td valign="top" align="left"><p>
367            the logger does not perform thread synchronization; use <code class="computeroutput"><span class="identifier">multi_thread_model</span></code> to declare a thread-safe
368            logger
369          </p></td>
370</tr>
371<tr>
372<td width="5%" valign="top" align="left"><p><a name="log.extension.sources.c9"></a><a href="#log.extension.sources.c8"><img src="../../../../../../doc/src/images/callouts/4.png" alt="4" border="0"></a> </p></td>
373<td valign="top" align="left"><p>
374            the list of features we want to combine
375          </p></td>
376</tr>
377</table></div>
378<p>
379        As you can see, creating a logger is a quite simple procedure. The <code class="computeroutput"><span class="identifier">BOOST_LOG_FORWARD_LOGGER_MEMBERS_TEMPLATE</span></code>
380        macro you see here is for mere convenience purpose: it unfolds into a default
381        constructor, copy constructor, assignment operator and a number of constructors
382        to support named arguments. For non-template loggers there is a similar
383        <code class="computeroutput"><span class="identifier">BOOST_LOG_FORWARD_LOGGER_MEMBERS</span></code>
384        macro.
385      </p>
386<p>
387        Assuming we have defined severity levels like this:
388      </p>
389<p>
390</p>
391<pre class="programlisting"><span class="keyword">enum</span> <span class="identifier">severity_level</span>
392<span class="special">{</span>
393    <span class="identifier">normal</span><span class="special">,</span>
394    <span class="identifier">warning</span><span class="special">,</span>
395    <span class="identifier">error</span>
396<span class="special">};</span>
397</pre>
398<p>
399      </p>
400<p>
401        we can now use our logger as follows:
402      </p>
403<p>
404</p>
405<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">manual_logging</span><span class="special">()</span>
406<span class="special">{</span>
407    <span class="identifier">my_logger</span><span class="special">&lt;</span> <span class="identifier">severity_level</span> <span class="special">&gt;</span> <span class="identifier">logger</span><span class="special">;</span>
408
409    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">record</span> <span class="identifier">rec</span> <span class="special">=</span> <span class="identifier">logger</span><span class="special">.</span><span class="identifier">open_record</span><span class="special">((</span><span class="identifier">keywords</span><span class="special">::</span><span class="identifier">severity</span> <span class="special">=</span> <span class="identifier">normal</span><span class="special">,</span> <span class="identifier">my_keywords</span><span class="special">::</span><span class="identifier">tag</span> <span class="special">=</span> <span class="string">"GUI"</span><span class="special">));</span>
410    <span class="keyword">if</span> <span class="special">(</span><span class="identifier">rec</span><span class="special">)</span>
411    <span class="special">{</span>
412        <span class="identifier">logging</span><span class="special">::</span><span class="identifier">record_ostream</span> <span class="identifier">strm</span><span class="special">(</span><span class="identifier">rec</span><span class="special">);</span>
413        <span class="identifier">strm</span> <span class="special">&lt;&lt;</span> <span class="string">"The user has confirmed his choice"</span><span class="special">;</span>
414        <span class="identifier">strm</span><span class="special">.</span><span class="identifier">flush</span><span class="special">();</span>
415        <span class="identifier">logger</span><span class="special">.</span><span class="identifier">push_record</span><span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">rec</span><span class="special">));</span>
416    <span class="special">}</span>
417<span class="special">}</span>
418</pre>
419<p>
420      </p>
421<p>
422        All this verbosity is usually not required. One can define a special macro
423        to make the code more concise:
424      </p>
425<p>
426</p>
427<pre class="programlisting"><span class="preprocessor">#define</span> <span class="identifier">LOG_WITH_TAG</span><span class="special">(</span><span class="identifier">lg</span><span class="special">,</span> <span class="identifier">sev</span><span class="special">,</span> <span class="identifier">tg</span><span class="special">)</span> <span class="special">\</span>
428    <span class="identifier">BOOST_LOG_WITH_PARAMS</span><span class="special">((</span><span class="identifier">lg</span><span class="special">),</span> <span class="special">(</span><span class="identifier">keywords</span><span class="special">::</span><span class="identifier">severity</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">sev</span><span class="special">))(</span><span class="identifier">my_keywords</span><span class="special">::</span><span class="identifier">tag</span> <span class="special">=</span> <span class="special">(</span><span class="identifier">tg</span><span class="special">)))</span>
429
430<span class="keyword">void</span> <span class="identifier">logging_function</span><span class="special">()</span>
431<span class="special">{</span>
432    <span class="identifier">my_logger</span><span class="special">&lt;</span> <span class="identifier">severity_level</span> <span class="special">&gt;</span> <span class="identifier">logger</span><span class="special">;</span>
433
434    <span class="identifier">LOG_WITH_TAG</span><span class="special">(</span><span class="identifier">logger</span><span class="special">,</span> <span class="identifier">normal</span><span class="special">,</span> <span class="string">"GUI"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"The user has confirmed his choice"</span><span class="special">;</span>
435<span class="special">}</span>
436</pre>
437<p>
438      </p>
439<p>
440        <a href="../../../../../../libs/log/example/doc/extension_record_tagger.cpp" target="_top">See
441        the complete code</a>.
442      </p>
443<h5>
444<a name="log.extension.sources.h1"></a>
445        <span class="phrase"><a name="log.extension.sources.guidelines_for_designers_of_standalone_logging_sources"></a></span><a class="link" href="sources.html#log.extension.sources.guidelines_for_designers_of_standalone_logging_sources">Guidelines
446        for designers of standalone logging sources</a>
447      </h5>
448<p>
449        In general, you can implement new logging sources the way you like, the library
450        does not mandate any design requirements on log sources. However, there are
451        some notes regarding the way log sources should interact with logging core.
452      </p>
453<div class="orderedlist"><ol class="orderedlist" type="1">
454<li class="listitem">
455            Whenever a logging source is ready to emit a log record, it should call
456            the <code class="computeroutput"><span class="identifier">open_record</span></code> in the
457            core. The source-specific attributes should be passed into that call.
458            During that call the core allocates resources for the record being made
459            and performs filtering.
460          </li>
461<li class="listitem">
462            If the call to <code class="computeroutput"><span class="identifier">open_record</span></code>
463            returned a valid log record, then the record has passed the filtering
464            and is considered to be opened. The record may later be either confirmed
465            by the source by subsequently calling <code class="computeroutput"><span class="identifier">push_record</span></code>
466            or withdrawn by destroying it.
467          </li>
468<li class="listitem">
469            If the call to <code class="computeroutput"><span class="identifier">open_record</span></code>
470            returned an invalid (empty) log record, it means that the record has
471            not been opened (most likely due to filtering rejection). In that case
472            the logging core does not hold any resources associated with the record,
473            and thus the source must not call <code class="computeroutput"><span class="identifier">push_record</span></code>
474            for that particular logging attempt.
475          </li>
476<li class="listitem">
477            The source may subsequently open more than one record. Opened log records
478            exist independently from each other.
479          </li>
480</ol></div>
481</div>
482<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
483<td align="left"></td>
484<td align="right"><div class="copyright-footer">Copyright © 2007-2019 Andrey Semashev<p>
485        Distributed under the Boost Software License, Version 1.0. (See accompanying
486        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>).
487      </p>
488</div></td>
489</tr></table>
490<hr>
491<div class="spirit-nav">
492<a accesskey="p" href="../extension.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../extension.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="attributes.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
493</div>
494</body>
495</html>
496