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 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
|
/*
* 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/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 long sec = std::stoul(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;
}
|