Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / log / doc / html / log / extension.html
1 <html>
2 <head>
3 <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
4 <title>Extending the library</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&#160;1.&#160;Boost.Log v2">
8 <link rel="up" href="../index.html" title="Chapter&#160;1.&#160;Boost.Log v2">
9 <link rel="prev" href="detailed/utilities.html" title="Utilities">
10 <link rel="next" href="extension/sources.html" title="Writing your own sources">
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="detailed/utilities.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.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="extension/sources.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
17 </div>
18 <div class="section">
19 <div class="titlepage"><div><div><h2 class="title" style="clear: both">
20 <a name="log.extension"></a><a class="link" href="extension.html" title="Extending the library">Extending the library</a>
21 </h2></div></div></div>
22 <div class="toc"><dl class="toc">
23 <dt><span class="section"><a href="extension.html#log.extension.sinks">Writing your own sinks</a></span></dt>
24 <dt><span class="section"><a href="extension/sources.html">Writing your own sources</a></span></dt>
25 <dt><span class="section"><a href="extension/attributes.html">Writing your own attributes</a></span></dt>
26 <dt><span class="section"><a href="extension/settings.html">Extending library settings support</a></span></dt>
27 </dl></div>
28 <div class="section">
29 <div class="titlepage"><div><div><h3 class="title">
30 <a name="log.extension.sinks"></a><a class="link" href="extension.html#log.extension.sinks" title="Writing your own sinks">Writing your own sinks</a>
31 </h3></div></div></div>
32 <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><code class="computeroutput"><a class="link" href="../sinks.html#header.boost.log.sinks.basic_sink_backend_hpp" title="Header &lt;boost/log/sinks/basic_sink_backend.hpp&gt;">boost/log/sinks/basic_sink_backend.hpp</a></code><span class="special">&gt;</span>
33 </pre>
34 <p>
35         As was described in the <a class="link" href="design.html" title="Design overview">Design overview</a>
36         section, sinks consist of two parts: frontend and backend. Frontends are
37         provided by the library and usually do not need to be reimplemented. Thanks
38         to frontends, implementing backends is much easier than it could be: all
39         filtering, formatting and thread synchronization is done there.
40       </p>
41 <p>
42         In order to develop a sink backend, you derive your class from either <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_sink_backend.html" title="Struct template basic_sink_backend">basic_sink_backend</a></code>
43         or <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_fo_idm45711346315728.html" title="Struct template basic_formatted_sink_backend">basic_formatted_sink_backend</a></code>,
44         depending on whether your backend requires formatted log records or not.
45         Both base classes define a set of types that are required to interface with
46         sink frontends. One of these types is <code class="computeroutput"><span class="identifier">frontend_requirements</span></code>.
47       </p>
48 <h5>
49 <a name="log.extension.sinks.h0"></a>
50         <span class="phrase"><a name="log.extension.sinks.frontend_requirements"></a></span><a class="link" href="extension.html#log.extension.sinks.frontend_requirements">Frontend
51         requirements</a>
52       </h5>
53 <pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><code class="computeroutput"><a class="link" href="../sinks.html#header.boost.log.sinks.frontend_requirements_hpp" title="Header &lt;boost/log/sinks/frontend_requirements.hpp&gt;">boost/log/sinks/frontend_requirements.hpp</a></code><span class="special">&gt;</span>
54 </pre>
55 <p>
56         In order to work with sink backends, frontends use the <code class="computeroutput"><span class="identifier">frontend_requirements</span></code>
57         type defined by all backends. The type combines one or several requirement
58         tags:
59       </p>
60 <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
61 <li class="listitem">
62             <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronized_feeding.html" title="Struct synchronized_feeding">synchronized_feeding</a></code>.
63             If the backend has this requirement, it expects log records to be passed
64             from frontend in synchronized manner (i.e. only one thread should be
65             feeding a record at a time). Note that different threads may be feeding
66             different records, the requirement merely states that there will be no
67             concurrent feeds.
68           </li>
69 <li class="listitem">
70             <code class="computeroutput"><a class="link" href="../boost/log/sinks/concurrent_feeding.html" title="Struct concurrent_feeding">concurrent_feeding</a></code>.
71             This requirement extends <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronized_feeding.html" title="Struct synchronized_feeding">synchronized_feeding</a></code>
72             by allowing different threads to feed records concurrently. The backend
73             implements all necessary thread synchronization in this case.
74           </li>
75 <li class="listitem">
76             <code class="computeroutput"><a class="link" href="../boost/log/sinks/formatted_records.html" title="Struct formatted_records">formatted_records</a></code>.
77             The backend expects formatted log records. The frontend implements formatting
78             to a string with character type defined by the <code class="computeroutput"><span class="identifier">char_type</span></code>
79             typedef within the backend. The formatted string will be passed along
80             with the log record to the backend. The <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_fo_idm45711346315728.html" title="Struct template basic_formatted_sink_backend">basic_formatted_sink_backend</a></code>
81             base class automatically adds this requirement to the <code class="computeroutput"><span class="identifier">frontend_requirements</span></code>
82             type.
83           </li>
84 <li class="listitem">
85             <code class="computeroutput"><a class="link" href="../boost/log/sinks/flushing.html" title="Struct flushing">flushing</a></code>. The
86             backend supports flushing its internal buffers. If the backend indicates
87             this requirement it has to implement the <code class="computeroutput"><span class="identifier">flush</span></code>
88             method taking no arguments; this method will be called by the frontend
89             when flushed.
90           </li>
91 </ul></div>
92 <div class="tip"><table border="0" summary="Tip">
93 <tr>
94 <td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../../../doc/src/images/tip.png"></td>
95 <th align="left">Tip</th>
96 </tr>
97 <tr><td align="left" valign="top"><p>
98           By choosing either of the thread synchronization requirements you effectively
99           allow or prohibit certain <a class="link" href="detailed/sink_frontends.html" title="Sink frontends">sink
100           frontends</a> from being used with your backend.
101         </p></td></tr>
102 </table></div>
103 <p>
104         Multiple requirements can be combined into <code class="computeroutput"><span class="identifier">frontend_requirements</span></code>
105         type with the <code class="computeroutput"><a class="link" href="../boost/log/sinks/combine_requirements.html" title="Struct template combine_requirements">combine_requirements</a></code>
106         metafunction:
107       </p>
108 <pre class="programlisting"><span class="keyword">typedef</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">combine_requirements</span><span class="special">&lt;</span>
109     <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronized_feeding</span><span class="special">,</span>
110     <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">formatted_records</span><span class="special">,</span>
111     <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">flushing</span>
112 <span class="special">&gt;::</span><span class="identifier">type</span> <span class="identifier">frontend_requirements</span><span class="special">;</span>
113 </pre>
114 <p>
115         It must be noted that <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronized_feeding.html" title="Struct synchronized_feeding">synchronized_feeding</a></code>
116         and <code class="computeroutput"><a class="link" href="../boost/log/sinks/concurrent_feeding.html" title="Struct concurrent_feeding">concurrent_feeding</a></code>
117         should not be combined together as it would make the synchronization requirement
118         ambiguous. The <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronized_feeding.html" title="Struct synchronized_feeding">synchronized_feeding</a></code>
119         is a more strict requirement than <code class="computeroutput"><a class="link" href="../boost/log/sinks/concurrent_feeding.html" title="Struct concurrent_feeding">concurrent_feeding</a></code>,
120         so whenever the backend requires concurrent feeding it is also capable of
121         synchronized feeding.
122       </p>
123 <p>
124         The <code class="computeroutput"><a class="link" href="../boost/log/sinks/has_requirement.html" title="Struct template has_requirement">has_requirement</a></code>
125         metafunction can be used to test for a specific requirement in the <code class="computeroutput"><span class="identifier">frontend_requirements</span></code> typedef.
126       </p>
127 <h5>
128 <a name="log.extension.sinks.h1"></a>
129         <span class="phrase"><a name="log.extension.sinks.minimalistic_sink_backend"></a></span><a class="link" href="extension.html#log.extension.sinks.minimalistic_sink_backend">Minimalistic
130         sink backend</a>
131       </h5>
132 <p>
133         As an example of the <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_sink_backend.html" title="Struct template basic_sink_backend">basic_sink_backend</a></code>
134         class usage, let's implement a simple statistical information collector backend.
135         Assume we have a network server and we want to monitor how many incoming
136         connections are active and how much data was sent or received. The collected
137         information should be written to a CSV-file every minute. The backend definition
138         could look something like this:
139       </p>
140 <p>
141 </p>
142 <pre class="programlisting"><span class="comment">// The backend collects statistical information about network activity of the application</span>
143 <span class="keyword">class</span> <span class="identifier">stat_collector</span> <span class="special">:</span>
144     <span class="keyword">public</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">basic_sink_backend</span><span class="special">&lt;</span>
145         <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">combine_requirements</span><span class="special">&lt;</span>
146             <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronized_feeding</span><span class="special">,</span>                                        <a class="co" name="log.extension.sinks.c0" href="extension.html#log.extension.sinks.c1"><img src="../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
147             <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">flushing</span>                                                     <a class="co" name="log.extension.sinks.c2" href="extension.html#log.extension.sinks.c3"><img src="../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a>
148         <span class="special">&gt;::</span><span class="identifier">type</span>
149     <span class="special">&gt;</span>
150 <span class="special">{</span>
151 <span class="keyword">private</span><span class="special">:</span>
152     <span class="comment">// The file to write the collected information to</span>
153     <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>
154
155     <span class="comment">// Here goes the data collected so far:</span>
156     <span class="comment">// Active connections</span>
157     <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_active_connections</span><span class="special">;</span>
158     <span class="comment">// Sent bytes</span>
159     <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_sent_bytes</span><span class="special">;</span>
160     <span class="comment">// Received bytes</span>
161     <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_received_bytes</span><span class="special">;</span>
162
163     <span class="comment">// The number of collected records since the last write to the file</span>
164     <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">m_collected_count</span><span class="special">;</span>
165     <span class="comment">// The time when the collected data has been written to the file last time</span>
166     <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>
167
168 <span class="keyword">public</span><span class="special">:</span>
169     <span class="comment">// The constructor initializes the internal data</span>
170     <span class="keyword">explicit</span> <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>
171
172     <span class="comment">// The function consumes the log records that come from the frontend</span>
173     <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">&amp;</span> <span class="identifier">rec</span><span class="special">);</span>
174     <span class="comment">// The function flushes the file</span>
175     <span class="keyword">void</span> <span class="identifier">flush</span><span class="special">();</span>
176
177 <span class="keyword">private</span><span class="special">:</span>
178     <span class="comment">// The function resets statistical accumulators to initial values</span>
179     <span class="keyword">void</span> <span class="identifier">reset_accumulators</span><span class="special">();</span>
180     <span class="comment">// The function writes the collected data to the file</span>
181     <span class="keyword">void</span> <span class="identifier">write_data</span><span class="special">();</span>
182 <span class="special">};</span>
183 </pre>
184 <p>
185       </p>
186 <div class="calloutlist"><table border="0" summary="Callout list">
187 <tr>
188 <td width="5%" valign="top" align="left"><p><a name="log.extension.sinks.c1"></a><a href="#log.extension.sinks.c0"><img src="../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
189 <td valign="top" align="left"><p>
190             we will have to store internal data, so let's require frontend to synchronize
191             feeding calls to the backend
192           </p></td>
193 </tr>
194 <tr>
195 <td width="5%" valign="top" align="left"><p><a name="log.extension.sinks.c3"></a><a href="#log.extension.sinks.c2"><img src="../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
196 <td valign="top" align="left"><p>
197             also enable flushing support
198           </p></td>
199 </tr>
200 </table></div>
201 <p>
202         As you can see, the public interface of the backend is quite simple. Only
203         the <code class="computeroutput"><span class="identifier">consume</span></code> and <code class="computeroutput"><span class="identifier">flush</span></code> methods are called by frontends.
204         The <code class="computeroutput"><span class="identifier">consume</span></code> function is called
205         every time a logging record passes filtering in the frontend. The record,
206         as was stated before, contains a set of attribute values and the message
207         string. Since we have no need for the record message, we will ignore it for
208         now. But from the other attributes we can extract the statistical data to
209         accumulate and write to the file. We can use <a class="link" href="detailed/expressions.html#log.detailed.expressions.attr_keywords" title="Defining attribute keywords">attribute
210         keywords</a> and <a class="link" href="detailed/attributes.html#log.detailed.attributes.related_components.value_processing.visitation" title="Value visitation">value
211         visitation</a> to accomplish this.
212       </p>
213 <p>
214 </p>
215 <pre class="programlisting"><span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">sent</span><span class="special">,</span> <span class="string">"Sent"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span><span class="special">)</span>
216 <span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">received</span><span class="special">,</span> <span class="string">"Received"</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span><span class="special">)</span>
217
218 <span class="comment">// The function consumes the log records that come from the frontend</span>
219 <span class="keyword">void</span> <span class="identifier">stat_collector</span><span class="special">::</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">&amp;</span> <span class="identifier">rec</span><span class="special">)</span>
220 <span class="special">{</span>
221     <span class="comment">// Accumulate statistical readings</span>
222     <span class="keyword">if</span> <span class="special">(</span><span class="identifier">rec</span><span class="special">.</span><span class="identifier">attribute_values</span><span class="special">().</span><span class="identifier">count</span><span class="special">(</span><span class="string">"Connected"</span><span class="special">))</span>
223         <span class="special">++</span><span class="identifier">m_active_connections</span><span class="special">;</span>
224     <span class="keyword">else</span> <span class="keyword">if</span> <span class="special">(</span><span class="identifier">rec</span><span class="special">.</span><span class="identifier">attribute_values</span><span class="special">().</span><span class="identifier">count</span><span class="special">(</span><span class="string">"Disconnected"</span><span class="special">))</span>
225         <span class="special">--</span><span class="identifier">m_active_connections</span><span class="special">;</span>
226     <span class="keyword">else</span>
227     <span class="special">{</span>
228         <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>
229         <span class="identifier">logging</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span><span class="identifier">sent</span><span class="special">,</span> <span class="identifier">rec</span><span class="special">,</span> <span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">m_sent_bytes</span><span class="special">)</span> <span class="special">+=</span> <span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">_1</span><span class="special">);</span>
230         <span class="identifier">logging</span><span class="special">::</span><span class="identifier">visit</span><span class="special">(</span><span class="identifier">received</span><span class="special">,</span> <span class="identifier">rec</span><span class="special">,</span> <span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">ref</span><span class="special">(</span><span class="identifier">m_received_bytes</span><span class="special">)</span> <span class="special">+=</span> <span class="identifier">phoenix</span><span class="special">::</span><span class="identifier">placeholders</span><span class="special">::</span><span class="identifier">_1</span><span class="special">);</span>
231     <span class="special">}</span>
232     <span class="special">++</span><span class="identifier">m_collected_count</span><span class="special">;</span>
233
234     <span class="comment">// Check if it's time to write the accumulated data to the file</span>
235     <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">now</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">microsec_clock</span><span class="special">::</span><span class="identifier">universal_time</span><span class="special">();</span>
236     <span class="keyword">if</span> <span class="special">(</span><span class="identifier">now</span> <span class="special">-</span> <span class="identifier">m_last_store_time</span> <span class="special">&gt;=</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>
237     <span class="special">{</span>
238         <span class="identifier">write_data</span><span class="special">();</span>
239         <span class="identifier">m_last_store_time</span> <span class="special">=</span> <span class="identifier">now</span><span class="special">;</span>
240     <span class="special">}</span>
241 <span class="special">}</span>
242
243 <span class="comment">// The function writes the collected data to the file</span>
244 <span class="keyword">void</span> <span class="identifier">stat_collector</span><span class="special">::</span><span class="identifier">write_data</span><span class="special">()</span>
245 <span class="special">{</span>
246     <span class="identifier">m_csv_file</span> <span class="special">&lt;&lt;</span> <span class="identifier">m_active_connections</span>
247         <span class="special">&lt;&lt;</span> <span class="char">','</span> <span class="special">&lt;&lt;</span> <span class="identifier">m_sent_bytes</span>
248         <span class="special">&lt;&lt;</span> <span class="char">','</span> <span class="special">&lt;&lt;</span> <span class="identifier">m_received_bytes</span>
249         <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
250     <span class="identifier">reset_accumulators</span><span class="special">();</span>
251 <span class="special">}</span>
252
253 <span class="comment">// The function resets statistical accumulators to initial values</span>
254 <span class="keyword">void</span> <span class="identifier">stat_collector</span><span class="special">::</span><span class="identifier">reset_accumulators</span><span class="special">()</span>
255 <span class="special">{</span>
256     <span class="identifier">m_sent_bytes</span> <span class="special">=</span> <span class="identifier">m_received_bytes</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
257     <span class="identifier">m_collected_count</span> <span class="special">=</span> <span class="number">0</span><span class="special">;</span>
258 <span class="special">}</span>
259 </pre>
260 <p>
261       </p>
262 <p>
263         Note that we used <a href="http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html" target="_top">Boost.Phoenix</a>
264         to automatically generate visitor function objects for attribute values.
265       </p>
266 <p>
267         The last bit of implementation is the <code class="computeroutput"><span class="identifier">flush</span></code>
268         method. It is used to flush all buffered data to the external storage, which
269         is a file in our case. The method can be implemented in the following way:
270       </p>
271 <p>
272 </p>
273 <pre class="programlisting"><span class="comment">// The function flushes the file</span>
274 <span class="keyword">void</span> <span class="identifier">stat_collector</span><span class="special">::</span><span class="identifier">flush</span><span class="special">()</span>
275 <span class="special">{</span>
276     <span class="comment">// Store any data that may have been collected since the list write to the file</span>
277     <span class="keyword">if</span> <span class="special">(</span><span class="identifier">m_collected_count</span> <span class="special">&gt;</span> <span class="number">0</span><span class="special">)</span>
278     <span class="special">{</span>
279         <span class="identifier">write_data</span><span class="special">();</span>
280         <span class="identifier">m_last_store_time</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">microsec_clock</span><span class="special">::</span><span class="identifier">universal_time</span><span class="special">();</span>
281     <span class="special">}</span>
282
283     <span class="identifier">m_csv_file</span><span class="special">.</span><span class="identifier">flush</span><span class="special">();</span>
284 <span class="special">}</span>
285 </pre>
286 <p>
287       </p>
288 <p>
289         You can find the complete code of this example <a href="../../../../../libs/log/example/doc/extension_stat_collector.cpp" target="_top">here</a>.
290       </p>
291 <h5>
292 <a name="log.extension.sinks.h2"></a>
293         <span class="phrase"><a name="log.extension.sinks.formatting_sink_backend"></a></span><a class="link" href="extension.html#log.extension.sinks.formatting_sink_backend">Formatting
294         sink backend</a>
295       </h5>
296 <p>
297         As an example of a formatting sink backend, let's implement a sink that will
298         display text notifications for every log record passed to it.
299       </p>
300 <div class="tip"><table border="0" summary="Tip">
301 <tr>
302 <td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="../../../../../doc/src/images/tip.png"></td>
303 <th align="left">Tip</th>
304 </tr>
305 <tr><td align="left" valign="top"><p>
306           Real world applications would probably use some GUI toolkit API to display
307           notifications but GUI programming is out of scope of this documentation.
308           In order to display notifications we shall use an external program which
309           does just that. In this example we shall employ <code class="computeroutput"><span class="identifier">notify</span><span class="special">-</span><span class="identifier">send</span></code>
310           program which is available on Linux (Ubuntu/Debian users can install it
311           with the <code class="computeroutput"><span class="identifier">libnotify</span><span class="special">-</span><span class="identifier">bin</span></code> package; other distros should also
312           have it available in their package repositories). The program takes the
313           notification parameters in the command line, displays the notification
314           in the current desktop environment and then exits. Other platforms may
315           also have similar tools.
316         </p></td></tr>
317 </table></div>
318 <p>
319         The definition of the backend is very similar to what we have seen in the
320         previous section:
321       </p>
322 <p>
323 </p>
324 <pre class="programlisting"><span class="comment">// The backend starts an external application to display notifications</span>
325 <span class="keyword">class</span> <span class="identifier">app_launcher</span> <span class="special">:</span>
326     <span class="keyword">public</span> <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">basic_formatted_sink_backend</span><span class="special">&lt;</span>
327         <span class="keyword">char</span><span class="special">,</span>                                                                   <a class="co" name="log.extension.sinks.c4" href="extension.html#log.extension.sinks.c5"><img src="../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a>
328         <span class="identifier">sinks</span><span class="special">::</span><span class="identifier">synchronized_feeding</span>                                             <a class="co" name="log.extension.sinks.c6" href="extension.html#log.extension.sinks.c7"><img src="../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a>
329     <span class="special">&gt;</span>
330 <span class="special">{</span>
331 <span class="keyword">public</span><span class="special">:</span>
332     <span class="comment">// The function consumes the log records that come from the frontend</span>
333     <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">&amp;</span> <span class="identifier">rec</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">command_line</span><span class="special">);</span>
334 <span class="special">};</span>
335 </pre>
336 <p>
337       </p>
338 <div class="calloutlist"><table border="0" summary="Callout list">
339 <tr>
340 <td width="5%" valign="top" align="left"><p><a name="log.extension.sinks.c5"></a><a href="#log.extension.sinks.c4"><img src="../../../../../doc/src/images/callouts/1.png" alt="1" border="0"></a> </p></td>
341 <td valign="top" align="left"><p>
342             target character type
343           </p></td>
344 </tr>
345 <tr>
346 <td width="5%" valign="top" align="left"><p><a name="log.extension.sinks.c7"></a><a href="#log.extension.sinks.c6"><img src="../../../../../doc/src/images/callouts/2.png" alt="2" border="0"></a> </p></td>
347 <td valign="top" align="left"><p>
348             in order not to spawn too many application instances we require records
349             to be processed serial
350           </p></td>
351 </tr>
352 </table></div>
353 <p>
354         The first thing to notice is that the <code class="computeroutput"><span class="identifier">app_launcher</span></code>
355         backend derives from <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_fo_idm45711346315728.html" title="Struct template basic_formatted_sink_backend">basic_formatted_sink_backend</a></code>
356         rather than <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_sink_backend.html" title="Struct template basic_sink_backend">basic_sink_backend</a></code>.
357         This base class accepts the character type in addition to the requirements.
358         The specified character type defines the target string type the formatter
359         will compose in the frontend and it typically corresponds to the underlying
360         API the backend uses to process records. It must be mentioned that the character
361         type the backend requires is not related to the character types of string
362         attribute values, including the message text. The formatter will take care
363         of character code conversion when needed.
364       </p>
365 <p>
366         The second notable difference from the previous examples is that <code class="computeroutput"><span class="identifier">consume</span></code> method takes an additional string
367         parameter besides the log record. This is the result of formatting. The
368         <code class="computeroutput"><span class="identifier">string_type</span></code> type is defined
369         by the <code class="computeroutput"><a class="link" href="../boost/log/sinks/basic_fo_idm45711346315728.html" title="Struct template basic_formatted_sink_backend">basic_formatted_sink_backend</a></code>
370         base class and it corresponds to the requested character type.
371       </p>
372 <p>
373         We don't need to flush any buffers in this example, so we didn't specify
374         the <code class="computeroutput"><a class="link" href="../boost/log/sinks/flushing.html" title="Struct flushing">flushing</a></code> requirement
375         and omitted the <code class="computeroutput"><span class="identifier">flush</span></code> method
376         in the backend. Although we don't need any synchronization in our backend,
377         we specified <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronized_feeding.html" title="Struct synchronized_feeding">synchronized_feeding</a></code>
378         requirement so that we don't spawn multiple instances of <code class="computeroutput"><span class="identifier">notify</span><span class="special">-</span><span class="identifier">send</span></code> program
379         and cause a "fork bomb".
380       </p>
381 <p>
382         Now, the <code class="computeroutput"><span class="identifier">consume</span></code> implementation
383         is trivial:
384       </p>
385 <p>
386 </p>
387 <pre class="programlisting"><span class="comment">// The function consumes the log records that come from the frontend</span>
388 <span class="keyword">void</span> <span class="identifier">app_launcher</span><span class="special">::</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">&amp;</span> <span class="identifier">rec</span><span class="special">,</span> <span class="identifier">string_type</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">command_line</span><span class="special">)</span>
389 <span class="special">{</span>
390     <span class="identifier">std</span><span class="special">::</span><span class="identifier">system</span><span class="special">(</span><span class="identifier">command_line</span><span class="special">.</span><span class="identifier">c_str</span><span class="special">());</span>
391 <span class="special">}</span>
392 </pre>
393 <p>
394       </p>
395 <p>
396         So the formatted string is expected to actually be a command line to start
397         the application. The exact application name and arguments are to be determined
398         by the formatter. This approach adds flexibility because the backend can
399         be used for different purposes and updating the command line is as easy as
400         updating the formatter.
401       </p>
402 <p>
403         The sink can be configured with the following code:
404       </p>
405 <p>
406 </p>
407 <pre class="programlisting"><span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">process_name</span><span class="special">,</span> <span class="string">"ProcessName"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">)</span>
408 <span class="identifier">BOOST_LOG_ATTRIBUTE_KEYWORD</span><span class="special">(</span><span class="identifier">caption</span><span class="special">,</span> <span class="string">"Caption"</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">)</span>
409
410 <span class="comment">// Custom severity level formatting function</span>
411 <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">severity_level_as_urgency</span><span class="special">(</span>
412     <span class="identifier">logging</span><span class="special">::</span><span class="identifier">value_ref</span><span class="special">&lt;</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</span><span class="special">::</span><span class="identifier">severity_level</span><span class="special">,</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</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>
413 <span class="special">{</span>
414     <span class="keyword">if</span> <span class="special">(!</span><span class="identifier">level</span> <span class="special">||</span> <span class="identifier">level</span><span class="special">.</span><span class="identifier">get</span><span class="special">()</span> <span class="special">==</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</span><span class="special">::</span><span class="identifier">info</span><span class="special">)</span>
415         <span class="keyword">return</span> <span class="string">"normal"</span><span class="special">;</span>
416     <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</span><span class="special">::</span><span class="identifier">severity_level</span> <span class="identifier">lvl</span> <span class="special">=</span> <span class="identifier">level</span><span class="special">.</span><span class="identifier">get</span><span class="special">();</span>
417     <span class="keyword">if</span> <span class="special">(</span><span class="identifier">lvl</span> <span class="special">&lt;</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</span><span class="special">::</span><span class="identifier">info</span><span class="special">)</span>
418         <span class="keyword">return</span> <span class="string">"low"</span><span class="special">;</span>
419     <span class="keyword">else</span>
420         <span class="keyword">return</span> <span class="string">"critical"</span><span class="special">;</span>
421 <span class="special">}</span>
422
423 <span class="comment">// The function initializes the logging library</span>
424 <span class="keyword">void</span> <span class="identifier">init_logging</span><span class="special">()</span>
425 <span class="special">{</span>
426     <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">core</span> <span class="special">&gt;</span> <span class="identifier">core</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>
427
428     <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">app_launcher</span> <span class="special">&gt;</span> <span class="identifier">sink_t</span><span class="special">;</span>
429     <span class="identifier">boost</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span> <span class="identifier">sink_t</span> <span class="special">&gt;</span> <span class="identifier">sink</span><span class="special">(</span><span class="keyword">new</span> <span class="identifier">sink_t</span><span class="special">());</span>
430
431     <span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="special">&gt;</span> <span class="identifier">shell_decorations</span><span class="special">[]</span> <span class="special">=</span>
432     <span class="special">{</span>
433         <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="special">&gt;(</span><span class="string">"\""</span><span class="special">,</span> <span class="string">"\\\""</span><span class="special">),</span>
434         <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="special">&gt;(</span><span class="string">"$"</span><span class="special">,</span> <span class="string">"\\$"</span><span class="special">),</span>
435         <span class="identifier">std</span><span class="special">::</span><span class="identifier">pair</span><span class="special">&lt;</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*,</span> <span class="keyword">const</span> <span class="keyword">char</span><span class="special">*</span> <span class="special">&gt;(</span><span class="string">"!"</span><span class="special">,</span> <span class="string">"\\!"</span><span class="special">)</span>
436     <span class="special">};</span>
437
438     <span class="comment">// Make the formatter generate the command line for notify-send</span>
439     <span class="identifier">sink</span><span class="special">-&gt;</span><span class="identifier">set_formatter</span>
440     <span class="special">(</span>
441         <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special">&lt;&lt;</span> <span class="string">"notify-send -t 2000 -u "</span>
442             <span class="special">&lt;&lt;</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">(&amp;</span><span class="identifier">severity_level_as_urgency</span><span class="special">,</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">trivial</span><span class="special">::</span><span class="identifier">severity</span><span class="special">.</span><span class="identifier">or_none</span><span class="special">())</span>
443             <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">process_name</span><span class="special">))</span>
444                <span class="special">[</span>
445                     <span class="identifier">expr</span><span class="special">::</span><span class="identifier">stream</span> <span class="special">&lt;&lt;</span> <span class="string">" -a '"</span> <span class="special">&lt;&lt;</span> <span class="identifier">process_name</span> <span class="special">&lt;&lt;</span> <span class="string">"'"</span>
446                <span class="special">]</span>
447             <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">caption</span><span class="special">))</span>
448                <span class="special">[</span>
449                     <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">expr</span><span class="special">::</span><span class="identifier">char_decor</span><span class="special">(</span><span class="identifier">shell_decorations</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">caption</span> <span class="special">]</span> <span class="special">&lt;&lt;</span> <span class="string">"\""</span>
450                <span class="special">]</span>
451             <span class="special">&lt;&lt;</span> <span class="string">" \""</span> <span class="special">&lt;&lt;</span> <span class="identifier">expr</span><span class="special">::</span><span class="identifier">char_decor</span><span class="special">(</span><span class="identifier">shell_decorations</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">expr</span><span class="special">::</span><span class="identifier">message</span> <span class="special">]</span> <span class="special">&lt;&lt;</span> <span class="string">"\""</span>
452     <span class="special">);</span>
453
454     <span class="identifier">core</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>
455
456     <span class="comment">// Add attributes that we will use</span>
457     <span class="identifier">core</span><span class="special">-&gt;</span><span class="identifier">add_global_attribute</span><span class="special">(</span><span class="string">"ProcessName"</span><span class="special">,</span> <span class="identifier">attrs</span><span class="special">::</span><span class="identifier">current_process_name</span><span class="special">());</span>
458 <span class="special">}</span>
459 </pre>
460 <p>
461       </p>
462 <p>
463         The most interesting part is the sink setup. The <code class="computeroutput"><a class="link" href="../boost/log/sinks/synchronous_sink.html" title="Class template synchronous_sink">synchronous_sink</a></code>
464         frontend (as well as any other frontend) will detect that the <code class="computeroutput"><span class="identifier">app_launcher</span></code> backend requires formatting
465         and enable the corresponding functionality. The <code class="computeroutput"><span class="identifier">set_formatter</span></code>
466         method becomes available and can be used to set the formatting expression
467         that composes the command line to start the <code class="computeroutput"><span class="identifier">notify</span><span class="special">-</span><span class="identifier">send</span></code> program.
468         We used <a class="link" href="detailed/expressions.html#log.detailed.expressions.attr_keywords" title="Defining attribute keywords">attribute
469         keywords</a> to identify particular attribute values in the formatter.
470         Notice that string attribute values have to be preprocessed so that special
471         characters interpreted by the shell are escaped in the command line. We achieve
472         that with the <code class="computeroutput"><a class="link" href="../boost/log/expressions/char_dec_idm45711347999168.html" title="Function template char_decor">char_decor</a></code> decorator with
473         our custom replacement map. After the sink is configured we also add the
474         <a class="link" href="detailed/attributes.html#log.detailed.attributes.process_name" title="Current process name">current process name</a>
475         attribute to the core so that we don't have to add it to every record.
476       </p>
477 <p>
478         After all this is done, we can finally display some notifications:
479       </p>
480 <p>
481 </p>
482 <pre class="programlisting"><span class="keyword">void</span> <span class="identifier">test_notifications</span><span class="special">()</span>
483 <span class="special">{</span>
484     <span class="identifier">BOOST_LOG_TRIVIAL</span><span class="special">(</span><span class="identifier">debug</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"Hello, it's a simple notification"</span><span class="special">;</span>
485     <span class="identifier">BOOST_LOG_TRIVIAL</span><span class="special">(</span><span class="identifier">info</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="identifier">logging</span><span class="special">::</span><span class="identifier">add_value</span><span class="special">(</span><span class="identifier">caption</span><span class="special">,</span> <span class="string">"Caption text"</span><span class="special">)</span> <span class="special">&lt;&lt;</span> <span class="string">"And this notification has caption as well"</span><span class="special">;</span>
486 <span class="special">}</span>
487 </pre>
488 <p>
489       </p>
490 <p>
491         The complete code of this example is available <a href="../../../../../libs/log/example/doc/extension_app_launcher.cpp" target="_top">here</a>.
492       </p>
493 </div>
494 </div>
495 <table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
496 <td align="left"></td>
497 <td align="right"><div class="copyright-footer">Copyright &#169; 2007-2016 Andrey Semashev<p>
498         Distributed under the Boost Software License, Version 1.0. (See accompanying
499         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>).
500       </p>
501 </div></td>
502 </tr></table>
503 <hr>
504 <div class="spirit-nav">
505 <a accesskey="p" href="detailed/utilities.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.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="extension/sources.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
506 </div>
507 </body>
508 </html>