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)
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>
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
;
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
,
48 // The file to write the collected information to
49 std::ofstream m_csv_file
;
51 // Here goes the data collected so far:
53 unsigned int m_active_connections
;
55 unsigned int m_sent_bytes
;
57 unsigned int m_received_bytes
;
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
;
67 // The constructor initializes the internal data
68 stat_collector(const char* file_name
, boost::posix_time::time_duration write_interval
);
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
76 // The function resets statistical accumulators to initial values
77 void reset_accumulators();
78 // The function writes the collected data to the file
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
)
91 if (!m_csv_file
.is_open())
92 throw std::runtime_error("could not open the CSV file");
95 BOOST_LOG_ATTRIBUTE_KEYWORD(sent
, "Sent", unsigned int)
96 BOOST_LOG_ATTRIBUTE_KEYWORD(received
, "Received", unsigned int)
98 // The function consumes the log records that come from the frontend
99 void stat_collector::consume(logging::record_view
const& rec
)
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
;
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
);
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
)
119 m_last_store_time
= now
;
123 // The function writes the collected data to the file
124 void stat_collector::write_data()
126 m_csv_file
<< m_active_connections
127 << ',' << m_sent_bytes
128 << ',' << m_received_bytes
130 reset_accumulators();
133 // The function resets statistical accumulators to initial values
134 void stat_collector::reset_accumulators()
136 m_sent_bytes
= m_received_bytes
= 0;
137 m_collected_count
= 0;
140 // The function flushes the file
141 void stat_collector::flush()
143 // Store any data that may have been collected since the list write to the file
144 if (m_collected_count
> 0)
147 m_last_store_time
= boost::posix_time::microsec_clock::universal_time();
153 //[ example_extension_stat_collector_factory
154 // Factory for the stat_collector sink
155 class stat_collector_factory
:
156 public logging::sink_factory
< char >
159 // Creates the sink with the provided parameters
160 boost::shared_ptr
< sinks::sink
> create_sink(settings_section
const& settings
)
162 // Read sink parameters
163 std::string file_name
;
164 if (boost::optional
< std::string
> param
= settings
["FileName"])
165 file_name
= param
.get();
167 throw std::runtime_error("No target file name specified in settings");
169 boost::posix_time::time_duration write_interval
= boost::posix_time::minutes(1);
170 if (boost::optional
< std::string
> param
= settings
["WriteInterval"])
172 unsigned int sec
= boost::lexical_cast
< unsigned int >(param
.get());
173 write_interval
= boost::posix_time::seconds(sec
);
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
);
180 if (boost::optional
< std::string
> param
= settings
["Filter"])
182 sink
->set_filter(logging::parse_filter(param
.get()));
189 void init_factories()
191 logging::register_sink_factory("StatCollector", boost::make_shared
< stat_collector_factory
>());
195 const char settings
[] =
197 "Destination=StatCollector\n"
198 "FileName=stat.csv\n"
206 std::istringstream
strm(settings
);
207 logging::init_from_stream(strm
);
210 int main(int, char*[])
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);
219 logging::core::get()->flush();