123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- /*
- * Copyright Andrey Semashev 2007 - 2015.
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE_1_0.txt or copy at
- * http://www.boost.org/LICENSE_1_0.txt)
- */
- #include <string>
- #include <fstream>
- #include <sstream>
- #include <iostream>
- #include <stdexcept>
- #include <boost/smart_ptr/shared_ptr.hpp>
- #include <boost/smart_ptr/make_shared_object.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/optional/optional.hpp>
- #include <boost/date_time/posix_time/posix_time_types.hpp>
- #include <boost/phoenix.hpp>
- #include <boost/log/core.hpp>
- #include <boost/log/expressions.hpp>
- #include <boost/log/sinks/basic_sink_backend.hpp>
- #include <boost/log/sinks/sync_frontend.hpp>
- #include <boost/log/sources/logger.hpp>
- #include <boost/log/sources/record_ostream.hpp>
- #include <boost/log/attributes/value_visitation.hpp>
- #include <boost/log/utility/manipulators/add_value.hpp>
- #include <boost/log/utility/setup/filter_parser.hpp>
- #include <boost/log/utility/setup/from_stream.hpp>
- #include <boost/log/utility/setup/from_settings.hpp>
- namespace logging = boost::log;
- namespace src = boost::log::sources;
- namespace expr = boost::log::expressions;
- namespace sinks = boost::log::sinks;
- namespace keywords = boost::log::keywords;
- //[ example_extension_stat_collector_settings_definition
- // The backend collects statistical information about network activity of the application
- class stat_collector :
- public sinks::basic_sink_backend<
- sinks::combine_requirements<
- sinks::synchronized_feeding,
- sinks::flushing
- >::type
- >
- {
- private:
- // The file to write the collected information to
- std::ofstream m_csv_file;
- // Here goes the data collected so far:
- // Active connections
- unsigned int m_active_connections;
- // Sent bytes
- unsigned int m_sent_bytes;
- // Received bytes
- unsigned int m_received_bytes;
- // The number of collected records since the last write to the file
- unsigned int m_collected_count;
- // The time when the collected data has been written to the file last time
- boost::posix_time::ptime m_last_store_time;
- // The collected data writing interval
- boost::posix_time::time_duration m_write_interval;
- public:
- // The constructor initializes the internal data
- stat_collector(const char* file_name, boost::posix_time::time_duration write_interval);
- // The function consumes the log records that come from the frontend
- void consume(logging::record_view const& rec);
- // The function flushes the file
- void flush();
- private:
- // The function resets statistical accumulators to initial values
- void reset_accumulators();
- // The function writes the collected data to the file
- void write_data();
- };
- //]
- // The constructor initializes the internal data
- stat_collector::stat_collector(const char* file_name, boost::posix_time::time_duration write_interval) :
- m_csv_file(file_name, std::ios::app),
- m_active_connections(0),
- m_last_store_time(boost::posix_time::microsec_clock::universal_time()),
- m_write_interval(write_interval)
- {
- reset_accumulators();
- if (!m_csv_file.is_open())
- throw std::runtime_error("could not open the CSV file");
- }
- BOOST_LOG_ATTRIBUTE_KEYWORD(sent, "Sent", unsigned int)
- BOOST_LOG_ATTRIBUTE_KEYWORD(received, "Received", unsigned int)
- // The function consumes the log records that come from the frontend
- void stat_collector::consume(logging::record_view const& rec)
- {
- // Accumulate statistical readings
- if (rec.attribute_values().count("Connected"))
- ++m_active_connections;
- else if (rec.attribute_values().count("Disconnected"))
- --m_active_connections;
- else
- {
- namespace phoenix = boost::phoenix;
- logging::visit(sent, rec, phoenix::ref(m_sent_bytes) += phoenix::placeholders::_1);
- logging::visit(received, rec, phoenix::ref(m_received_bytes) += phoenix::placeholders::_1);
- }
- ++m_collected_count;
- // Check if it's time to write the accumulated data to the file
- boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
- if (now - m_last_store_time >= m_write_interval)
- {
- write_data();
- m_last_store_time = now;
- }
- }
- // The function writes the collected data to the file
- void stat_collector::write_data()
- {
- m_csv_file << m_active_connections
- << ',' << m_sent_bytes
- << ',' << m_received_bytes
- << std::endl;
- reset_accumulators();
- }
- // The function resets statistical accumulators to initial values
- void stat_collector::reset_accumulators()
- {
- m_sent_bytes = m_received_bytes = 0;
- m_collected_count = 0;
- }
- // The function flushes the file
- void stat_collector::flush()
- {
- // Store any data that may have been collected since the list write to the file
- if (m_collected_count > 0)
- {
- write_data();
- m_last_store_time = boost::posix_time::microsec_clock::universal_time();
- }
- m_csv_file.flush();
- }
- //[ example_extension_stat_collector_factory
- // Factory for the stat_collector sink
- class stat_collector_factory :
- public logging::sink_factory< char >
- {
- public:
- // Creates the sink with the provided parameters
- boost::shared_ptr< sinks::sink > create_sink(settings_section const& settings)
- {
- // Read sink parameters
- std::string file_name;
- if (boost::optional< std::string > param = settings["FileName"])
- file_name = param.get();
- else
- throw std::runtime_error("No target file name specified in settings");
- boost::posix_time::time_duration write_interval = boost::posix_time::minutes(1);
- if (boost::optional< std::string > param = settings["WriteInterval"])
- {
- unsigned int sec = boost::lexical_cast< unsigned int >(param.get());
- write_interval = boost::posix_time::seconds(sec);
- }
- // Create the sink
- boost::shared_ptr< stat_collector > backend = boost::make_shared< stat_collector >(file_name.c_str(), write_interval);
- boost::shared_ptr< sinks::synchronous_sink< stat_collector > > sink = boost::make_shared< sinks::synchronous_sink< stat_collector > >(backend);
- if (boost::optional< std::string > param = settings["Filter"])
- {
- sink->set_filter(logging::parse_filter(param.get()));
- }
- return sink;
- }
- };
- void init_factories()
- {
- logging::register_sink_factory("StatCollector", boost::make_shared< stat_collector_factory >());
- }
- //]
- const char settings[] =
- "[Sinks.MyStat]\n"
- "Destination=StatCollector\n"
- "FileName=stat.csv\n"
- "WriteInterval=30\n"
- ;
- void init_logging()
- {
- init_factories();
- std::istringstream strm(settings);
- logging::init_from_stream(strm);
- }
- int main(int, char*[])
- {
- init_logging();
- src::logger lg;
- BOOST_LOG(lg) << logging::add_value("Connected", true);
- BOOST_LOG(lg) << logging::add_value("Sent", 100u);
- BOOST_LOG(lg) << logging::add_value("Received", 200u);
- logging::core::get()->flush();
- return 0;
- }
|