libs/log/example/doc/extension_filter_parser_custom_rel.cpp
/*
* 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 <sstream>
#include <iostream>
#include <stdexcept>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared_object.hpp>
#include <boost/phoenix.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes/attribute_name.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/formatting_ostream.hpp>
#include <boost/log/utility/manipulators/add_value.hpp>
#include <boost/log/utility/setup/filter_parser.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/console.hpp>
namespace logging = boost::log;
namespace attrs = boost::log::attributes;
namespace src = boost::log::sources;
namespace expr = boost::log::expressions;
namespace sinks = boost::log::sinks;
namespace keywords = boost::log::keywords;
struct point
{
float m_x, m_y;
point() : m_x(0.0f), m_y(0.0f) {}
point(float x, float y) : m_x(x), m_y(y) {}
};
bool operator== (point const& left, point const& right);
bool operator!= (point const& left, point const& right);
template< typename CharT, typename TraitsT >
std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, point const& p);
template< typename CharT, typename TraitsT >
std::basic_istream< CharT, TraitsT >& operator>> (std::basic_istream< CharT, TraitsT >& strm, point& p);
const float epsilon = 0.0001f;
bool operator== (point const& left, point const& right)
{
return (left.m_x - epsilon <= right.m_x && left.m_x + epsilon >= right.m_x) &&
(left.m_y - epsilon <= right.m_y && left.m_y + epsilon >= right.m_y);
}
bool operator!= (point const& left, point const& right)
{
return !(left == right);
}
template< typename CharT, typename TraitsT >
std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, point const& p)
{
if (strm.good())
strm << "(" << p.m_x << ", " << p.m_y << ")";
return strm;
}
template< typename CharT, typename TraitsT >
std::basic_istream< CharT, TraitsT >& operator>> (std::basic_istream< CharT, TraitsT >& strm, point& p)
{
if (strm.good())
{
CharT left_brace = static_cast< CharT >(0), comma = static_cast< CharT >(0), right_brace = static_cast< CharT >(0);
strm.setf(std::ios_base::skipws);
strm >> left_brace >> p.m_x >> comma >> p.m_y >> right_brace;
if (left_brace != '(' || comma != ',' || right_brace != ')')
strm.setstate(std::ios_base::failbit);
}
return strm;
}
//[ example_extension_filter_parser_rectangle_definition
struct rectangle
{
point m_top_left, m_bottom_right;
};
template< typename CharT, typename TraitsT >
std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, rectangle const& r);
template< typename CharT, typename TraitsT >
std::basic_istream< CharT, TraitsT >& operator>> (std::basic_istream< CharT, TraitsT >& strm, rectangle& r);
//]
template< typename CharT, typename TraitsT >
std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, rectangle const& r)
{
if (strm.good())
strm << "{" << r.m_top_left << " - " << r.m_bottom_right << "}";
return strm;
}
template< typename CharT, typename TraitsT >
std::basic_istream< CharT, TraitsT >& operator>> (std::basic_istream< CharT, TraitsT >& strm, rectangle& r)
{
if (strm.good())
{
CharT left_brace = static_cast< CharT >(0), dash = static_cast< CharT >(0), right_brace = static_cast< CharT >(0);
strm.setf(std::ios_base::skipws);
strm >> left_brace >> r.m_top_left >> dash >> r.m_bottom_right >> right_brace;
if (left_brace != '{' || dash != '-' || right_brace != '}')
strm.setstate(std::ios_base::failbit);
}
return strm;
}
//[ example_extension_custom_filter_factory_with_custom_rel
// The function checks if the point is inside the rectangle
bool is_in_rectangle(logging::value_ref< point > const& p, rectangle const& r)
{
if (p)
{
return p->m_x >= r.m_top_left.m_x && p->m_x <= r.m_bottom_right.m_x &&
p->m_y >= r.m_top_left.m_y && p->m_y <= r.m_bottom_right.m_y;
}
return false;
}
// Custom point filter factory
class point_filter_factory :
public logging::filter_factory< char >
{
public:
logging::filter on_exists_test(logging::attribute_name const& name)
{
return expr::has_attr< point >(name);
}
logging::filter on_equality_relation(logging::attribute_name const& name, string_type const& arg)
{
return expr::attr< point >(name) == parse_argument< point >(arg);
}
logging::filter on_inequality_relation(logging::attribute_name const& name, string_type const& arg)
{
return expr::attr< point >(name) != parse_argument< point >(arg);
}
logging::filter on_custom_relation(logging::attribute_name const& name, string_type const& rel, string_type const& arg)
{
if (rel == "is_in_rectangle")
{
return boost::phoenix::bind(&is_in_rectangle, expr::attr< point >(name), parse_argument< rectangle >(arg));
}
throw std::runtime_error("Unsupported filter relation: " + rel);
}
private:
template< typename ArgumentT >
static ArgumentT parse_argument(string_type const& arg)
{
std::istringstream strm(arg);
ArgumentT val;
strm >> val;
if (strm.fail() || strm.bad())
throw std::runtime_error("Failed to parse argument from \"" + arg + "\"");
return val;
}
};
void init_factories()
{
//<-
logging::register_simple_formatter_factory< point, char >("Coordinates");
//->
logging::register_filter_factory("Coordinates", boost::make_shared< point_filter_factory >());
}
//]
void init_logging()
{
init_factories();
logging::add_console_log
(
std::clog,
keywords::filter = "%Coordinates% is_in_rectangle \"{(0, 0) - (20, 20)}\"",
keywords::format = "%TimeStamp% %Coordinates% %Message%"
);
logging::add_common_attributes();
}
int main(int, char*[])
{
init_logging();
src::logger lg;
// We have to use scoped attributes in order coordinates to be passed to filters
{
BOOST_LOG_SCOPED_LOGGER_TAG(lg, "Coordinates", point(10, 10));
BOOST_LOG(lg) << "Hello, world with coordinates (10, 10)!";
}
{
BOOST_LOG_SCOPED_LOGGER_TAG(lg, "Coordinates", point(50, 50));
BOOST_LOG(lg) << "Hello, world with coordinates (50, 50)!"; // this message will be suppressed by filter
}
return 0;
}