]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 <string> | |
9 | #include <fstream> | |
10 | #include <sstream> | |
11 | #include <iostream> | |
12 | #include <stdexcept> | |
13 | #include <boost/smart_ptr/shared_ptr.hpp> | |
14 | #include <boost/smart_ptr/make_shared_object.hpp> | |
15 | #include <boost/lexical_cast.hpp> | |
16 | #include <boost/optional/optional.hpp> | |
17 | #include <boost/date_time/posix_time/posix_time_types.hpp> | |
18 | #include <boost/phoenix.hpp> | |
19 | #include <boost/log/core.hpp> | |
20 | #include <boost/log/expressions.hpp> | |
21 | #include <boost/log/sinks/basic_sink_backend.hpp> | |
22 | #include <boost/log/sinks/sync_frontend.hpp> | |
23 | #include <boost/log/sources/logger.hpp> | |
24 | #include <boost/log/sources/record_ostream.hpp> | |
25 | #include <boost/log/attributes/value_visitation.hpp> | |
26 | #include <boost/log/utility/manipulators/add_value.hpp> | |
27 | #include <boost/log/utility/setup/filter_parser.hpp> | |
28 | #include <boost/log/utility/setup/from_stream.hpp> | |
29 | #include <boost/log/utility/setup/from_settings.hpp> | |
30 | ||
31 | namespace logging = boost::log; | |
32 | namespace src = boost::log::sources; | |
33 | namespace expr = boost::log::expressions; | |
34 | namespace sinks = boost::log::sinks; | |
35 | namespace keywords = boost::log::keywords; | |
36 | ||
37 | //[ example_extension_stat_collector_settings_definition | |
38 | // The backend collects statistical information about network activity of the application | |
39 | class stat_collector : | |
40 | public sinks::basic_sink_backend< | |
41 | sinks::combine_requirements< | |
42 | sinks::synchronized_feeding, | |
43 | sinks::flushing | |
44 | >::type | |
45 | > | |
46 | { | |
47 | private: | |
48 | // The file to write the collected information to | |
49 | std::ofstream m_csv_file; | |
50 | ||
51 | // Here goes the data collected so far: | |
52 | // Active connections | |
53 | unsigned int m_active_connections; | |
54 | // Sent bytes | |
55 | unsigned int m_sent_bytes; | |
56 | // Received bytes | |
57 | unsigned int m_received_bytes; | |
58 | ||
59 | // The number of collected records since the last write to the file | |
60 | unsigned int m_collected_count; | |
61 | // The time when the collected data has been written to the file last time | |
62 | boost::posix_time::ptime m_last_store_time; | |
63 | // The collected data writing interval | |
64 | boost::posix_time::time_duration m_write_interval; | |
65 | ||
66 | public: | |
67 | // The constructor initializes the internal data | |
68 | stat_collector(const char* file_name, boost::posix_time::time_duration write_interval); | |
69 | ||
70 | // The function consumes the log records that come from the frontend | |
71 | void consume(logging::record_view const& rec); | |
72 | // The function flushes the file | |
73 | void flush(); | |
74 | ||
75 | private: | |
76 | // The function resets statistical accumulators to initial values | |
77 | void reset_accumulators(); | |
78 | // The function writes the collected data to the file | |
79 | void write_data(); | |
80 | }; | |
81 | //] | |
82 | ||
83 | // The constructor initializes the internal data | |
84 | stat_collector::stat_collector(const char* file_name, boost::posix_time::time_duration write_interval) : | |
85 | m_csv_file(file_name, std::ios::app), | |
86 | m_active_connections(0), | |
87 | m_last_store_time(boost::posix_time::microsec_clock::universal_time()), | |
88 | m_write_interval(write_interval) | |
89 | { | |
90 | reset_accumulators(); | |
91 | if (!m_csv_file.is_open()) | |
92 | throw std::runtime_error("could not open the CSV file"); | |
93 | } | |
94 | ||
95 | BOOST_LOG_ATTRIBUTE_KEYWORD(sent, "Sent", unsigned int) | |
96 | BOOST_LOG_ATTRIBUTE_KEYWORD(received, "Received", unsigned int) | |
97 | ||
98 | // The function consumes the log records that come from the frontend | |
99 | void stat_collector::consume(logging::record_view const& rec) | |
100 | { | |
101 | // Accumulate statistical readings | |
102 | if (rec.attribute_values().count("Connected")) | |
103 | ++m_active_connections; | |
104 | else if (rec.attribute_values().count("Disconnected")) | |
105 | --m_active_connections; | |
106 | else | |
107 | { | |
108 | namespace phoenix = boost::phoenix; | |
109 | logging::visit(sent, rec, phoenix::ref(m_sent_bytes) += phoenix::placeholders::_1); | |
110 | logging::visit(received, rec, phoenix::ref(m_received_bytes) += phoenix::placeholders::_1); | |
111 | } | |
112 | ++m_collected_count; | |
113 | ||
114 | // Check if it's time to write the accumulated data to the file | |
115 | boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time(); | |
116 | if (now - m_last_store_time >= m_write_interval) | |
117 | { | |
118 | write_data(); | |
119 | m_last_store_time = now; | |
120 | } | |
121 | } | |
122 | ||
123 | // The function writes the collected data to the file | |
124 | void stat_collector::write_data() | |
125 | { | |
126 | m_csv_file << m_active_connections | |
127 | << ',' << m_sent_bytes | |
128 | << ',' << m_received_bytes | |
129 | << std::endl; | |
130 | reset_accumulators(); | |
131 | } | |
132 | ||
133 | // The function resets statistical accumulators to initial values | |
134 | void stat_collector::reset_accumulators() | |
135 | { | |
136 | m_sent_bytes = m_received_bytes = 0; | |
137 | m_collected_count = 0; | |
138 | } | |
139 | ||
140 | // The function flushes the file | |
141 | void stat_collector::flush() | |
142 | { | |
143 | // Store any data that may have been collected since the list write to the file | |
144 | if (m_collected_count > 0) | |
145 | { | |
146 | write_data(); | |
147 | m_last_store_time = boost::posix_time::microsec_clock::universal_time(); | |
148 | } | |
149 | ||
150 | m_csv_file.flush(); | |
151 | } | |
152 | ||
153 | //[ example_extension_stat_collector_factory | |
154 | // Factory for the stat_collector sink | |
155 | class stat_collector_factory : | |
156 | public logging::sink_factory< char > | |
157 | { | |
158 | public: | |
159 | // Creates the sink with the provided parameters | |
160 | boost::shared_ptr< sinks::sink > create_sink(settings_section const& settings) | |
161 | { | |
162 | // Read sink parameters | |
163 | std::string file_name; | |
164 | if (boost::optional< std::string > param = settings["FileName"]) | |
165 | file_name = param.get(); | |
166 | else | |
167 | throw std::runtime_error("No target file name specified in settings"); | |
168 | ||
169 | boost::posix_time::time_duration write_interval = boost::posix_time::minutes(1); | |
170 | if (boost::optional< std::string > param = settings["WriteInterval"]) | |
171 | { | |
172 | unsigned int sec = boost::lexical_cast< unsigned int >(param.get()); | |
173 | write_interval = boost::posix_time::seconds(sec); | |
174 | } | |
175 | ||
176 | // Create the sink | |
177 | boost::shared_ptr< stat_collector > backend = boost::make_shared< stat_collector >(file_name.c_str(), write_interval); | |
178 | boost::shared_ptr< sinks::synchronous_sink< stat_collector > > sink = boost::make_shared< sinks::synchronous_sink< stat_collector > >(backend); | |
179 | ||
180 | if (boost::optional< std::string > param = settings["Filter"]) | |
181 | { | |
182 | sink->set_filter(logging::parse_filter(param.get())); | |
183 | } | |
184 | ||
185 | return sink; | |
186 | } | |
187 | }; | |
188 | ||
189 | void init_factories() | |
190 | { | |
191 | logging::register_sink_factory("StatCollector", boost::make_shared< stat_collector_factory >()); | |
192 | } | |
193 | //] | |
194 | ||
195 | const char settings[] = | |
196 | "[Sinks.MyStat]\n" | |
197 | "Destination=StatCollector\n" | |
198 | "FileName=stat.csv\n" | |
199 | "WriteInterval=30\n" | |
200 | ; | |
201 | ||
202 | void init_logging() | |
203 | { | |
204 | init_factories(); | |
205 | ||
206 | std::istringstream strm(settings); | |
207 | logging::init_from_stream(strm); | |
208 | } | |
209 | ||
210 | int main(int, char*[]) | |
211 | { | |
212 | init_logging(); | |
213 | ||
214 | src::logger lg; | |
215 | BOOST_LOG(lg) << logging::add_value("Connected", true); | |
216 | BOOST_LOG(lg) << logging::add_value("Sent", 100u); | |
217 | BOOST_LOG(lg) << logging::add_value("Received", 200u); | |
218 | ||
219 | logging::core::get()->flush(); | |
220 | ||
221 | return 0; | |
222 | } |