/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }