Original Post
I've written a logging system based on Boost.Iostreams (I wanted to add date/time information and other stuff to log messages automatically, so I wrote a sink class which I use with boost::iostreams::stream_buffer) but there's a problem with multiple threads trying to access the stream at once. My sink class looks like this: I've then just got a global ostream, which I use like so:
class log_sink
{
private:
std::string filename_;
std::ofstream outs_;
public:
typedef char char_type;
typedef io::sink_tag category;
log_sink(std::string const &filename);
log_sink(log_sink const ©);
std::streamsize write(const char* s, std::streamsize n);
};
log_sink::log_sink(std::string const &filename)
: filename_(filename)
{
outs_.open(filename_.c_str());
}
log_sink::log_sink(log_sink const ©)
: filename_(copy._filename)
{
outs_.open(filename_.c_str());
}
std::streamsize log_sink::write(const char *s, std::streamsize n)
{
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::lock_guard<boost::mutex> lock(mutex);
outs_ << now << " : ";
outs_.write(s, n);
outs_.flush();
return n;
}
boost::iostreams::stream_buffer<log_sink> debug_buffer;
std::ostream debug(&debug_buffer);
// ...
debug << "some stuff to write to the file" << std::endl; Now, notice I use a boost::lock_guard<> in an attempt to prevent multiple threads from writing to the file at once. However, I think the problem is that the s pointer that is passed to the write function is pointing to a buffer that's shared between threads, so the lock doesn't really do much. I've had this problem for a while, and I never really bothered to look into it too much. But then I saw the recent Simple STL Logging article and I thought it might have had a solution. Unfortunately, the author basically got around the multi-threading problem by wrapping the whole "log << stuff" thing in a mutex, like this: boost::mutex::scoped_lock lock(CLogger::log_mutex);
debug << "some stuff to write to the file" << std::endl;
lock.unlock();
Which I thought was a bit intrusive. I was thinking one way to do it would be to put my global stream object into thread-local storage and then sort out the multi-threading stuff inside my write function, pretty much like it already does. Is there a better way? This is really stretching my knowledge of Boost/SC++L :-)