summaryrefslogtreecommitdiff
path: root/libs/log/doc/html/log/tutorial/advanced_filtering.html
blob: 6723cf5246feed918b1ddbfeb9d6363b81d6fbdc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Filtering revisited</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.78.1">
<link rel="home" href="../../index.html" title="Chapter&#160;1.&#160;Boost.Log v2">
<link rel="up" href="../tutorial.html" title="Tutorial">
<link rel="prev" href="formatters.html" title="Log record formatting">
<link rel="next" href="wide_char.html" title="Wide character logging">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr><td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td></tr></table>
<hr>
<div class="spirit-nav">
<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>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="log.tutorial.advanced_filtering"></a><a class="link" href="advanced_filtering.html" title="Filtering revisited">Filtering revisited</a>
</h3></div></div></div>
<p>
        We've already touched filtering in the previous sections but we barely scratched
        the surface. Now that we are able to add attributes to log records and set
        up sinks, we can build however complex filtering we need. Let's consider
        this example:
      </p>
<p>
</p>
<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>
<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>
<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>

<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span>
<span class="special">{</span>
    <span class="comment">// Setup the common formatter for all sinks</span>
    <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>
        <span class="special">&lt;&lt;</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">&lt;&lt;</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">&lt;&lt;</span> <span class="identifier">line_id</span> <span class="special">&lt;&lt;</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>
        <span class="special">&lt;&lt;</span> <span class="string">": &lt;"</span> <span class="special">&lt;&lt;</span> <span class="identifier">severity</span> <span class="special">&lt;&lt;</span> <span class="string">"&gt;\t"</span>
        <span class="special">&lt;&lt;</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>
           <span class="special">[</span>
               <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special">&lt;&lt;</span> <span class="string">"["</span> <span class="special">&lt;&lt;</span> <span class="identifier">tag_attr</span> <span class="special">&lt;&lt;</span> <span class="string">"] "</span>
           <span class="special">]</span>
        <span class="special">&lt;&lt;</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">smessage</span><span class="special">;</span>

    <span class="comment">// Initialize sinks</span>
    <span class="keyword">typedef</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronous_sink</span><span class="special">&lt;</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">text_ostream_backend</span> <span class="special">&gt;</span> <span class="identifier">text_sink</span><span class="special">;</span>
    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;</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">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;();</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">locked_backend</span><span class="special">()-&gt;</span><span class="identifier">add_stream</span><span class="special">(</span>
        <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">&gt;(</span><span class="string">"full.log"</span><span class="special">));</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span>

    <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">()-&gt;</span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">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">&lt;</span> <span class="identifier">text_sink</span> <span class="special">&gt;();</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">locked_backend</span><span class="special">()-&gt;</span><span class="identifier">add_stream</span><span class="special">(</span>
        <span class="identifier">boost</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">ofstream</span> <span class="special">&gt;(</span><span class="string">"important.log"</span><span class="special">));</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_formatter</span><span class="special">(</span><span class="identifier">fmt</span><span class="special">);</span>

    <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_filter</span><span class="special">(</span><span class="identifier">severity</span> <span class="special">&gt;=</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">&amp;&amp;</span> <span class="identifier">tag_attr</span> <span class="special">==</span> <span class="string">"IMPORTANT_MESSAGE"</span><span class="special">));</span>

    <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">()-&gt;</span><span class="identifier">add_sink</span><span class="special">(</span><span class="identifier">sink</span><span class="special">);</span>

    <span class="comment">// Add attributes</span>
    <span class="identifier">logging</span><span class="special">::</span><span class="identifier">add_common_attributes</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
      </p>
<p>
        <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">See the complete
        code</a>.
      </p>
<p>
        In this sample we initialize two sinks - one for the complete log file and
        the other for important messages only. Both sinks will be writing to text
        files with the same log record format, which we initialize first and save
        to the <code class="computeroutput"><span class="identifier">fmt</span></code> variable. The
        <code class="computeroutput"><a class="link" href="../../boost/log/basic_formatter.html" title="Class template basic_formatter">formatter</a></code> type is
        a type-erased function object with the formatter calling signature; in many
        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>
        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.
        There is also <code class="computeroutput"><a class="link" href="../../boost/log/filter.html" title="Class filter">a similar function object</a></code>
        for filters.
      </p>
<p>
        Notably, the formatter itself contains a filter here. As you can see, the
        format contains a conditional part that is only present when log records
        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
        the record contains the "Tag" attribute value and controls whether
        it is put into the file or not. We used the attribute keyword to specify
        the name and type of the attribute for the predicate, but it is also possible
        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
        formatters are explained in more details <a class="link" href="../detailed/expressions.html#log.detailed.expressions.formatters.conditional" title="Conditional formatters">here</a>.
      </p>
<p>
        Further goes the initialization of the two sinks. The first sink does not
        have any filter, which means it will save every log record to the file. We
        call <code class="computeroutput"><span class="identifier">set_filter</span></code> on the second
        sink to only save log records with severity no less than <code class="computeroutput"><span class="identifier">warning</span></code>
        or having a "Tag" attribute with value "IMPORTANT_MESSAGE".
        As you can see, the filter syntax resembles usual C++ very much, especially
        when attribute keywords are used.
      </p>
<p>
        Like with formatters, it is also possible to use custom functions as filters.
        <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a>
        can be very helpful in this case as its <code class="computeroutput"><span class="identifier">bind</span></code>
        implementation is compatible with attribute placeholders. The previous example
        can be modified in the following way:
      </p>
<p>
</p>
<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">&lt;</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">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">level</span><span class="special">,</span>
               <span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special">&lt;</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">&gt;</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">tag</span><span class="special">)</span>
<span class="special">{</span>
    <span class="keyword">return</span> <span class="identifier">level</span> <span class="special">&gt;=</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>
<span class="special">}</span>

<span class="keyword">void</span> <span class="identifier">init</span><span class="special">()</span>
<span class="special">{</span>
    <span class="comment">// ...</span>

    <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>
    <span class="identifier">sink</span><span class="special">-&gt;</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">(&amp;</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>

    <span class="comment">// ...</span>
<span class="special">}</span>
</pre>
<p>
      </p>
<p>
        As you can see, the custom formatter receives attribute values 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 contains an optional reference to the attribute value
        of the specified type; the reference is valid if the log record contains
        the attribute value of the required type. The relational operators used in
        <code class="computeroutput"><span class="identifier">my_filter</span></code> 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 is done with the <code class="computeroutput"><span class="identifier">bind</span></code>
        expression which will recognize the <code class="computeroutput"><span class="identifier">severity</span></code>
        and <code class="computeroutput"><span class="identifier">tag_attr</span></code> keywords and
        extract the corresponding values before passing them to <code class="computeroutput"><span class="identifier">my_filter</span></code>.
      </p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
          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>
          (see <a href="https://svn.boost.org/trac/boost/ticket/7996" target="_top">#7996</a>), it is required to explicitly specify the fallback policy
          in case if the attribute value is missing, when attribute keywords are
          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>.
          In the example above, this is done by calling <code class="computeroutput"><span class="identifier">or_none</span></code>,
          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
          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
          policies</a> that can be used instead.
        </p></td></tr>
</table></div>
<p>
        You can try how this works by compiling and running the <a href="../../../../../../libs/log/example/doc/tutorial_filtering.cpp" target="_top">test</a>.
      </p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright &#169; 2007-2014 Andrey Semashev<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        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>).
      </p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<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>
</div>
</body>
</html>