1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Extending library settings support</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="attributes.html" title="Writing your own attributes"> 10<link rel="next" href="../rationale.html" title="Rationale and FAQ"> 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="attributes.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="../rationale.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.settings"></a><a class="link" href="settings.html" title="Extending library settings support">Extending library settings support</a> 21</h3></div></div></div> 22<div class="toc"><dl class="toc"> 23<dt><span class="section"><a href="settings.html#log.extension.settings.formatter">Adding support for 24 user-defined types to the formatter parser</a></span></dt> 25<dt><span class="section"><a href="settings.html#log.extension.settings.filter">Adding support for user-defined 26 types to the filter parser</a></span></dt> 27<dt><span class="section"><a href="settings.html#log.extension.settings.sinks">Adding support for user-defined 28 sinks</a></span></dt> 29</dl></div> 30<p> 31 If you write your own logging sinks or use your own types in attributes, 32 you may want to add support for these components to the settings parser provided 33 by the library. Without doing this, the library will not be aware of your 34 types and thus will not be able to use them when parsing settings. 35 </p> 36<div class="section"> 37<div class="titlepage"><div><div><h4 class="title"> 38<a name="log.extension.settings.formatter"></a><a class="link" href="settings.html#log.extension.settings.formatter" title="Adding support for user-defined types to the formatter parser">Adding support for 39 user-defined types to the formatter parser</a> 40</h4></div></div></div> 41<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><code class="computeroutput"><a class="link" href="../../utilities.html#header.boost.log.utility.setup.formatter_parser_hpp" title="Header <boost/log/utility/setup/formatter_parser.hpp>">boost/log/utility/setup/formatter_parser.hpp</a></code><span class="special">></span> 42</pre> 43<p> 44 In order to add support for user-defined types to the formatter parser, 45 one has to register a formatter factory. The factory is basically an object 46 that derives from <code class="computeroutput"><a class="link" href="../../boost/log/formatter_factory.html" title="Struct template formatter_factory">formatter_factory</a></code> 47 interface. The factory mainly implements the single <code class="computeroutput"><span class="identifier">create_formatter</span></code> 48 method which, when called, will construct a formatter for the particular 49 attribute value. 50 </p> 51<p> 52 When the user-defined type supports putting to a stream with <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> 53 and this operator behavior is suitable for logging, one can use a simple 54 generic formatter factory provided by the library out of the box. For example, 55 let's assume we have the following user-defined type that we want to use 56 as an attribute value: 57 </p> 58<p> 59</p> 60<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">point</span> 61<span class="special">{</span> 62 <span class="keyword">float</span> <span class="identifier">m_x</span><span class="special">,</span> <span class="identifier">m_y</span><span class="special">;</span> 63 64 <span class="identifier">point</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">m_x</span><span class="special">(</span><span class="number">0.0f</span><span class="special">),</span> <span class="identifier">m_y</span><span class="special">(</span><span class="number">0.0f</span><span class="special">)</span> <span class="special">{}</span> 65 <span class="identifier">point</span><span class="special">(</span><span class="keyword">float</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">float</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">m_x</span><span class="special">(</span><span class="identifier">x</span><span class="special">),</span> <span class="identifier">m_y</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span> <span class="special">{}</span> 66<span class="special">};</span> 67 68<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">TraitsT</span> <span class="special">></span> 69<span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="keyword">operator</span><span class="special"><<</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">p</span><span class="special">)</span> 70<span class="special">{</span> 71 <span class="identifier">strm</span> <span class="special"><<</span> <span class="string">"("</span> <span class="special"><<</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">m_x</span> <span class="special"><<</span> <span class="string">", "</span> <span class="special"><<</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">m_y</span> <span class="special"><<</span> <span class="string">")"</span><span class="special">;</span> 72 <span class="keyword">return</span> <span class="identifier">strm</span><span class="special">;</span> 73<span class="special">}</span> 74</pre> 75<p> 76 </p> 77<p> 78 Then, in order to register this type with the simple formatter factory, 79 a single call to <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573048096.html" title="Function template register_simple_formatter_factory">register_simple_formatter_factory</a></code> 80 will suffice: 81 </p> 82<p> 83</p> 84<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 85<span class="special">{</span> 86 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_simple_formatter_factory</span><span class="special"><</span> <span class="identifier">point</span><span class="special">,</span> <span class="keyword">char</span> <span class="special">>(</span><span class="string">"Coordinates"</span><span class="special">);</span> 87<span class="special">}</span> 88</pre> 89<p> 90 </p> 91<div class="note"><table border="0" summary="Note"> 92<tr> 93<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td> 94<th align="left">Note</th> 95</tr> 96<tr><td align="left" valign="top"><p> 97 The <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> 98 for the attribute value stored type must be visible from the point of 99 this call. 100 </p></td></tr> 101</table></div> 102<p> 103 The function takes the stored attribute value type (<code class="computeroutput"><span class="identifier">point</span></code>, 104 in our case) and the target character type used by formatters as template 105 parameters. From the point of this call, whenever the formatter parser 106 encounters a reference to the "Coordinates" attribute in the 107 format string, it will invoke the formatter factory, which will construct 108 the formatter that calls our <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code> for class <code class="computeroutput"><span class="identifier">point</span></code>. 109 </p> 110<div class="tip"><table border="0" summary="Tip"> 111<tr> 112<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../../../../doc/src/images/tip.png"></td> 113<th align="left">Tip</th> 114</tr> 115<tr><td align="left" valign="top"><p> 116 It is typically a good idea to register all formatter factories at an 117 early stage of the application initialization, before any other library 118 initialization, such as reading config files. 119 </p></td></tr> 120</table></div> 121<p> 122 From the <a class="link" href="../detailed/utilities.html#log.detailed.utilities.setup.filter_formatter" title="Filter and formatter parsers">formatter 123 parser description</a> it is known that the parser supports passing 124 additional parameters from the format string to the formatter factory. 125 We can use these parameters to customize the output generated by the formatter. 126 </p> 127<p> 128 For example, let's implement customizable formatting of our <code class="computeroutput"><span class="identifier">point</span></code> objects, so that the following 129 format string works as expected: 130 </p> 131<pre class="programlisting">%TimeStamp% %Coordinates(format="{%0.3f; %0.3f}")% %Message%</pre> 132<p> 133 The simple formatter factory ignores all additional parameters from the 134 format string, so we have to implement our own factory instead. Custom 135 factories are registered with the <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573061152.html" title="Function template register_formatter_factory">register_formatter_factory</a></code> 136 function, which is similar to <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573048096.html" title="Function template register_simple_formatter_factory">register_simple_formatter_factory</a></code> 137 but accepts a pointer to the factory instead of the explicit template parameters. 138 </p> 139<p> 140</p> 141<pre class="programlisting"><span class="comment">// Custom point formatter</span> 142<span class="keyword">class</span> <span class="identifier">point_formatter</span> 143<span class="special">{</span> 144<span class="keyword">public</span><span class="special">:</span> 145 <span class="keyword">typedef</span> <span class="keyword">void</span> <span class="identifier">result_type</span><span class="special">;</span> 146 147<span class="keyword">public</span><span class="special">:</span> 148 <span class="keyword">explicit</span> <span class="identifier">point_formatter</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">fmt</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">m_format</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">)</span> 149 <span class="special">{</span> 150 <span class="special">}</span> 151 152 <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()</span> <span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">formatting_ostream</span><span class="special">&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">value</span><span class="special">)</span> <span class="keyword">const</span> 153 <span class="special">{</span> 154 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">value</span><span class="special">)</span> 155 <span class="special">{</span> 156 <span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">p</span> <span class="special">=</span> <span class="identifier">value</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span> 157 <span class="identifier">m_format</span> <span class="special">%</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">m_x</span> <span class="special">%</span> <span class="identifier">p</span><span class="special">.</span><span class="identifier">m_y</span><span class="special">;</span> 158 <span class="identifier">strm</span> <span class="special"><<</span> <span class="identifier">m_format</span><span class="special">;</span> 159 <span class="identifier">m_format</span><span class="special">.</span><span class="identifier">clear</span><span class="special">();</span> 160 <span class="special">}</span> 161 <span class="special">}</span> 162 163<span class="keyword">private</span><span class="special">:</span> 164 <span class="keyword">mutable</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">format</span> <span class="identifier">m_format</span><span class="special">;</span> 165<span class="special">};</span> 166 167<span class="comment">// Custom point formatter factory</span> 168<span class="keyword">class</span> <span class="identifier">point_formatter_factory</span> <span class="special">:</span> 169 <span class="keyword">public</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">basic_formatter_factory</span><span class="special"><</span> <span class="keyword">char</span><span class="special">,</span> <span class="identifier">point</span> <span class="special">></span> 170<span class="special">{</span> 171<span class="keyword">public</span><span class="special">:</span> 172 <span class="identifier">formatter_type</span> <span class="identifier">create_formatter</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">args_map</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">args</span><span class="special">)</span> 173 <span class="special">{</span> 174 <span class="identifier">args_map</span><span class="special">::</span><span class="identifier">const_iterator</span> <span class="identifier">it</span> <span class="special">=</span> <span class="identifier">args</span><span class="special">.</span><span class="identifier">find</span><span class="special">(</span><span class="string">"format"</span><span class="special">);</span> 175 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">it</span> <span class="special">!=</span> <span class="identifier">args</span><span class="special">.</span><span class="identifier">end</span><span class="special">())</span> 176 <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">point_formatter</span><span class="special">(</span><span class="identifier">it</span><span class="special">-></span><span class="identifier">second</span><span class="special">),</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">));</span> 177 <span class="keyword">else</span> 178 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special"><<</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">);</span> 179 <span class="special">}</span> 180<span class="special">};</span> 181 182<span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 183<span class="special">{</span> 184 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_formatter_factory</span><span class="special">(</span><span class="string">"Coordinates"</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">point_formatter_factory</span> <span class="special">>());</span> 185<span class="special">}</span> 186</pre> 187<p> 188 </p> 189<p> 190 Let's walk through this code sample. Our <code class="computeroutput"><span class="identifier">point_formatter_factory</span></code> 191 class derives from the <code class="computeroutput"><a class="link" href="../../boost/log/basic_formatter_factory.html" title="Class template basic_formatter_factory">basic_formatter_factory</a></code> 192 base class provided by the library. This class derives from the base <code class="computeroutput"><a class="link" href="../../boost/log/formatter_factory.html" title="Struct template formatter_factory">formatter_factory</a></code> interface 193 and defines a few useful types, such as <code class="computeroutput"><span class="identifier">formatter_type</span></code> 194 and <code class="computeroutput"><span class="identifier">args_map</span></code> that we use. 195 The only thing left to do in our factory is to define the <code class="computeroutput"><span class="identifier">create_formatter</span></code> method. The method analyzes 196 the parameters from the format string which are passed as the <code class="computeroutput"><span class="identifier">args</span></code> argument, which is basically <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">map</span></code> of string keys (parameter names) 197 to string values (the parameter values). We seek for the <code class="computeroutput"><span class="identifier">format</span></code> parameter and expect it to contain 198 a <a href="http://www.boost.org/doc/libs/release/libs/format/index.html" target="_top">Boost.Format</a>-compatible 199 format string for our <code class="computeroutput"><span class="identifier">point</span></code> 200 objects. If the parameter is found we create a formatter that invokes 201 <code class="computeroutput"><span class="identifier">point_formatter</span></code> for the 202 attribute values. Otherwise we create a default formatter that simply uses 203 the <code class="computeroutput"><span class="keyword">operator</span><span class="special"><<</span></code>, 204 like the simple formatter factory does. Note that we use the <code class="computeroutput"><span class="identifier">name</span></code> argument of <code class="computeroutput"><span class="identifier">create_formatter</span></code> 205 to identify the attribute so that the same factory can be used for different 206 attributes. 207 </p> 208<p> 209 The <code class="computeroutput"><span class="identifier">point_formatter</span></code> is 210 our custom formatter based on <a href="http://www.boost.org/doc/libs/release/libs/format/index.html" target="_top">Boost.Format</a>. 211 With help of <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a> 212 and <a class="link" href="../detailed/expressions.html#log.detailed.expressions.attr" title="Generic attribute placeholder">expression placeholders</a> 213 we can construct a formatter that will extract the attribute value and 214 pass it along with the target stream to the <code class="computeroutput"><span class="identifier">point_formatter</span></code> 215 function object. Note that the formatter accepts the attribute value wrapped 216 into the <a class="link" href="../detailed/utilities.html#log.detailed.utilities.value_ref" title="Value reference wrapper"><code class="computeroutput"><span class="identifier">value_ref</span></code></a> wrapper which can be 217 empty if the value is not present. 218 </p> 219<p> 220 Lastly, the call to <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573061152.html" title="Function template register_formatter_factory">register_formatter_factory</a></code> 221 creates the factory and adds it to the library. 222 </p> 223<p> 224 You can find the complete code of this example <a href="../../../../../../libs/log/example/doc/extension_formatter_parser.cpp" target="_top">here</a>. 225 </p> 226</div> 227<div class="section"> 228<div class="titlepage"><div><div><h4 class="title"> 229<a name="log.extension.settings.filter"></a><a class="link" href="settings.html#log.extension.settings.filter" title="Adding support for user-defined types to the filter parser">Adding support for user-defined 230 types to the filter parser</a> 231</h4></div></div></div> 232<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><code class="computeroutput"><a class="link" href="../../utilities.html#header.boost.log.utility.setup.filter_parser_hpp" title="Header <boost/log/utility/setup/filter_parser.hpp>">boost/log/utility/setup/filter_parser.hpp</a></code><span class="special">></span> 233</pre> 234<p> 235 You can extend filter parser in the similar way you can extend the formatter 236 parser - by registering filter factories for your attribute values into 237 the library. However, since it takes a considerably more complex syntax 238 to describe filters, a filter factory typically implements several generator 239 functions. 240 </p> 241<p> 242 Like with formatter parser extension, you can avoid spelling out the filter 243 factory and register a simple factory provided by the library: 244 </p> 245<p> 246</p> 247<pre class="programlisting"><span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 248<span class="special">{</span> 249 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_simple_filter_factory</span><span class="special"><</span> <span class="identifier">point</span><span class="special">,</span> <span class="keyword">char</span> <span class="special">>(</span><span class="string">"Coordinates"</span><span class="special">);</span> 250<span class="special">}</span> 251</pre> 252<p> 253 </p> 254<p> 255 In order this to work the user's type should fulfill these requirements: 256 </p> 257<div class="orderedlist"><ol class="orderedlist" type="1"> 258<li class="listitem"> 259 Support reading from an input stream with <code class="computeroutput"><span class="keyword">operator</span><span class="special">>></span></code>. 260 </li> 261<li class="listitem"> 262 Support the complete set of comparison and ordering operators. 263 </li> 264</ol></div> 265<p> 266 Naturally, all these operators must be visible from the point of the <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573131168.html" title="Function template register_simple_filter_factory">register_simple_filter_factory</a></code> 267 call. Note that unlike the simple formatter factory, the filter factory 268 requires the user's type to support reading from a stream. This is so because 269 the filter factory would have to parse the argument of the filter relation 270 from a string. 271 </p> 272<p> 273 But we won't get away with a simple filter factory, because our <code class="computeroutput"><span class="identifier">point</span></code> class doesn't have a sensible ordering 274 semantics and thus we cannot define the complete set of operators. We'll 275 have to implement our own filter factory instead. Filter factories derive 276 from the <code class="computeroutput"><a class="link" href="../../boost/log/filter_factory.html" title="Struct template filter_factory">filter_factory</a></code> 277 interface. This base class declares a number of virtual functions that 278 will be called in order to create filters, according to the filter expression. 279 If some functions are not overridden by the factory, the corresponding 280 operations are considered to be not supported by the attribute value. But 281 before we define the filter factory we have to improve our <code class="computeroutput"><span class="identifier">point</span></code> class slightly: 282 </p> 283<p> 284</p> 285<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">point</span> 286<span class="special">{</span> 287 <span class="keyword">float</span> <span class="identifier">m_x</span><span class="special">,</span> <span class="identifier">m_y</span><span class="special">;</span> 288 289 <span class="identifier">point</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">m_x</span><span class="special">(</span><span class="number">0.0f</span><span class="special">),</span> <span class="identifier">m_y</span><span class="special">(</span><span class="number">0.0f</span><span class="special">)</span> <span class="special">{}</span> 290 <span class="identifier">point</span><span class="special">(</span><span class="keyword">float</span> <span class="identifier">x</span><span class="special">,</span> <span class="keyword">float</span> <span class="identifier">y</span><span class="special">)</span> <span class="special">:</span> <span class="identifier">m_x</span><span class="special">(</span><span class="identifier">x</span><span class="special">),</span> <span class="identifier">m_y</span><span class="special">(</span><span class="identifier">y</span><span class="special">)</span> <span class="special">{}</span> 291<span class="special">};</span> 292 293<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">==</span> <span class="special">(</span><span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">left</span><span class="special">,</span> <span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">right</span><span class="special">);</span> 294<span class="keyword">bool</span> <span class="keyword">operator</span><span class="special">!=</span> <span class="special">(</span><span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">left</span><span class="special">,</span> <span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">right</span><span class="special">);</span> 295 296<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">TraitsT</span> <span class="special">></span> 297<span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="keyword">operator</span><span class="special"><<</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">point</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">p</span><span class="special">);</span> 298<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">TraitsT</span> <span class="special">></span> 299<span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_istream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="keyword">operator</span><span class="special">>></span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_istream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">point</span><span class="special">&</span> <span class="identifier">p</span><span class="special">);</span> 300</pre> 301<p> 302 </p> 303<p> 304 We have added comparison and input operators for the <code class="computeroutput"><span class="identifier">point</span></code> 305 class. The output operator is still used by formatters and not required 306 by the filter factory. Now we can define and register the filter factory: 307 </p> 308<p> 309</p> 310<pre class="programlisting"><span class="comment">// Custom point filter factory</span> 311<span class="keyword">class</span> <span class="identifier">point_filter_factory</span> <span class="special">:</span> 312 <span class="keyword">public</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter_factory</span><span class="special"><</span> <span class="keyword">char</span> <span class="special">></span> 313<span class="special">{</span> 314<span class="keyword">public</span><span class="special">:</span> 315 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_exists_test</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">)</span> 316 <span class="special">{</span> 317 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">);</span> 318 <span class="special">}</span> 319 320 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_equality_relation</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">arg</span><span class="special">)</span> 321 <span class="special">{</span> 322 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">)</span> <span class="special">==</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">arg</span><span class="special">);</span> 323 <span class="special">}</span> 324 325 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_inequality_relation</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">arg</span><span class="special">)</span> 326 <span class="special">{</span> 327 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">)</span> <span class="special">!=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">arg</span><span class="special">);</span> 328 <span class="special">}</span> 329<span class="special">};</span> 330 331<span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 332<span class="special">{</span> 333 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_filter_factory</span><span class="special">(</span><span class="string">"Coordinates"</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">point_filter_factory</span> <span class="special">>());</span> 334<span class="special">}</span> 335</pre> 336<p> 337 </p> 338<p> 339 Having called the <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079573144416.html" title="Function template register_filter_factory">register_filter_factory</a></code> 340 function, whenever the <a class="link" href="../detailed/utilities.html#log.detailed.utilities.setup.filter_formatter" title="Filter and formatter parsers">filter 341 parser</a> encounters the "Coordinates" attribute mentioned 342 in the filter, it will use the <code class="computeroutput"><span class="identifier">point_filter_factory</span></code> 343 object to construct the appropriate filter. For example, in the case of 344 the following filter 345 </p> 346<pre class="programlisting">%Coordinates% = "(10, 10)"</pre> 347<p> 348 the <code class="computeroutput"><span class="identifier">on_equality_relation</span></code> 349 method will be called with <code class="computeroutput"><span class="identifier">name</span></code> 350 argument being "Coordinates" and <code class="computeroutput"><span class="identifier">arg</span></code> 351 being "(10, 10)". 352 </p> 353<div class="note"><table border="0" summary="Note"> 354<tr> 355<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td> 356<th align="left">Note</th> 357</tr> 358<tr><td align="left" valign="top"><p> 359 The quotes around the parenthesis are necessary because the filter parser 360 should interpret the point coordinates as a single string. Also, round 361 brackets are already used to group subexpressions of the filter expression. 362 Whenever there is need to pass several parameters to the relation (like 363 in this case - a number of components of the <code class="computeroutput"><span class="identifier">point</span></code> 364 class) the parameters should be encoded into a quoted string. The string 365 may include C-style escape sequences that will be unfolded upon parsing. 366 </p></td></tr> 367</table></div> 368<p> 369 The constructed filter will use the corresponding comparison operators 370 for the <code class="computeroutput"><span class="identifier">point</span></code> class. Ordering 371 operations, like ">" or "<=", will not be supported 372 for attributes named "Coordinates", and this is exactly the way 373 we want it, because the <code class="computeroutput"><span class="identifier">point</span></code> 374 class does not support them either. The complete example is available 375 <a href="../../../../../../libs/log/example/doc/extension_filter_parser.cpp" target="_top">here</a>. 376 </p> 377<p> 378 The library allows not only adding support for new types, but also associating 379 new relations with them. For instance, we can create a new relation "is_in_rectangle" 380 that will yield positive if the coordinates fit into a rectangle denoted 381 with two points. The filter might look like this: 382 </p> 383<pre class="programlisting">%Coordinates% is_in_rectangle "{(10, 10) - (20, 20)}"</pre> 384<p> 385 First, let's define our rectangle class: 386 </p> 387<p> 388</p> 389<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">rectangle</span> 390<span class="special">{</span> 391 <span class="identifier">point</span> <span class="identifier">m_top_left</span><span class="special">,</span> <span class="identifier">m_bottom_right</span><span class="special">;</span> 392<span class="special">};</span> 393 394<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">TraitsT</span> <span class="special">></span> 395<span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="keyword">operator</span><span class="special"><<</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_ostream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">rectangle</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">r</span><span class="special">);</span> 396<span class="keyword">template</span><span class="special"><</span> <span class="keyword">typename</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="keyword">typename</span> <span class="identifier">TraitsT</span> <span class="special">></span> 397<span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_istream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="keyword">operator</span><span class="special">>></span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">basic_istream</span><span class="special"><</span> <span class="identifier">CharT</span><span class="special">,</span> <span class="identifier">TraitsT</span> <span class="special">>&</span> <span class="identifier">strm</span><span class="special">,</span> <span class="identifier">rectangle</span><span class="special">&</span> <span class="identifier">r</span><span class="special">);</span> 398</pre> 399<p> 400 </p> 401<p> 402 As it was said, the rectangle is described by two points - the top left 403 and the bottom right corners of the rectangle area. Now let's extend our 404 filter factory with the <code class="computeroutput"><span class="identifier">on_custom_relation</span></code> 405 method: 406 </p> 407<p> 408</p> 409<pre class="programlisting"><span class="comment">// The function checks if the point is inside the rectangle</span> 410<span class="keyword">bool</span> <span class="identifier">is_in_rectangle</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">p</span><span class="special">,</span> <span class="identifier">rectangle</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">r</span><span class="special">)</span> 411<span class="special">{</span> 412 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">p</span><span class="special">)</span> 413 <span class="special">{</span> 414 <span class="keyword">return</span> <span class="identifier">p</span><span class="special">-></span><span class="identifier">m_x</span> <span class="special">>=</span> <span class="identifier">r</span><span class="special">.</span><span class="identifier">m_top_left</span><span class="special">.</span><span class="identifier">m_x</span> <span class="special">&&</span> <span class="identifier">p</span><span class="special">-></span><span class="identifier">m_x</span> <span class="special"><=</span> <span class="identifier">r</span><span class="special">.</span><span class="identifier">m_bottom_right</span><span class="special">.</span><span class="identifier">m_x</span> <span class="special">&&</span> 415 <span class="identifier">p</span><span class="special">-></span><span class="identifier">m_y</span> <span class="special">>=</span> <span class="identifier">r</span><span class="special">.</span><span class="identifier">m_top_left</span><span class="special">.</span><span class="identifier">m_y</span> <span class="special">&&</span> <span class="identifier">p</span><span class="special">-></span><span class="identifier">m_y</span> <span class="special"><=</span> <span class="identifier">r</span><span class="special">.</span><span class="identifier">m_bottom_right</span><span class="special">.</span><span class="identifier">m_y</span><span class="special">;</span> 416 <span class="special">}</span> 417 <span class="keyword">return</span> <span class="keyword">false</span><span class="special">;</span> 418<span class="special">}</span> 419 420<span class="comment">// Custom point filter factory</span> 421<span class="keyword">class</span> <span class="identifier">point_filter_factory</span> <span class="special">:</span> 422 <span class="keyword">public</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter_factory</span><span class="special"><</span> <span class="keyword">char</span> <span class="special">></span> 423<span class="special">{</span> 424<span class="keyword">public</span><span class="special">:</span> 425 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_exists_test</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">)</span> 426 <span class="special">{</span> 427 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">);</span> 428 <span class="special">}</span> 429 430 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_equality_relation</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">arg</span><span class="special">)</span> 431 <span class="special">{</span> 432 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">)</span> <span class="special">==</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">arg</span><span class="special">);</span> 433 <span class="special">}</span> 434 435 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_inequality_relation</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">arg</span><span class="special">)</span> 436 <span class="special">{</span> 437 <span class="keyword">return</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">)</span> <span class="special">!=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">arg</span><span class="special">);</span> 438 <span class="special">}</span> 439 440 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">filter</span> <span class="identifier">on_custom_relation</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_name</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">name</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">rel</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">arg</span><span class="special">)</span> 441 <span class="special">{</span> 442 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">rel</span> <span class="special">==</span> <span class="string">"is_in_rectangle"</span><span class="special">)</span> 443 <span class="special">{</span> 444 <span class="keyword">return</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">bind</span><span class="special">(&</span><span class="identifier">is_in_rectangle</span><span class="special">,</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">attr</span><span class="special"><</span> <span class="identifier">point</span> <span class="special">>(</span><span class="identifier">name</span><span class="special">),</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="identifier">rectangle</span> <span class="special">>(</span><span class="identifier">arg</span><span class="special">));</span> 445 <span class="special">}</span> 446 <span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">runtime_error</span><span class="special">(</span><span class="string">"Unsupported filter relation: "</span> <span class="special">+</span> <span class="identifier">rel</span><span class="special">);</span> 447 <span class="special">}</span> 448<span class="special">};</span> 449 450<span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 451<span class="special">{</span> 452 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_filter_factory</span><span class="special">(</span><span class="string">"Coordinates"</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">point_filter_factory</span> <span class="special">>());</span> 453<span class="special">}</span> 454</pre> 455<p> 456 </p> 457<p> 458 The <code class="computeroutput"><span class="identifier">on_custom_relation</span></code> 459 method is called with the relation name (the "is_in_rectangle" 460 string in our case) and the right-hand argument for the relation (the rectangle 461 description). All we have to do is to construct the filter, which is implemented 462 by our <code class="computeroutput"><span class="identifier">is_in_rectangle</span></code> 463 function. We use <code class="computeroutput"><span class="identifier">bind</span></code> from 464 <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a> 465 to compose the filter from the function and the <a class="link" href="../detailed/expressions.html#log.detailed.expressions.attr" title="Generic attribute placeholder">attribute 466 placeholder</a>. You can find the complete code of this example <a href="../../../../../../libs/log/example/doc/extension_filter_parser_custom_rel.cpp" target="_top">here</a>. 467 </p> 468</div> 469<div class="section"> 470<div class="titlepage"><div><div><h4 class="title"> 471<a name="log.extension.settings.sinks"></a><a class="link" href="settings.html#log.extension.settings.sinks" title="Adding support for user-defined sinks">Adding support for user-defined 472 sinks</a> 473</h4></div></div></div> 474<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special"><</span><code class="computeroutput"><a class="link" href="../../utilities.html#header.boost.log.utility.setup.from_settings_hpp" title="Header <boost/log/utility/setup/from_settings.hpp>">boost/log/utility/setup/from_settings.hpp</a></code><span class="special">></span> 475<span class="preprocessor">#include</span> <span class="special"><</span><code class="computeroutput"><a class="link" href="../../utilities.html#header.boost.log.utility.setup.from_stream_hpp" title="Header <boost/log/utility/setup/from_stream.hpp>">boost/log/utility/setup/from_stream.hpp</a></code><span class="special">></span> 476</pre> 477<p> 478 The library provides mechanism of extending support for sinks similar to 479 the formatter and filter parsers. In order to be able to mention user-defined 480 sinks in a settings file, the user has to register a sink factory, which 481 essentially contains the <code class="computeroutput"><span class="identifier">create_sink</span></code> 482 method that receives a <a class="link" href="../detailed/utilities.html#log.detailed.utilities.setup.settings" title="Library initialization from a settings container">settings 483 subsection</a> and returns a pointer to the initialized sink. The factory 484 is registered for a specific destination (see the <a class="link" href="../detailed/utilities.html#log.detailed.utilities.setup.settings" title="Library initialization from a settings container">settings 485 file description</a>), so whenever a sink with the specified destination 486 is mentioned in the settings file, the factory gets called. 487 </p> 488<p> 489 For example, let's register the <code class="computeroutput"><span class="identifier">stat_collector</span></code> 490 sink we described <a class="link" href="../extension.html#log.extension.sinks" title="Writing your own sinks">before</a> in 491 the library. First, let's remember the sink definition: 492 </p> 493<p> 494</p> 495<pre class="programlisting"><span class="comment">// The backend collects statistical information about network activity of the application</span> 496<span class="keyword">class</span> <span class="identifier">stat_collector</span> <span class="special">:</span> 497 <span class="keyword">public</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">basic_sink_backend</span><span class="special"><</span> 498 <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">combine_requirements</span><span class="special"><</span> 499 <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronized_feeding</span><span class="special">,</span> 500 <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">flushing</span> 501 <span class="special">>::</span><span class="identifier">type</span> 502 <span class="special">></span> 503<span class="special">{</span> 504<span class="keyword">private</span><span class="special">:</span> 505 <span class="comment">// The file to write the collected information to</span> 506 <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="identifier">m_csv_file</span><span class="special">;</span> 507 508 <span class="comment">// Here goes the data collected so far:</span> 509 <span class="comment">// Active connections</span> 510 <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_active_connections</span><span class="special">;</span> 511 <span class="comment">// Sent bytes</span> 512 <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_sent_bytes</span><span class="special">;</span> 513 <span class="comment">// Received bytes</span> 514 <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_received_bytes</span><span class="special">;</span> 515 516 <span class="comment">// The number of collected records since the last write to the file</span> 517 <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_collected_count</span><span class="special">;</span> 518 <span class="comment">// The time when the collected data has been written to the file last time</span> 519 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">ptime</span> <span class="identifier">m_last_store_time</span><span class="special">;</span> 520 <span class="comment">// The collected data writing interval</span> 521 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">time_duration</span> <span class="identifier">m_write_interval</span><span class="special">;</span> 522 523<span class="keyword">public</span><span class="special">:</span> 524 <span class="comment">// The constructor initializes the internal data</span> 525 <span class="identifier">stat_collector</span><span class="special">(</span><span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="identifier">file_name</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">time_duration</span> <span class="identifier">write_interval</span><span class="special">);</span> 526 527 <span class="comment">// The function consumes the log records that come from the frontend</span> 528 <span class="keyword">void</span> <span class="identifier">consume</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">record_view</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">rec</span><span class="special">);</span> 529 <span class="comment">// The function flushes the file</span> 530 <span class="keyword">void</span> <span class="identifier">flush</span><span class="special">();</span> 531 532<span class="keyword">private</span><span class="special">:</span> 533 <span class="comment">// The function resets statistical accumulators to initial values</span> 534 <span class="keyword">void</span> <span class="identifier">reset_accumulators</span><span class="special">();</span> 535 <span class="comment">// The function writes the collected data to the file</span> 536 <span class="keyword">void</span> <span class="identifier">write_data</span><span class="special">();</span> 537<span class="special">};</span> 538</pre> 539<p> 540 </p> 541<p> 542 Compared to the earlier definition we added the <code class="computeroutput"><span class="identifier">write_interval</span></code> 543 constructor parameter so we can set the statistical information flush interval 544 in the settings file. The implementation of the sink stays pretty much 545 the same as before. Now we have to define the factory: 546 </p> 547<p> 548</p> 549<pre class="programlisting"><span class="comment">// Factory for the stat_collector sink</span> 550<span class="keyword">class</span> <span class="identifier">stat_collector_factory</span> <span class="special">:</span> 551 <span class="keyword">public</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">sink_factory</span><span class="special"><</span> <span class="keyword">char</span> <span class="special">></span> 552<span class="special">{</span> 553<span class="keyword">public</span><span class="special">:</span> 554 <span class="comment">// Creates the sink with the provided parameters</span> 555 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">sink</span> <span class="special">></span> <span class="identifier">create_sink</span><span class="special">(</span><span class="identifier">settings_section</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">settings</span><span class="special">)</span> 556 <span class="special">{</span> 557 <span class="comment">// Read sink parameters</span> 558 <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">file_name</span><span class="special">;</span> 559 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">settings</span><span class="special">[</span><span class="string">"FileName"</span><span class="special">])</span> 560 <span class="identifier">file_name</span> <span class="special">=</span> <span class="identifier">param</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span> 561 <span class="keyword">else</span> 562 <span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">runtime_error</span><span class="special">(</span><span class="string">"No target file name specified in settings"</span><span class="special">);</span> 563 564 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">time_duration</span> <span class="identifier">write_interval</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">minutes</span><span class="special">(</span><span class="number">1</span><span class="special">);</span> 565 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">settings</span><span class="special">[</span><span class="string">"WriteInterval"</span><span class="special">])</span> 566 <span class="special">{</span> 567 <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">sec</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span><span class="special"><</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="special">>(</span><span class="identifier">param</span><span class="special">.</span><span class="identifier">get</span><span class="special">());</span> 568 <span class="identifier">write_interval</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">posix_time</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="identifier">sec</span><span class="special">);</span> 569 <span class="special">}</span> 570 571 <span class="comment">// Create the sink</span> 572 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">stat_collector</span> <span class="special">></span> <span class="identifier">backend</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">stat_collector</span> <span class="special">>(</span><span class="identifier">file_name</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">(),</span> <span class="identifier">write_interval</span><span class="special">);</span> 573 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronous_sink</span><span class="special"><</span> <span class="identifier">stat_collector</span> <span class="special">></span> <span class="special">></span> <span class="identifier">sink</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronous_sink</span><span class="special"><</span> <span class="identifier">stat_collector</span> <span class="special">></span> <span class="special">>(</span><span class="identifier">backend</span><span class="special">);</span> 574 575 <span class="keyword">if</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="special">></span> <span class="identifier">param</span> <span class="special">=</span> <span class="identifier">settings</span><span class="special">[</span><span class="string">"Filter"</span><span class="special">])</span> 576 <span class="special">{</span> 577 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">set_filter</span><span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">parse_filter</span><span class="special">(</span><span class="identifier">param</span><span class="special">.</span><span class="identifier">get</span><span class="special">()));</span> 578 <span class="special">}</span> 579 580 <span class="keyword">return</span> <span class="identifier">sink</span><span class="special">;</span> 581 <span class="special">}</span> 582<span class="special">};</span> 583 584<span class="keyword">void</span> <span class="identifier">init_factories</span><span class="special">()</span> 585<span class="special">{</span> 586 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">register_sink_factory</span><span class="special">(</span><span class="string">"StatCollector"</span><span class="special">,</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">stat_collector_factory</span> <span class="special">>());</span> 587<span class="special">}</span> 588</pre> 589<p> 590 </p> 591<p> 592 As you can see, we read parameters from settings and simply create our 593 sink with them as a result of <code class="computeroutput"><span class="identifier">create_sink</span></code> 594 method. Generally, users are free to name parameters of their sinks the 595 way they like, as long as <a class="link" href="../detailed/utilities.html#log.detailed.utilities.setup.settings_file" title="Library initialization from a settings file">settings 596 file format</a> is adhered. However, it is a good idea to follow the 597 pattern established by the library and reuse parameter names with the same 598 meaning. That is, it should be obvious that the parameter "Filter" 599 means the same for both the library-provided "TextFile" sink 600 and out custom "StatCollector" sink. 601 </p> 602<p> 603 After defining the factory we only have to register it with the <code class="computeroutput"><a class="link" href="../../boost/log/register_idm46079572998352.html" title="Function template register_sink_factory">register_sink_factory</a></code> 604 call. The first argument is the new value of the "Destination" 605 parameter in the settings. Whenever the library finds sink description 606 with destination "StatCollector", our factory will be invoked 607 to create the sink. It is also possible to override library-provided destination 608 types with user-defined factories, however it is not possible to restore 609 the default factories afterwards. 610 </p> 611<div class="note"><table border="0" summary="Note"> 612<tr> 613<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td> 614<th align="left">Note</th> 615</tr> 616<tr><td align="left" valign="top"><p> 617 As the "Destination" parameter is used to determine the sink 618 factory, this parameter is reserved and cannot be used by sink factories 619 for their own purposes. 620 </p></td></tr> 621</table></div> 622<p> 623 Now that the factory is registered, we can use it when initializing from 624 files or settings. For example, this is what the settings file could look 625 like: 626 </p> 627<pre class="programlisting">[Sinks.MyStat] 628 629Destination=StatCollector 630FileName=stat.csv 631WriteInterval=30 632</pre> 633<p> 634 The complete code of the example in this section can be found <a href="../../../../../../libs/log/example/doc/extension_stat_collector_settings.cpp" target="_top">here</a>. 635 </p> 636</div> 637</div> 638<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 639<td align="left"></td> 640<td align="right"><div class="copyright-footer">Copyright © 2007-2019 Andrey Semashev<p> 641 Distributed under the Boost Software License, Version 1.0. (See accompanying 642 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>). 643 </p> 644</div></td> 645</tr></table> 646<hr> 647<div class="spirit-nav"> 648<a accesskey="p" href="attributes.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="../rationale.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 649</div> 650</body> 651</html> 652