extension_stat_collector.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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 <iostream>
  10. #include <stdexcept>
  11. #include <boost/smart_ptr/shared_ptr.hpp>
  12. #include <boost/date_time/posix_time/posix_time_types.hpp>
  13. #include <boost/phoenix.hpp>
  14. #include <boost/log/core.hpp>
  15. #include <boost/log/expressions.hpp>
  16. #include <boost/log/sinks/sync_frontend.hpp>
  17. #include <boost/log/sinks/basic_sink_backend.hpp>
  18. #include <boost/log/sources/logger.hpp>
  19. #include <boost/log/sources/record_ostream.hpp>
  20. #include <boost/log/attributes/value_visitation.hpp>
  21. #include <boost/log/utility/manipulators/add_value.hpp>
  22. namespace logging = boost::log;
  23. namespace src = boost::log::sources;
  24. namespace expr = boost::log::expressions;
  25. namespace sinks = boost::log::sinks;
  26. namespace keywords = boost::log::keywords;
  27. //[ example_extension_stat_collector_definition
  28. // The backend collects statistical information about network activity of the application
  29. class stat_collector :
  30. public sinks::basic_sink_backend<
  31. sinks::combine_requirements<
  32. sinks::synchronized_feeding, /*< we will have to store internal data, so let's require frontend to synchronize feeding calls to the backend >*/
  33. sinks::flushing /*< also enable flushing support >*/
  34. >::type
  35. >
  36. {
  37. private:
  38. // The file to write the collected information to
  39. std::ofstream m_csv_file;
  40. // Here goes the data collected so far:
  41. // Active connections
  42. unsigned int m_active_connections;
  43. // Sent bytes
  44. unsigned int m_sent_bytes;
  45. // Received bytes
  46. unsigned int m_received_bytes;
  47. // The number of collected records since the last write to the file
  48. unsigned int m_collected_count;
  49. // The time when the collected data has been written to the file last time
  50. boost::posix_time::ptime m_last_store_time;
  51. public:
  52. // The constructor initializes the internal data
  53. explicit stat_collector(const char* file_name);
  54. // The function consumes the log records that come from the frontend
  55. void consume(logging::record_view const& rec);
  56. // The function flushes the file
  57. void flush();
  58. private:
  59. // The function resets statistical accumulators to initial values
  60. void reset_accumulators();
  61. // The function writes the collected data to the file
  62. void write_data();
  63. };
  64. //]
  65. // The constructor initializes the internal data
  66. stat_collector::stat_collector(const char* file_name) :
  67. m_csv_file(file_name, std::ios::app),
  68. m_active_connections(0),
  69. m_last_store_time(boost::posix_time::microsec_clock::universal_time())
  70. {
  71. reset_accumulators();
  72. if (!m_csv_file.is_open())
  73. throw std::runtime_error("could not open the CSV file");
  74. }
  75. //[ example_extension_stat_collector_consume
  76. BOOST_LOG_ATTRIBUTE_KEYWORD(sent, "Sent", unsigned int)
  77. BOOST_LOG_ATTRIBUTE_KEYWORD(received, "Received", unsigned int)
  78. // The function consumes the log records that come from the frontend
  79. void stat_collector::consume(logging::record_view const& rec)
  80. {
  81. // Accumulate statistical readings
  82. if (rec.attribute_values().count("Connected"))
  83. ++m_active_connections;
  84. else if (rec.attribute_values().count("Disconnected"))
  85. --m_active_connections;
  86. else
  87. {
  88. namespace phoenix = boost::phoenix;
  89. logging::visit(sent, rec, phoenix::ref(m_sent_bytes) += phoenix::placeholders::_1);
  90. logging::visit(received, rec, phoenix::ref(m_received_bytes) += phoenix::placeholders::_1);
  91. }
  92. ++m_collected_count;
  93. // Check if it's time to write the accumulated data to the file
  94. boost::posix_time::ptime now = boost::posix_time::microsec_clock::universal_time();
  95. if (now - m_last_store_time >= boost::posix_time::minutes(1))
  96. {
  97. write_data();
  98. m_last_store_time = now;
  99. }
  100. }
  101. // The function writes the collected data to the file
  102. void stat_collector::write_data()
  103. {
  104. m_csv_file << m_active_connections
  105. << ',' << m_sent_bytes
  106. << ',' << m_received_bytes
  107. << std::endl;
  108. reset_accumulators();
  109. }
  110. // The function resets statistical accumulators to initial values
  111. void stat_collector::reset_accumulators()
  112. {
  113. m_sent_bytes = m_received_bytes = 0;
  114. m_collected_count = 0;
  115. }
  116. //]
  117. //[ example_extension_stat_collector_flush
  118. // The function flushes the file
  119. void stat_collector::flush()
  120. {
  121. // Store any data that may have been collected since the list write to the file
  122. if (m_collected_count > 0)
  123. {
  124. write_data();
  125. m_last_store_time = boost::posix_time::microsec_clock::universal_time();
  126. }
  127. m_csv_file.flush();
  128. }
  129. //]
  130. // Complete sink type
  131. typedef sinks::synchronous_sink< stat_collector > sink_t;
  132. void init_logging()
  133. {
  134. boost::shared_ptr< logging::core > core = logging::core::get();
  135. boost::shared_ptr< stat_collector > backend(new stat_collector("stat.csv"));
  136. boost::shared_ptr< sink_t > sink(new sink_t(backend));
  137. core->add_sink(sink);
  138. }
  139. int main(int, char*[])
  140. {
  141. init_logging();
  142. src::logger lg;
  143. BOOST_LOG(lg) << logging::add_value("Connected", true);
  144. BOOST_LOG(lg) << logging::add_value("Sent", 100u);
  145. BOOST_LOG(lg) << logging::add_value("Received", 200u);
  146. logging::core::get()->flush();
  147. return 0;
  148. }