[ create a new paste ] login | about

Link: http://codepad.org/8ACp0obH    [ raw code | fork | 1 comment ]

C++, pasted on Mar 11:
// 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;
}


Create a new paste based on this one


Comments:
posted by seanc on Mar 11
For a reason I didn't investigate further, the operator<<() call on line 176 isn't invoking the correct overload on line 83.

Also worth noting the cleanup of TSS streams results in a crash if a user inputs 0.

This was intended to be a rough illustration of how I would envision an improved logging framework.
reply