Inheriting from std::ostream to override formatting.

A

AJG

Hi there. I am using a library called SOCI that has a method to set a
stream which it uses to log SQL queries. The signature is as follows:

void setLogStream(std::eek:stream *s);

This works great when used with something like
setLogStream(&std::cerr). However, I would like to add more context to
the query logged. Specifically, I'd like to add the thread ID. So,
instead of the query logged looking like:

select * from foo;

it would look like:

<thread-id>| select * from foo;

I already have the function to get the thread id
(boost::this_thread::get_id()), but I need to find a way to pass an
object to setLogStream that will do the formatting for me. As far as I
can tell, the only way to do this is inheriting from std::eek:stream and
somehow overriding the default formatting. Except I'm not sure which
of its methods are virtual and meant to be overridden. Any clues?

Basically, I figure what I need might look something like:

struct ThreadLogger : public std::eek:stream {
// ...
virtual void someOverridenFunction(const char *const buffer) {
std::cerr << boost::this_thread::get_id() << "| " << buffer;
}
// ...
};

and then:

ThreadLogger logger;
setLogStream(&logger);

Is what I'm looking to do possible? Should I look into IO manipulators
instead? Any help greatly appreciated :).

Thanks!
 
J

James Kanze

Hi there. I am using a library called SOCI that has a method
to set a stream which it uses to log SQL queries. The
signature is as follows:
void setLogStream(std::eek:stream *s);
This works great when used with something like
setLogStream(&std::cerr). However, I would like to add more
context to the query logged. Specifically, I'd like to add the
thread ID. So, instead of the query logged looking like:
select * from foo;
it would look like:
<thread-id>| select * from foo;
I already have the function to get the thread id
(boost::this_thread::get_id()), but I need to find a way to
pass an object to setLogStream that will do the formatting for
me.

You also need a way of ensuring correct locking on the output
stream object.
As far as I can tell, the only way to do this is inheriting
from std::eek:stream and somehow overriding the default
formatting. Except I'm not sure which of its methods are
virtual and meant to be overridden.

None of the functions (except the destructor) are virtual and
are meant to be overridden. That's not how ostream works.
Any clues?

You could use a filtering streambuf to insert the thread id at
the start of each line, but that still leaves the issue of
locking. The usual solution is to combine a filtering streambuf
(to "decorate" the output, i.e. adding timestamp, thread id,
line and filename...) and an output stream wrapper (to manage
the lock, and more generally the notion of a "record", and to
ensure that each record ends with a new line, is immediately
flushed, and is atomic, e.g. when the output stream sends emails
or writes to syslog).

For more information on filtering streambufs, see
http://kanze.james.neuf.fr/articles-en.html; an implementation
is also available there, or you can use boost::iostream (if e.g.
you're already using Boost). I'm not aware of any good article
on output stream wrappers, but the concept is simple enough that
it might not be necessary. Again, an implementation is
available at my site, but if you don't feel like installing the
entire library (and I've made no effort to date to make it
fractionable), it's small enough and simple enough that you
should be able to just copy the relevant code and manage it as
your own.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top