// Compiled with:
// g++-mp-4.4 -g -pedantic -Wall -Wextra -Iusr/local/boost/include/ foo.cc /usr/local/boost/lib/libboost_thread-mt.a && ./a.out
#include <deque>
#include <iostream>
#include <string>
#include <boost/strong_typedef.hpp>
#include <boost/thread/tss.hpp>
// Begin pseudo-code
namespace boost {
namespace log {
namespace record {
struct base_type {
// Stub, currently empty
};
namespace attribute {
template< typename CharT >
struct message {
typedef std::basic_string< CharT > string_type;
string_type message;
};
template< typename SevT >
struct severity {
SevT severity_;
};
} // namespace attribute
} // namespace record
} // namespace log
} // namespace boost
typedef enum {
info = 0,
warn = 1,
crit = 2
} severity_t;
// User's struct
template< typename CharT = char >
struct my_log_record
: boost::log::record::base_type,
boost::log::record::attribute::message<CharT>,
boost::log::record::attribute::severity<severity_t>
{
typedef CharT char_type;
typedef my_log_record< char_type > this_type;
typedef std::basic_ostream< char_type > ostream_type;
my_log_record(ostream_type& os) : port(42), strm(os) {}
ostream_type& set_port(const int p) { port = p; return strm; }
int port;
ostream_type& strm;
};
// template<typename LogRecordT>
// typename LogRecordT::ostream_type& operator<<(typename LogRecordT::ostream_type& out, LogRecordT& /* rec */) {
// return out;
// }
typedef my_log_record<char> my_log_record_t;
//my_log_record_t::ostream_type& operator<<(my_log_record_t::ostream_type&, my_log_record_t::this_type&);
// namespace std {
// my_log_record_t::ostream_type& operator<<(my_log_record_t::ostream_type& out, my_log_record_t::this_type& /* rec */) {
// std::cout << "here" << std::endl;
// return out;
// }
// }
my_log_record_t::ostream_type&
operator<<(my_log_record_t::ostream_type& out, my_log_record_t::this_type& /* rec */) {
std::cout << "here" << std::endl;
return out;
}
// Pseudo-sink hidden away by the implementation
namespace boost {
namespace log {
namespace sink {
template< typename LogRecordT, typename CharT = char >
struct base_sink {
typedef CharT char_type;
typedef LogRecordT log_record_type;
typedef base_sink< log_record_type, char_type > this_type;
typedef typename log_record_type::ostream_type ostream_type;
typedef std::deque< log_record_type* > log_record_queue_type;
public:
base_sink(ostream_type& strm) : strm_(strm) {
this_type::tss_self_.reset(this);
}
// friend ostream_type& operator<<(ostream_type& out, log_record_type& log_record);
static LogRecordT& record() {
return *(log_record_.get());
}
// Save the last record in a TLS variable
static void set_record(log_record_type& rec) {
this_type::log_record_.reset(&rec);
}
static ostream_type& stream_init() {
log_record_type* rec = new log_record_type(stream());
// Use mutex or atomic op in future
set_record(*rec);
return stream();
}
static ostream_type& stream() {
return this_type::tss_self_.get()->strm_;
}
private:
ostream_type& strm_;
static boost::thread_specific_ptr< this_type > tss_self_;
static boost::thread_specific_ptr< log_record_type > log_record_;
};
// this should get moved to a different namespace, being hastey with the implementation
typedef struct base_sink< my_log_record_t, char > sink_t;
template<> boost::thread_specific_ptr< sink_t > sink_t::tss_self_(NULL); // Prevent recursive dtor bug
template<> boost::thread_specific_ptr< sink_t::log_record_type > sink_t::log_record_(NULL);
} // namespace sink
} // namespace log
} // namespace boost
// End of implementation
// sink setup
template < typename BaseSinkT, typename CharT = char >
struct my_sink : BaseSinkT {
my_sink(typename BaseSinkT::ostream_type& strm) : BaseSinkT(strm) {}
// Or however the developer wants to decide if a log record should be created
inline bool accept(const int& sev) const {
return sev == 0 ? false : true;
}
};
typedef boost::log::sink::base_sink< my_log_record_t > base_sink_t;
typedef struct my_sink< base_sink_t > my_sink_t;
// end logging setup
// Leave it up to the backend to do the actual formatting
#define LOG(_sev) if (lg.accept(_sev)) my_sink_t::stream_init()
int
main() {
my_sink_t lg(std::cerr);
int severity = 0;
// Guarantee that there is no compile time optimizations for the value of i
std::cout << "Enter a severity level: ";
std::cin >> severity;
// An actual sink would append a newline
LOG(severity) << "My log message\n";
std::cerr << my_sink_t::record().port << std::endl;
{
// The following
LOG(severity) << my_sink_t::record().set_port(80);// << "My log message2\n";
std::cerr << my_sink_t::record().port << std::endl;
}
return 0;
}