1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
|
/*
* 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 <iostream>
#include <stdexcept>
#include <boost/smart_ptr/shared_ptr.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/sync_frontend.hpp>
#include <boost/log/sinks/basic_sink_backend.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>
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_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, /*< we will have to store internal data, so let's require frontend to synchronize feeding calls to the backend >*/
sinks::flushing /*< also enable flushing support >*/
>::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;
public:
// The constructor initializes the internal data
explicit stat_collector(const char* file_name);
// 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) :
m_csv_file(file_name, std::ios::app),
m_active_connections(0),
m_last_store_time(boost::posix_time::microsec_clock::universal_time())
{
reset_accumulators();
if (!m_csv_file.is_open())
throw std::runtime_error("could not open the CSV file");
}
//[ example_extension_stat_collector_consume
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 >= boost::posix_time::minutes(1))
{
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;
}
//]
//[ example_extension_stat_collector_flush
// 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();
}
//]
// Complete sink type
typedef sinks::synchronous_sink< stat_collector > sink_t;
void init_logging()
{
boost::shared_ptr< logging::core > core = logging::core::get();
boost::shared_ptr< stat_collector > backend(new stat_collector("stat.csv"));
boost::shared_ptr< sink_t > sink(new sink_t(backend));
core->add_sink(sink);
}
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;
}
|