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 1. 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"><<</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>
<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>
<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>
<span class="special">[</span>
<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>
<span class="special">]</span>
<span class="special"><<</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"><</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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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"><</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>
<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>
<span class="special">{</span>
<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>
<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">-></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>
<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 © 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>
|