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
|
/*
* 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 <cstddef>
#include <string>
#include <map>
#include <iostream>
#include <fstream>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes/scoped_attribute.hpp>
#include <boost/log/sources/logger.hpp>
#include <boost/log/sources/record_ostream.hpp>
#include <boost/log/utility/value_ref.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_expressions_has_attr_stat_accumulator
// Declare attribute keywords
BOOST_LOG_ATTRIBUTE_KEYWORD(stat_stream, "StatisticStream", std::string)
BOOST_LOG_ATTRIBUTE_KEYWORD(change, "Change", int)
// A simple sink backend to accumulate statistic information
class my_stat_accumulator :
public sinks::basic_sink_backend< sinks::synchronized_feeding >
{
// A map of accumulated statistic values,
// ordered by the statistic information stream name
typedef std::map< std::string, int > stat_info_map;
stat_info_map m_stat_info;
public:
// Destructor
~my_stat_accumulator()
{
// Display the accumulated data
stat_info_map::const_iterator it = m_stat_info.begin(), end = m_stat_info.end();
for (; it != end; ++it)
{
std::cout << "Statistic stream: " << it->first
<< ", accumulated value: " << it->second << "\n";
}
std::cout.flush();
}
// The method is called for every log record being put into the sink backend
void consume(logging::record_view const& rec)
{
// First, acquire statistic information stream name
logging::value_ref< std::string, tag::stat_stream > name = rec[stat_stream];
if (name)
{
// Next, get the statistic value change
logging::value_ref< int, tag::change > change_amount = rec[change];
if (change_amount)
{
// Accumulate the statistic data
m_stat_info[name.get()] += change_amount.get();
}
}
}
};
// The function registers two sinks - one for statistic information,
// and another one for other records
void init()
{
boost::shared_ptr< logging::core > core = logging::core::get();
// Create a backend and attach a stream to it
boost::shared_ptr< sinks::text_ostream_backend > backend =
boost::make_shared< sinks::text_ostream_backend >();
backend->add_stream(
boost::shared_ptr< std::ostream >(new std::ofstream("test.log")));
// Create a frontend and setup filtering
typedef sinks::synchronous_sink< sinks::text_ostream_backend > log_sink_type;
boost::shared_ptr< log_sink_type > log_sink(new log_sink_type(backend));
// All records that don't have a "StatisticStream" attribute attached
// will go to the "test.log" file
log_sink->set_filter(!expr::has_attr(stat_stream));
core->add_sink(log_sink);
// Create another sink that will receive all statistic data
typedef sinks::synchronous_sink< my_stat_accumulator > stat_sink_type;
boost::shared_ptr< stat_sink_type > stat_sink(new stat_sink_type());
// All records with a "StatisticStream" string attribute attached
// will go to the my_stat_accumulator sink
stat_sink->set_filter(expr::has_attr(stat_stream));
core->add_sink(stat_sink);
}
// This simple macro will simplify putting statistic data into a logger
#define PUT_STAT(lg, stat_stream_name, change)\
if (true) {\
BOOST_LOG_SCOPED_LOGGER_TAG(lg, "StatisticStream", stat_stream_name);\
BOOST_LOG(lg) << logging::add_value("Change", (int)(change));\
} else ((void)0)
void logging_function()
{
src::logger lg;
// Put a regular log record, it will go to the "test.log" file
BOOST_LOG(lg) << "A regular log record";
// Put some statistic data
PUT_STAT(lg, "StreamOne", 10);
PUT_STAT(lg, "StreamTwo", 20);
PUT_STAT(lg, "StreamOne", -5);
}
//]
int main(int, char*[])
{
init();
logging_function();
return 0;
}
|