1<html> 2<head> 3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 4<title>Filtering revisited</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="../tutorial.html" title="Tutorial"> 9<link rel="prev" href="formatters.html" title="Log record formatting"> 10<link rel="next" href="wide_char.html" title="Wide character logging"> 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="formatters.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.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="wide_char.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.tutorial.advanced_filtering"></a><a class="link" href="advanced_filtering.html" title="Filtering revisited">Filtering revisited</a> 21</h3></div></div></div> 22<p> 23 We've already touched filtering in the previous sections but we barely scratched 24 the surface. Now that we are able to add attributes to log records and set 25 up sinks, we can build however complex filtering we need. Let's consider 26 this example: 27 </p> 28<p> 29</p> 30<pre class="programlisting"><span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">line_id</span><span class="special">,</span> <span class="string">"LineID"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span><span class="special">)</span> 31<span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">severity</span><span class="special">,</span> <span class="string">"Severity"</span><span class="special">,</span> <span class="identifier">severity_level</span><span class="special">)</span> 32<span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">,</span> <span class="string">"Tag"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">)</span> 33 34<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span> 35<span class="special">{</span> 36 <span class="comment">// Setup the common formatter for all sinks</span> 37 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">formatter</span> <span class="identifier">fmt</span> <span class="special">=</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> 38 <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setw</span><span class="special">(</span><span class="number">6</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setfill</span><span class="special">(</span><span class="char">'0'</span><span class="special">)</span> <span class="special"><<</span> <span class="identifier">line_id</span> <span class="special"><<</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">setfill</span><span class="special">(</span><span class="char">' '</span><span class="special">)</span> 39 <span class="special"><<</span> <span class="string">": <"</span> <span class="special"><<</span> <span class="identifier">severity</span> <span class="special"><<</span> <span class="string">">\t"</span> 40 <span class="special"><<</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">if_</span><span class="special">(</span><span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">))</span> 41 <span class="special">[</span> 42 <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special"><<</span> <span class="string">"["</span> <span class="special"><<</span> <span class="identifier">tag_attr</span> <span class="special"><<</span> <span class="string">"] "</span> 43 <span class="special">]</span> 44 <span class="special"><<</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">smessage</span><span class="special">;</span> 45 46 <span class="comment">// Initialize sinks</span> 47 <span class="keyword">typedef</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronous_sink</span><span class="special"><</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">text_ostream_backend</span> <span class="special">></span> <span class="identifier">text_sink</span><span class="special">;</span> 48 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special"><</span> <span class="identifier">text_sink</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">text_sink</span> <span class="special">>();</span> 49 50 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">locked_backend</span><span class="special">()-></span><span class="identifier">add_stream</span><span class="special">(</span> 51 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">>(</span><span class="string">"full.log"</span><span class="special">));</span> 52 53 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span> 54 55 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">get</span><span class="special">()-></span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">sink</span><span class="special">);</span> 56 57 <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">text_sink</span> <span class="special">>();</span> 58 59 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">locked_backend</span><span class="special">()-></span><span class="identifier">add_stream</span><span class="special">(</span> 60 <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special"><</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">>(</span><span class="string">"important.log"</span><span class="special">));</span> 61 62 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span> 63 64 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">set_filter</span><span class="special">(</span><span class="identifier">severity</span> <span class="special">>=</span> <span class="identifier">warning</span> <span class="special">||</span> <span class="special">(</span><span class="identifier">expr</span><span class="special">::</span><span class="identifier">has_attr</span><span class="special">(</span><span class="identifier">tag_attr</span><span class="special">)</span> <span class="special">&&</span> <span class="identifier">tag_attr</span> <span class="special">==</span> <span class="string">"IMPORTANT_MESSAGE"</span><span class="special">));</span> 65 66 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">core</span><span class="special">::</span><span class="identifier">get</span><span class="special">()-></span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">sink</span><span class="special">);</span> 67 68 <span class="comment">// Add attributes</span> 69 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">add_common_attributes</span><span class="special">();</span> 70<span class="special">}</span> 71</pre> 72<p> 73 </p> 74<p> 75 <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">See the complete 76 code</a>. 77 </p> 78<p> 79 In this sample we initialize two sinks - one for the complete log file and 80 the other for important messages only. Both sinks will be writing to text 81 files with the same log record format, which we initialize first and save 82 to the <code class="computeroutput"><span class="identifier">fmt</span></code> variable. The 83 <code class="computeroutput"><a class="link" href="../../boost/log/basic_formatter.html" title="Class template basic_formatter">formatter</a></code> type is 84 a type-erased function object with the formatter calling signature; in many 85 respects it can be viewed similar to <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">function</span></code> 86 or <code class="computeroutput"><span class="identifier">std</span><span class="special">::</span><span class="identifier">function</span></code> except that it is never empty. 87 There is also <code class="computeroutput"><a class="link" href="../../boost/log/filter.html" title="Class filter">a similar function object</a></code> 88 for filters. 89 </p> 90<p> 91 Notably, the formatter itself contains a filter here. As you can see, the 92 format contains a conditional part that is only present when log records 93 contain the "Tag" attribute. The <a class="link" href="../detailed/expressions.html#log.detailed.expressions.predicates.has_attr" title="Attribute presence filter"><code class="computeroutput"><span class="identifier">has_attr</span></code></a> predicate checks whether 94 the record contains the "Tag" attribute value and controls whether 95 it is put into the file or not. We used the attribute keyword to specify 96 the name and type of the attribute for the predicate, but it is also possible 97 to specify them in the <a class="link" href="../detailed/expressions.html#log.detailed.expressions.predicates.has_attr" title="Attribute presence filter"><code class="computeroutput"><span class="identifier">has_attr</span></code></a> call site. Conditional 98 formatters are explained in more details <a class="link" href="../detailed/expressions.html#log.detailed.expressions.formatters.conditional" title="Conditional formatters">here</a>. 99 </p> 100<p> 101 Further goes the initialization of the two sinks. The first sink does not 102 have any filter, which means it will save every log record to the file. We 103 call <code class="computeroutput"><span class="identifier">set_filter</span></code> on the second 104 sink to only save log records with severity no less than <code class="computeroutput"><span class="identifier">warning</span></code> 105 or having a "Tag" attribute with value "IMPORTANT_MESSAGE". 106 As you can see, the filter syntax resembles usual C++ very much, especially 107 when attribute keywords are used. 108 </p> 109<p> 110 Like with formatters, it is also possible to use custom functions as filters. 111 Fundamentally, a filter function must support the following signature: 112 </p> 113<pre class="programlisting"><span class="keyword">bool</span> <span class="special">(</span><span class="identifier">logging</span><span class="special">::</span><span class="identifier">attribute_value_set</span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">attrs</span><span class="special">);</span> 114</pre> 115<p> 116 When the filter is called, <code class="computeroutput"><span class="identifier">attrs</span></code> 117 will contain a complete set of attribute values, which can be used to decide 118 whether the log record should be passed or suppressed. If the filter returns 119 <code class="computeroutput"><span class="keyword">true</span></code>, the log record will be 120 constructed and further processed by sinks. Otherwise, the record will be 121 discarded. 122 </p> 123<p> 124 <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a> 125 can be very helpful in constructing filters. It allows to automate extraction 126 of attribute values from the <code class="computeroutput"><span class="identifier">attrs</span></code> 127 set as its <code class="computeroutput"><span class="identifier">bind</span></code> implementation 128 is compatible with attribute placeholders. The previous example can be modified 129 in the following way: 130 </p> 131<p> 132</p> 133<pre class="programlisting"><span class="keyword">bool</span> <span class="identifier">my_filter</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">severity_level</span><span class="special">,</span> <span class="identifier">tag</span><span class="special">::</span><span class="identifier">severity</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">level</span><span class="special">,</span> 134 <span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</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">tag</span><span class="special">::</span><span class="identifier">tag_attr</span> <span class="special">></span> <span class="keyword">const</span><span class="special">&</span> <span class="identifier">tag</span><span class="special">)</span> 135<span class="special">{</span> 136 <span class="keyword">return</span> <span class="identifier">level</span> <span class="special">>=</span> <span class="identifier">warning</span> <span class="special">||</span> <span class="identifier">tag</span> <span class="special">==</span> <span class="string">"IMPORTANT_MESSAGE"</span><span class="special">;</span> 137<span class="special">}</span> 138 139<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span> 140<span class="special">{</span> 141 <span class="comment">// ...</span> 142 143 <span class="keyword">namespace</span> <span class="identifier">phoenix</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">phoenix</span><span class="special">;</span> 144 <span class="identifier">sink</span><span class="special">-></span><span class="identifier">set_filter</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">my_filter</span><span class="special">,</span> <span class="identifier">severity</span><span class="special">.</span><span class="identifier">or_none</span><span class="special">(),</span> <span class="identifier">tag_attr</span><span class="special">.</span><span class="identifier">or_none</span><span class="special">()));</span> 145 146 <span class="comment">// ...</span> 147<span class="special">}</span> 148</pre> 149<p> 150 </p> 151<p> 152 As you can see, the custom filter receives attribute values as separate arguments, 153 wrapped 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> template. This wrapper 154 contains an optional reference to the attribute value of the specified type; 155 the reference is valid if the log record contains the attribute value of 156 the required type. The relational operators used in <code class="computeroutput"><span class="identifier">my_filter</span></code> 157 can be applied unconditionally because they will automatically return <code class="computeroutput"><span class="keyword">false</span></code> if the reference is not valid. The rest 158 is done with the <code class="computeroutput"><span class="identifier">bind</span></code> expression 159 which will recognize the <code class="computeroutput"><span class="identifier">severity</span></code> 160 and <code class="computeroutput"><span class="identifier">tag_attr</span></code> keywords and 161 extract the corresponding values before passing them to <code class="computeroutput"><span class="identifier">my_filter</span></code>. 162 </p> 163<div class="note"><table border="0" summary="Note"> 164<tr> 165<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td> 166<th align="left">Note</th> 167</tr> 168<tr><td align="left" valign="top"><p> 169 Because of limitations related to the integration with <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a> 170 (see <a href="https://svn.boost.org/trac/boost/ticket/7996" target="_top">#7996</a>), it is required to explicitly specify the fallback policy 171 in case if the attribute value is missing, when attribute keywords are 172 used with <code class="computeroutput"><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">bind</span></code> or <code class="computeroutput"><span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">function</span></code>. 173 In the example above, this is done by calling <code class="computeroutput"><span class="identifier">or_none</span></code>, 174 which results in an empty <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> if the value is not 175 found. In other contexts this policy is the default. There are <a class="link" href="../detailed/expressions.html#log.detailed.expressions.attr.fallback_policies" title="Customizing fallback policy">other 176 policies</a> that can be used instead. 177 </p></td></tr> 178</table></div> 179<p> 180 You can try how this works by compiling and running the <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">test</a>. 181 </p> 182</div> 183<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr> 184<td align="left"></td> 185<td align="right"><div class="copyright-footer">Copyright © 2007-2019 Andrey Semashev<p> 186 Distributed under the Boost Software License, Version 1.0. (See accompanying 187 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>). 188 </p> 189</div></td> 190</tr></table> 191<hr> 192<div class="spirit-nav"> 193<a accesskey="p" href="formatters.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.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="wide_char.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a> 194</div> 195</body> 196</html> 197