• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 
8 #include <cstddef>
9 #include <string>
10 #include <map>
11 #include <iostream>
12 #include <fstream>
13 #include <boost/smart_ptr/shared_ptr.hpp>
14 #include <boost/smart_ptr/make_shared_object.hpp>
15 #include <boost/log/sinks.hpp>
16 #include <boost/log/expressions.hpp>
17 #include <boost/log/attributes/scoped_attribute.hpp>
18 #include <boost/log/sources/logger.hpp>
19 #include <boost/log/sources/record_ostream.hpp>
20 #include <boost/log/utility/value_ref.hpp>
21 #include <boost/log/utility/manipulators/add_value.hpp>
22 
23 namespace logging = boost::log;
24 namespace src = boost::log::sources;
25 namespace expr = boost::log::expressions;
26 namespace sinks = boost::log::sinks;
27 namespace keywords = boost::log::keywords;
28 
29 //[ example_expressions_has_attr_stat_accumulator
30 // Declare attribute keywords
31 BOOST_LOG_ATTRIBUTE_KEYWORD(stat_stream, "StatisticStream", std::string)
32 BOOST_LOG_ATTRIBUTE_KEYWORD(change, "Change", int)
33 
34 // A simple sink backend to accumulate statistic information
35 class my_stat_accumulator :
36     public sinks::basic_sink_backend< sinks::synchronized_feeding >
37 {
38     // A map of accumulated statistic values,
39     // ordered by the statistic information stream name
40     typedef std::map< std::string, int > stat_info_map;
41     stat_info_map m_stat_info;
42 
43 public:
44     // Destructor
~my_stat_accumulator()45     ~my_stat_accumulator()
46     {
47         // Display the accumulated data
48         stat_info_map::const_iterator it = m_stat_info.begin(), end = m_stat_info.end();
49         for (; it != end; ++it)
50         {
51             std::cout << "Statistic stream: " << it->first
52                 << ", accumulated value: " << it->second << "\n";
53         }
54         std::cout.flush();
55     }
56 
57     // The method is called for every log record being put into the sink backend
consume(logging::record_view const & rec)58     void consume(logging::record_view const& rec)
59     {
60         // First, acquire statistic information stream name
61         logging::value_ref< std::string, tag::stat_stream > name = rec[stat_stream];
62         if (name)
63         {
64             // Next, get the statistic value change
65             logging::value_ref< int, tag::change > change_amount = rec[change];
66             if (change_amount)
67             {
68                 // Accumulate the statistic data
69                 m_stat_info[name.get()] += change_amount.get();
70             }
71         }
72     }
73 };
74 
75 // The function registers two sinks - one for statistic information,
76 // and another one for other records
init()77 void init()
78 {
79     boost::shared_ptr< logging::core > core = logging::core::get();
80 
81     // Create a backend and attach a stream to it
82     boost::shared_ptr< sinks::text_ostream_backend > backend =
83         boost::make_shared< sinks::text_ostream_backend >();
84     backend->add_stream(
85         boost::shared_ptr< std::ostream >(new std::ofstream("test.log")));
86 
87     // Create a frontend and setup filtering
88     typedef sinks::synchronous_sink< sinks::text_ostream_backend > log_sink_type;
89     boost::shared_ptr< log_sink_type > log_sink(new log_sink_type(backend));
90     // All records that don't have a "StatisticStream" attribute attached
91     // will go to the "test.log" file
92     log_sink->set_filter(!expr::has_attr(stat_stream));
93 
94     core->add_sink(log_sink);
95 
96     // Create another sink that will receive all statistic data
97     typedef sinks::synchronous_sink< my_stat_accumulator > stat_sink_type;
98     boost::shared_ptr< stat_sink_type > stat_sink(new stat_sink_type());
99     // All records with a "StatisticStream" string attribute attached
100     // will go to the my_stat_accumulator sink
101     stat_sink->set_filter(expr::has_attr(stat_stream));
102 
103     core->add_sink(stat_sink);
104 }
105 
106 // This simple macro will simplify putting statistic data into a logger
107 #define PUT_STAT(lg, stat_stream_name, change)\
108     if (true) {\
109         BOOST_LOG_SCOPED_LOGGER_TAG(lg, "StatisticStream", stat_stream_name);\
110         BOOST_LOG(lg) << logging::add_value("Change", (int)(change));\
111     } else ((void)0)
112 
logging_function()113 void logging_function()
114 {
115     src::logger lg;
116 
117     // Put a regular log record, it will go to the "test.log" file
118     BOOST_LOG(lg) << "A regular log record";
119 
120     // Put some statistic data
121     PUT_STAT(lg, "StreamOne", 10);
122     PUT_STAT(lg, "StreamTwo", 20);
123     PUT_STAT(lg, "StreamOne", -5);
124 }
125 //]
126 
main(int,char * [])127 int main(int, char*[])
128 {
129     init();
130     logging_function();
131 
132     return 0;
133 }
134