extension_stat_collector_settings.cpp 7.0 KB

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